Creating an EC2 instance

Introduction

In this post I shall demonstrate how easy it is to create an EC2 instance, and a security group within an existing AWS VPC.

Python examples follow.

Initialize project

mkdir ec2-instance-demo
cd ec2-instance-demo
cdk init --language python

Activate virtual env

source .env/bin/activate

Install dependencies

pip install -r requirements.txt

List stacks

cdk ls
ec2-instance

Stack file

ec2_instance_stack.py (located inside the ec2_instance directory)

  • Import the required packages aws_ec2

  • Define an existing VPC using id vpcID

  • Define a new security group sec_group

  • Define the name to assign to the EC2 instance instanceName

  • Define the type of instance to use instanceType

  • Define the name of the AMI to assign to the instance amiName

from aws_cdk import (
    
    core,
    aws_ec2 as ec2,

)

vpcID="<VPC-ID>"
instanceName="webserver-1"
instanceType="t2.micro"
amiName="amzn2-ami-hvm-2.0.20200520.1-x86_64-gp2"


class Ec2InstanceStack(core.Stack):

    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # The code that defines your stack goes here

        # lookup existing VPC
        vpc = ec2.Vpc.from_lookup(
            self,
            "vpc",
            vpc_id=vpcID,
        )
        
        # create a new security group
        sec_group = ec2.SecurityGroup(
            self,
            "sec-group-allow-ssh",
            vpc=vpc,
            allow_all_outbound=True,
        )

        # add a new ingress rule to allow port 22 to internal hosts
        sec_group.add_ingress_rule(
            peer=ec2.Peer.ipv4('10.0.0.0/16'),
            description="Allow SSH connection", 
            connection=ec2.Port.tcp(22)
        )

        # define a new ec2 instance
        ec2_instance = ec2.Instance(
            self,
            "ec2-instance",
            instance_name=instanceName,
            instance_type=ec2.InstanceType(instanceType),
            machine_image=ec2.MachineImage().lookup(name=amiName),
            vpc=vpc,
            security_group=sec_group,
        )

CDK operations

Verify changes

Run a cdk diff to see what changes will be applied in AWS.

cdk diff
jsii.errors.JavaScriptError: 
  Error: Cannot retrieve value from context provider vpc-provider since account/region are not specified at the stack level. Either configure "env" with explicit account and region when you define your stack, or use the environment variables "CDK_DEFAULT_ACCOUNT" and "CDK_DEFAULT_REGION" to inherit environment information from the CLI (not recommended for production stacks)

Solving the error message

As the error message implies CDK is looking for the account and region information.

It could not find the information in the environment variables: CDK_DEFAULT_ACCOUNT and CDK_DEFAULT-REGION.

We could set these environment variables and that would be fine for development purposes; but CDK does highlight that this is not recommended for production stacks.

So, the alternative fix here is to set the information inside the app.py

The app.py file requires fine tuning to point to a specific AWS region and AWS account.

The boilerplate file does not contain this information, and this is required in order to create an EC2 instance using the CDK.

#!/usr/bin/env python3

from aws_cdk import core

from ec2_instance.ec2_instance_stack import Ec2InstanceStack


app = core.App()

env = core.Environment(region="<region>",account="<account-id>")

Ec2InstanceStack(app, "ec2-instance",env=env)
app.synth()

Here you define the env variable to point to a region and use account

The env is then passed into the stack Ec2InstanceStack

Notice that at the end of the file app.synth().

This synthesizes the code written using the AWS CDK framework into a cloud assembly, i.e. into a CloudFormation template.

By default the CloudFormation template lives in the project directory under cdk.out

Now, run cdk diff again.

cdk diff
Stack ec2-instance
IAM Statement Changes
┌───┬──────────────────────────────────┬────────┬────────────────┬───────────────────────────┬───────────┐
│   │ Resource                                │ Effect │ Action         │ Principal                 │ Condition │
├───┼──────────────────────────────────┼────────┼────────────────┼───────────────────────────┼───────────┤
│ + │ ${ec2-instance/InstanceRole.Arn} │ Allow  │ sts:AssumeRole │ Service:ec2.amazonaws.com │           │
└───┴──────────────────────────────────┴────────┴────────────────┴───────────────────────────┴───────────┘
Security Group Changes
┌───┬──────────────────────┬─────┬────────────┬─────────────────┐
│   │ Group                │ Dir │ Protocol   │ Peer            │
├───┼──────────────────────┼─────┼────────────┼─────────────────┤
│ + │ ${sec-group.GroupId} │ In  │ TCP 22     │ 10.0.0.0/16     │
│ + │ ${sec-group.GroupId} │ Out │ Everything │ Everyone (IPv4) │
└───┴──────────────────────┴─────┴────────────┴─────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Resources
[+] AWS::EC2::SecurityGroup sec-group secgroup81B6576A 
[+] AWS::IAM::Role ec2-instance/InstanceRole ec2instanceInstanceRoleCA97C688 
[+] AWS::IAM::InstanceProfile ec2-instance/InstanceProfile ec2instanceInstanceProfile9BCE9015 
[+] AWS::EC2::Instance ec2-instance ec2instance42082E81 

Changes:

  • New security group (x1)
  • New IAM roles (x2)
  • New EC2 instance (x1)

Synth

Run cdk synth to see the CloudFormation template generated from the code written in CDK.

Deploy

Now, run a cdk deploy.

Accept the changes when you are ready to deploy.

The provisioning of cloud infrastructure is carried out via CloudFormation.

cdk deploy
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:

IAM Statement Changes
┌───┬──────────────────────────────────┬────────┬────────────────┬───────────────────────────┬───────────┐
│   │ Resource                         │ Effect │ Action         │ Principal                 │ Condition │
├───┼──────────────────────────────────┼────────┼────────────────┼───────────────────────────┼───────────┤
│ + │ ${ec2-instance/InstanceRole.Arn} │ Allow  │ sts:AssumeRole │ Service:ec2.amazonaws.com │           │
└───┴──────────────────────────────────┴────────┴────────────────┴───────────────────────────┴───────────┘
Security Group Changes
┌───┬──────────────────────┬─────┬────────────┬─────────────────┐
│   │ Group                │ Dir │ Protocol   │ Peer            │
├───┼──────────────────────┼─────┼────────────┼─────────────────┤
│ + │ ${sec-group.GroupId} │ In  │ TCP 22     │ 10.0.0.0/16     │
│ + │ ${sec-group.GroupId} │ Out │ Everything │ Everyone (IPv4) │
└───┴──────────────────────┴─────┴────────────┴─────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Do you wish to deploy these changes (y/n)? y

Monitor the output to check the progress.

Once finished, head over to the AWS management console, too see the new infrastructure components deployed.

Destroy

You can remove the deployed components via cdk destroy

Are you sure you want to delete: ec2-instance (y/n)? y
ec2-instance: destroying...
...
 ✅  ec2-instance: destroyed
Last updated on 25 Jun 2020
Published on 25 Jun 2020