Deploy a Web Application on Amazon EC2

GETTING STARTED GUIDE

Module 1: Create Your Infrastructure

In this module, you will create an AWS CDK stack, a security group with inbound access, and an IAM instance profile.

Introduction

Before we deploy the web application, we need to create an Amazon EC2 instance and supporting resources. In this module, we'll create the new AWS CDK app, install the dependencies for our resources, and finally define an Amazon EC2 instance, a security group with inbound access, and an IAM instance profile. We will also, with the help of CDK, create the key pair used to access the instance.

What You Will Learn

  • Create a new AWS CDK app
  • Install dependencies for the needed resources
  • Define the resources in the CDK app

 Time to Complete

10 minutes

 Module Prereqs

  • AWS Account with administrator-level access**
  • Recommended browser: The latest version of Chrome or Firefox

[**]Accounts created within the past 24 hours might not yet have access to the services required for this tutorial.

Implementation

Create the CDK app

First, ensure you have CDK installed. if you do not have it installed, please follow the Getting Started with AWS CDK guide:

cdk --verison

We will now create the skeleton CDK application using TypeScript as our language of choice:

mkdir ec2-cdk
cd ec2-cdk
cdk init app --language typescript

This will output the following:

Applying project template app for typescript
# Welcome to your CDK TypeScript project!

This is a blank project for TypeScript development with CDK.

The `cdk.json` file tells the CDK Toolkit how to execute your app.

## Useful commands

 * `npm run build`   compile typescript to js
 * `npm run watch`   watch for changes and compile
 * `npm run test`    perform the jest unit tests
 * `cdk deploy`      deploy this stack to your default AWS account/region
 * `cdk diff`        compare deployed stack with current state
 * `cdk synth`       emits the synthesized CloudFormation template

Executing npm install...
✅ All done!

If you see the following message, we recommend you upgrade your CDK version using the supplied command, and then running npm update:

****************************************************
*** Newer version of CDK is available [1.122.0]  ***
*** Upgrade recommended (npm install -g aws-cdk) ***
****************************************************

# npm install -g aws-cdk
# npm update

Create the code for the resource stack

Go to the file /lib/cdk-ecs-infra-stack.ts, this is where you will write the code for the resource stack you are going to create.

A resource stack is a set of cloud infrastructure resources (in your particular case they will be all AWS resources), that will be provisioned into a specific account. The account/region where these resources are provisioned, can be configured in the stack.

In this resource stack, you are going to create the following resources:

  • IAM role: this role will be assigned to the EC2 instance to allow it to call other AWS services.
  • EC2 instance: the virtual machine you will use to host your web application.
  • Security Group: the virtual firewall to allow inbound requests to your web application.
  • EC2 SSH keypair: a set of credentials you can use to SSH to the instance to execute commands to set everything up.

Create the EC2 instance

To start creating the EC2 instance, and other resources, you first need to import the correct modules:

npm i @aws-cdk/aws-ec2 @aws-cdk/aws-iam @aws-cdk/aws-s3-assets cdk-ec2-key-pair

You will then edit the lib/cdk-eb-infra-stack.ts file to add the dependency at the top of the file below the existing import for @aws-cdk/core:

import * as ec2 from "@aws-cdk/aws-ec2";            // Allows working with EC2 and VPC resources
import * as iam from "@aws-cdk/aws-iam";            // Allows working with IAM resources
import * as s3assets from "@aws-cdk/aws-s3-assets"; // Allows managing files with S3
import * as keypair from "cdk-ec2-key-pair";        // Helper to create EC2 SSH keypairs
import * as path from "path";                       // Helper for working with file paths

These modules provide access to all the components you need for you to deploy the web application. The first step is to find the existing default VPC in your account by adding the following code below the line // The code that defines your stack goes here:

// The code that defines your stack goes here
      
      // Look up the default VPC
      const vpc = ec2.Vpc.fromLookup(this, "VPC", {
        isDefault: true
      });

Using the cdk-ec2-key-pair package, you will create an SSH key pair and store that in AWS Secrets Manager.

 // Create a key pair to be used with this EC2 Instance
    const key = new keypair.KeyPair(this, "KeyPair", {
      name: "cdk-keypair",
      description: "Key Pair created with CDK Deployment",
    });
    key.grantReadOnPublicKey; 

You now need to create a security group, allowing SSH and HTTP access from anywhere by adding 2 rules. Note that SSH access from anywhere is acceptable for a short time in a test environment, but it's unsafe for production environments. You will also create an IAM role for the EC2 instance to allow it to call other AWS services, and attached the pre-built policy to read configurations out of AWS Secrets Manager (where the SSH public key will be stored):

// Security group for the EC2 instance
    const securityGroup = new ec2.SecurityGroup(this, "SecurityGroup", {
      vpc,
      description: "Allow SSH (TCP port 22) and HTTP (TCP port 80) in",
      allowAllOutbound: true,
    });

    // Allow SSH access on port tcp/22
    securityGroup.addIngressRule(
      ec2.Peer.anyIpv4(),
      ec2.Port.tcp(22),
      "Allow SSH Access"
    );

    // Allow HTTP access on port tcp/80
    securityGroup.addIngressRule(
      ec2.Peer.anyIpv4(),
      ec2.Port.tcp(80),
      "Allow HTTP Access"
    );

    // IAM role to allow access to other AWS services
    const role = new iam.Role(this, "ec2Role", {
      assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"),
    });

    // IAM policy attachment to allow access to 
    role.addManagedPolicy(
      iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMManagedInstanceCore")
    );

You are now ready to create the EC2 instance using a pre-built Amazon Machine Image (AMI) - for this guide, you will be using the Amazon Linux 2 one for X86_64 CPU architecture. You will also pass the IAM role you created, the default VPC, and the instance type to run on, in your case, a t2.micro that has 1 vCPU and 1GB of memory - you view all the different instance types available here.

// Look up the AMI Id for the Amazon Linux 2 Image with CPU Type X86_64
    const ami = new ec2.AmazonLinuxImage({
      generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
      cpuType: ec2.AmazonLinuxCpuType.X86_64,
    });
// Create the EC2 instance using the Security Group, AMI, and KeyPair defined.
    const ec2Instance = new ec2.Instance(this, "Instance", {
      vpc,
      instanceType: ec2.InstanceType.of(
        ec2.InstanceClass.T2,
        ec2.InstanceSize.MICRO
      ),
      machineImage: ami,
      securityGroup: securityGroup,
      keyName: key.keyPairName,
      role: role,
    });

You have now defined your AWS CDK stack to create an Amazon EC2 instance, a security group with inbound access, and an IAM instance profile. Before deploying the stack, you still need to install the packages on the host OS to run your application, and also copy your application code to the instance. 

Your ec2-cdk-stack.ts file should now look like this:

import * as cdk from '@aws-cdk/core';
import * as ec2 from "@aws-cdk/aws-ec2"; // Allows working with EC2 and VPC resources
import * as iam from "@aws-cdk/aws-iam"; // Allows working with IAM resources
import * as s3assets from "@aws-cdk/aws-s3-assets"; // Allows managing files with S3
import * as keypair from "cdk-ec2-key-pair"; // Helper to create EC2 SSH keypairs
import * as path from "path"; // Helper for working with file paths

export class Ec2CdkStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here
          
    // Look up the default VPC
    const vpc = ec2.Vpc.fromLookup(this, "VPC", {
      isDefault: true
    });

    // Create a key pair to be used with this EC2 Instance
    const key = new keypair.KeyPair(this, "KeyPair", {
      name: "cdk-keypair",
      description: "Key Pair created with CDK Deployment",
    });
    key.grantReadOnPublicKey; 

    // Security group for the EC2 instance
    const securityGroup = new ec2.SecurityGroup(this, "SecurityGroup", {
      vpc,
      description: "Allow SSH (TCP port 22) and HTTP (TCP port 80) in",
      allowAllOutbound: true,
    });

    // Allow SSH access on port tcp/22
    securityGroup.addIngressRule(
      ec2.Peer.anyIpv4(),
      ec2.Port.tcp(22),
      "Allow SSH Access"
    );

    // Allow HTTP access on port tcp/80
    securityGroup.addIngressRule(
      ec2.Peer.anyIpv4(),
      ec2.Port.tcp(80),
      "Allow HTTP Access"
    );

    // IAM role to allow access to other AWS services
    const role = new iam.Role(this, "ec2Role", {
      assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"),
    });

    // IAM policy attachment to allow access to 
    role.addManagedPolicy(
      iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMManagedInstanceCore")
    );

    // Look up the AMI Id for the Amazon Linux 2 Image with CPU Type X86_64
    const ami = new ec2.AmazonLinuxImage({
      generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
      cpuType: ec2.AmazonLinuxCpuType.X86_64,
    });

    // Create the EC2 instance using the Security Group, AMI, and KeyPair defined.
    const ec2Instance = new ec2.Instance(this, "Instance", {
      vpc,
      instanceType: ec2.InstanceType.of(
        ec2.InstanceClass.T2,
        ec2.InstanceSize.MICRO
      ),
      machineImage: ami,
      securityGroup: securityGroup,
      keyName: key.keyPairName,
      role: role,
    });
  }
}

Conclusion

In this module, you learned how to create a CDK application to create all the infrastructure needed to deploy your web application on an EC2 instance. In the next module, you will learn how to configure the EC2 instance when it boots by installing all the OS packages, configuring them, and deploying your code onto the instance.

Up Next: Auto Configuration

Let us know how we did.

Thank you for your feedback
We're glad this page helped you. Would you like to share additional details to help us continue to improve?
Close
Thank you for your feedback
We're sorry this page didn't help you. Would you like to share additional details to help us continue to improve?
Close