CloudFormation Template for VPC with EC2 and ALB

2021.08.06

Introduction

This CloudFormation Template creates a VPC with a private and a public subnet in each AZ. Each public subnet contains a EC2 Instance, which is connected  to Application Load Balancer.  VPC has an Internet Gateway and route tables for public and private  subnets. The below image shows the architectural  design of the template.

 

 

CloudFormation Template

The template code is written in YAML, where all the required  resources  are defined in Resources section and dynamic inputs in Parameters section.

 

---
Parameters:
  SecurityGroupDescription:
    Description: Security Group Description
    Type: String
  KeyName:
    Description: Key Pair for EC2
    Type: 'AWS::EC2::KeyPair::KeyName'

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
      - Key: Name
        Value: VPC1

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
      - Key: Name
        Value: VPC Internet Gateway

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: us-east-2a
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: Public Subnet 1

  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.2.0/24
      MapPublicIpOnLaunch: false
      AvailabilityZone: us-east-2a
      Tags:
        - Key: Name
          Value: Private Subnet 1

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.3.0/24
      AvailabilityZone: us-east-2b
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: Public Subnet 2

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.4.0/24
      AvailabilityZone: us-east-2b
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: Private Subnet 2

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: Public Route Table

  PublicRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicSubnetRouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

  PublicSubnetRouteTableAssociation2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicRouteTable

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: Private Route Table

  PrivateSubnetRouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref PrivateRouteTable

  PrivateSubnetRouteTableAssociation2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateRouteTable

  #EC2 Instances
  EC2Instance1:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0233c2d874b811deb 
      InstanceType: t2.micro
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      SubnetId: !Ref PublicSubnet1
      KeyName: !Ref KeyName
      UserData: 
        Fn::Base64: !Sub |
          #!/bin/bash
          yum update -y
          yum install -y httpd
          systemctl start httpd
          systemctl enable httpd
          #echo "<h1>Hello from Region us-east-2b</h1>" > /var/www/html/index.html

    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0233c2d874b811deb
      InstanceType: t2.micro
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      SubnetId: !Ref PublicSubnet2
      KeyName: !Ref KeyName
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          yum update -y
          yum install -y httpd
          systemctl start httpd
          systemctl enable httpd
          #echo "<h1>Hello from Region us-east-2b</h1>" > /var/www/html/index.html

  # EC2 and ALB Security Groups
  ELBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: ELB Security Group
      VpcId: !Ref VPC
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 80
        ToPort: 80
        CidrIp: 0.0.0.0/0

  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: !Ref SecurityGroupDescription
      VpcId: !Ref VPC
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 80
        ToPort: 80
        SourceSecurityGroupId:
          Fn::GetAtt:
          - ELBSecurityGroup
          - GroupId
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: xxx.xxx.xxx.xxx

  # Target Group, Listener and Application  Load Balancer
  EC2TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 30
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 15
      HealthyThresholdCount: 5
      Matcher:
        HttpCode: '200'
      Name: EC2TargetGroup
      Port: 80
      Protocol: HTTP
      TargetGroupAttributes:
      - Key: deregistration_delay.timeout_seconds
        Value: '20'
      Targets:
      - Id: !Ref EC2Instance1
        Port: 80
      - Id: !Ref EC2Instance2
        Port: 80
      UnhealthyThresholdCount: 3
      VpcId: !Ref VPC

  ALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref EC2TargetGroup
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: 80
      Protocol: HTTP

  ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      Subnets:
      - !Ref PublicSubnet1
      - !Ref PublicSubnet2
      SecurityGroups:
        - !GetAtt ELBSecurityGroup.GroupId

 

Description of Resources Created

VPC

  • VPC
    • VPC is defined with CidrBlock 10.0.0.0/16.
    • DnsHostnames is set to 'true' to get public DNS hostname.

 

  • Subnets : a private and a public subnet is defined in each Availability Zone.
    • Public Subnet 1 - in Availability Zone 1 with CidrBlock 10.0.1.0/24.
    • Public Subnet 2 - in Availability Zone 2 with CidrBlock 10.0.3.0/24.
    • Private Subnet 1 - in Availability Zone 1 with CidrBlock 10.0.2.0/24.
    • Private Subnet 2 - in Availability Zone 2 with CidrBlock 10.0.4.0/24.

 

  • Internet Gateway  
    • It provides a target for internet-routable traffic in your route tables.
    • Route tables refer Internet Gateway as target for Destination.

 

  • Route Tables 
    • Public Route Table : routes traffic either to Internet Gateway for outbounds or within 10.0.0.0/16. Public subnets in two Availability  Zones are associated  with the public route table.

 

    • Private Route Table : routes traffic only within 10.0.0.0/16. Private subnets are associated  with private route table.

EC2

  • EC2 Instances
    • Two EC2 Instances are defined in public subnet with user data to install Apache web server.
    • The Instances have a reference to  EC2 Security  group and KeyPair.

 

  • Security Groups: 
    • EC2 Security Group : Port 22 for SSH and Port 80 open to the Load Balancer.

 

    • ELB Security Group :  Port 80 open to everyone.

 

  • Application  Load Balancer : Load balancer is defined with Listener, target group and references ELB security group.
    • Listener : The Listener is set with port 80 and protocol HTTP. The Listener forwards the traffic  to targets in target group.

 

    • Target Group : One target group is defined with two EC2 Instances as targets. Health Check port is set to 80.

 

Deploying CloudFormation Template

  • Click on 'Create stack' in CloudFormation console. Choose 'Template is ready' and Specify the Template either through S3 URL or by directly  uploading file. Click next to proceed further.

 

 

  • Enter a name for stack to association with the resources created. Choose a keypair and enter a description  for Security  Group in the Parameters Section. Continue choosing next and click on 'Create Stack' .

 

 

  • Creating Stack may take several minutes  to launch all the resources  with their dependencies. Deleting  a Stack deletes all the resources associated with the stack.

 

Template Design

This is the template design automatically generated by CloudFormation based on the YAML file. This Design shows the defined resources and their dependencies.

 

 

Summary

We have successfully  created VPC with EC2 Instances and Application Load Balancer using CloudFormation Template. CloudFormation is an easy way to create required resources  and manage them in an orderly  and easy manner. CloudFormation is a great way to represent architecture as code in your repository, which can be reused and controlled.