Getting Hands Dirty with AWS CloudFormation

Provision your AWS infrastructure via JSON/YAML template

Introduction

In this article, we are going to discuss the AWS CloudFormation service and how to provision the AWS services using the CloudFormation template. Firstly, I will discuss what the AWS CloudFormation is and then we try to understand the basis of the CloudFormation. Then I will be discussing what we are going to build in this article using the CloudFormation template and finally, I will be discussing each code segment in the CloudFormation template which is responsible for provisioning each AWS service along with our sample CloudFormation template.

What is AWS CloudFormation?

AWS CloudFormation is an AWS service which allows us to describe and provision almost all of the AWS services using the JSON or YAML template. It is defined as an “Infrastructure as a code”. That allows us to spend less time on managing infrastructure and more time spending on our application logic. We are able to define each AWS service and their relationship with each other using a JSON or YAML code and the CloudFormation will take care of provisioning all the defined services in the template. By using CloudFormation in such a way, it allows us to provision, alter and delete our infrastructure within a very shorter period. For the disaster recovery, this tool will help you a lot.

Some of the main features and the key advantages are,

  • It allows us to version control our infrastructure.
  • Very easy to understand and use.
  • It is Flexible and Declarative.
  • It allows us to pass the parameters to it.
  • It has a visual editor and drag and drops feature.
  • It supports all most all of the AWS services.

Understanding the AWS CloudFormation basis

In AWS CloudFormation we will work with the CloudFormation template and using the template we are creating a stack.

The template is written either by using JSON or YAML and it describes what AWS services are been provisioned into the stack. There are 6 main sections will feature in the template and only the resources section is mandatory.

  1. AWSTemplateFormatVersion: This is the template version. As of now, we do have only “2010–09–09” as a version.
  2. Description: This section will describe the CloudFormation template. We can use String to do that.
  3. Mappings: This section contains collections of key-value pairs. We can define constant values in here and later we can refer those values. 
    For an example, we can define our company public IPs.
  4. Parameters: This section contains collections of key-value pairs and it allows us to pass parameter values to the template. 
    For an example, we can pass the instant type.
  5. Resources: This section describes our AWS resources. This section is a mandatory section.
  6. Outputs: In this section, we can define the values which need to take as an output. 
    For an example elastic IP or a load balancer DNS.

What we are going to provision using the AWS CloudFormation template

In this article, I will be describing how to provision the AWS network infrastructure with consist of VPC, public and private subnet, and route tables, load balancer, and the EC2 instance using the sample CloudFormation template. Below diagram depicts the AWS services which will be created using our sample template.

A list of resources which we are going to create using our template and their resource types are listed in the below table as well.

1. Target AWS Infrastructure Diagram with Our Template.
2. Used AWS CloudFormation Resource Types in Our Templates.

We can identify the CloudFormation template steps as below,

  1. Defining a VPC.
  2. Defining public subnets.
  3. Defining an internet gateway.
  4. Defining public route table and routes, associate those with public subnets.
  5. Defining Bastian security group and the instance.
  6. Defining private subnets.
  7. Defining Elastic IP and NAT gateway.
  8. Defining private route table and routes, associate those with private subnets.
  9. Defining the application server security group and the application server instances.
  10. Defining the load balancer security group.
  11. Defining the load balancer, listeners and listener rules.
  12. Defining the target groups.

As for our infrastructure diagram, after we create the stack using our template, we would be able to browse the application server apache index page just by entering the ALB’s DNS in the browser. And also ALB should route the traffic to both application servers randomly.

Understanding our CloudFormation template in detail

As I explained earlier, our CloudFormation template will consist of six main sections. Template version and the description are the first two section and we can define those section as below.

Section 1

"AWSTemplateFormatVersion":"2010-09-09"

Section 2

"Description":"This AWS CloudFormation stack will create the sample infrastructure which discussed in the article: .  **WARNING** This template creates an Amazon EC2 instance and many more services. You will be billed for the AWS resources used if you create a stack from this template."

Section 3

The 3rd section is for the Mappings section. I will be defining two constant values in this section and those are for the AMI id and for the environment tag.

* Please note that this CloudFormation template will run in the Asia Pacific (Singapore) region. AMI ids are different from region to region. You may need to update AMI id with respective one to your region.

Section 4

The 4th section is for the Parameters section. I will be defining six parameter values in this section as below.

  1. BastianHostInstanceType: Instance type of the Bastian host.
  2. ApplicationServerInstanceType: Instance type of the application servers.
  3. AvailabilityZone1: The first availability zone. This will be a drop down box filled with the Availability Zones in the current region.
  4. AvailabilityZone2: The second availability zone. This will be a drop down box filled with the Availability Zones in the current region.
  5. Environment: Environment.
  6. PEMFileName: Private key file name of the instances. (I will be using the same pem file for all 3 instances.)

Section 5

Section 5, the Resources section, is the most important section and the only section which is a mandatory section in the template.

As I have listed in the above 12 CloudFormation template steps, now is time to understand the AWS servicers in the Resources section.

1: Defining a VPC.
Resource type: AWS::EC2::VPC
VPC CIRD range is hardcoded in here. Also, we may parameterize the CIRD rage by using the Parameters section.

2: Defining public subnets.
Resource type: AWS::EC2::Subnet
As per our infrastructure diagram, we do have two public subnets with two separate CIRD ranges. These two subnets will be provisioned into two separate availability zones.

3: Defining an internet gateway.
Resource types: AWS::EC2::InternetGateway, AWS::EC2::VPCGatewayAttachment
In here we are defining an internet gateway and attaching it to the VPC.

4: Defining the public route table and routes, associate those with public subnets.
Resource types: AWS::EC2::RouteTable, AWS::EC2::Route, AWS::EC2::SubnetRouteTableAssociation
In here we are defining a route table and route by assigning an above-created internet gateway. Then the subnet will be associated with this route table.

5: Defining Bastian security group and the instance.
Resource types: AWS::EC2::SecurityGroup, AWS::EC2::Instance
In here we are defining Bastian host security group and the Bastian host. Bastian host will be provisioned into the public subnet1 with 20GB gp2 volume. And also we use parameterized instance type value and AMI id constant value in here. We should create a private key and then the key name should be provided as a parameterized value.

6: Defining private subnets.
Resource type: AWS::EC2::Subnet

7: Defining Elastic IP and NAT gateway.
Resource types: AWS::EC2::EIP, AWS::EC2::NatGateway
In here we are defining an EPI and NAT gateway.

8: Defining private route table and routes, associate those with private subnets.
Resource types: AWS::EC2::RouteTable, AWS::EC2::Route, AWS::EC2::SubnetRouteTableAssociation
In here we are defining a route table and route by assigning an above-created NAT gateway. Then subnet will be associated with this route table.

9: Defining the application server security group and the application server instances.
Resource types: AWS::EC2::SecurityGroup, AWS::EC2::Instance
In here we are defining two application servers in each private subnet. In addition to the above-mentioned configuration in the Bastian host, to this app server instances, we are passing user data and metadata which will be executed when the instance is initializing. Apache server will be installed into these two servers and index.html file will be updated with the given content with the instance initialization.

10: Defining the load balancer security group.
Resource types: AWS::EC2::SecurityGroup

11: Defining the load balancer, listeners and listener rules.
Resource types: AWS::ElasticLoadBalancingV2::LoadBalancer, AWS::ElasticLoadBalancingV2::Listener, AWS::ElasticLoadBalancingV2::ListenerRule
In here we are defining the internet facing ALB, listener who is listening to the port 80 and the listener rule which is responsible for forwarding request coming to the port 80 to the app server target group.

12: Defining the target groups.
Resource types: AWS::ElasticLoadBalancingV2::TargetGroup
In here we are defining the application server target group and will be adding our two app servers as targets.

Section 6

Section 6 is the Outputs section in the template. In our template, we are getting the output of the Bastian host public IP, app servers private IPs, and the ALB’s DNS name.

Creating the stack using our template

Finally, now is the time for us to create the stack using our template in the AWS CloudFormation dashboard.

1. Navigate to the CloudFormation dashboard and click on the “Design Template” button.

2. In the CloudFormation designer, Click on the “Template” tab(1 in the below screenshot). Now you can copy and paste our template in the text area.
Complete template: https://github.com/sabeywardhana/cloud-formation-blog/blob/master/cloud-formation.json

3. Click the refresh button(2 in the below screenshot) so that you would be able to view the generated infrastructure diagram by CloudFormation.

4. Now you can validate(3 in the below screenshot) the template and then create(4 in the below screenshot) the stack.

3. CloudFormation Designer Window.

5. In the “Select Template” page click on the next button.

6. In the 2nd page, you will be asked to enter perimeter values. Fill those appropriately and then hit the next.

4. Parameters Page.

7. Hit next and next in next two pages. Now our stack should be in the “CREATE_IN_PROGRESS” status. After a few minutes, the status will change to the “CREATE_COMPLETE” status.
Now we can inspect the “Outputs” tab to view the output values such as ALB’s DNS name.

5. Outputs tab.
6. Events List.

8. After a few minutes, you should be able to view our application server index.html file content by just copy and pasting the ALB’s DNS name in a browser. And also ALB should route the traffic to both app server instances, so the browser should display the “Hello Sajith, this is AppServer 1” and “Hello Sajith, this is AppServer 2” pages randomly.

7. Browser Output.