Infrastructure as Code: AWS CloudFormation
Hilda Ogamba
Posted on January 24, 2022
Introduction
Infrastructure as code (IaC) is the process of provisioning and managing your cloud computing services by coming up with a template file. This lets you reliably and efficiently replicate environment architecture on-demand. AWS CloudFormation is the built-in IaC service. To provision these resources on AWS, you can describe them in a text file with either a .json
, .yaml
, .template
, or .txt
extension.
Prerequisites
You will need an active AWS account. Please note that it is advised to follow security guidelines when creating an AWS account to prevent unauthorized access. To follow along from the terminal/command line, you can follow these steps to install AWS CLI and quickly configure the basic settings on your computer.
Benefits of AWS CloudFormation
- An infrastructure as code template acts as a clear record of resources that you have provisioned.
- If you accidentally change the the wrong settings while deploying resources, it may break things. IaC helps solve this, especially when it is combined with version control, such as Git.
- IaC is also reusable meaning that one comprehensive template can be utilized multiple times, in multiple regions, making it much easier to horizontally scale.
- By creating IaC that follows proper security guidelines you can reuse it with the assurance that the resource settings are secure.
- CloudFormation can verify that the architecture was successfully deployed, and if there is a failure it can gracefully roll-back the infrastructure to a previously stable state.
AWS CloudFormation concepts
There are three main concepts in CloudFormation:
a) Template: This is the text file that describes your architecture. The template is then used to deploy these resources either through the CLI or the console.
Here is an example of a YAML template. This describes a VPC, one public subnet, an EC2 instance (running a web server) and other dependent resources:
AWSTemplateFormatVersion: 2010-09-09
Description: Template example
# VPC with public subnet and Internet Gateway
Parameters:
ExampleVpcCidr:
Type: String
Default: 10.0.0.0/20
PublicSubnetCidr:
Type: String
Default: 10.0.0.0/24
AmazonLinuxAMIID:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
Resources:
###########
# VPC with Internet Gateway
###########
ExampleVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref ExampleVpcCidr
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: Example VPC
IGW:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: Example IGW
VPCtoIGWConnection:
Type: AWS::EC2::VPCGatewayAttachment
DependsOn:
- IGW
- ExampleVPC
Properties:
InternetGatewayId: !Ref IGW
VpcId: !Ref ExampleVPC
###########
# Public Route Table
###########
PublicRouteTable:
Type: AWS::EC2::RouteTable
DependsOn: ExampleVPC
Properties:
VpcId: !Ref ExampleVPC
Tags:
- Key: Name
Value: Public Route Table
PublicRoute:
Type: AWS::EC2::Route
DependsOn:
- PublicRouteTable
- IGW
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref IGW
RouteTableId: !Ref PublicRouteTable
###########
# Public Subnet
###########
PublicSubnet:
Type: AWS::EC2::Subnet
DependsOn: ExampleVPC
Properties:
VpcId: !Ref ExampleVPC
MapPublicIpOnLaunch: true
CidrBlock: !Ref PublicSubnetCidr
AvailabilityZone: !Select
- 0
- !GetAZs
Ref: AWS::Region
Tags:
- Key: Name
Value: Public Subnet
PublicRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
DependsOn:
- PublicRouteTable
- PublicSubnet
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet
###########
# App Security Group
###########
AppSecurityGroup:
Type: AWS::EC2::SecurityGroup
DependsOn: ExampleVPC
Properties:
GroupName: App
GroupDescription: Enable access to App
VpcId: !Ref ExampleVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: App
###########
# EC2 Instance
###########
Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: t2.micro
ImageId: !Ref AmazonLinuxAMIID
SubnetId: !Ref PublicSubnet
SecurityGroupIds:
- !Ref AppSecurityGroup
Tags:
- Key: Name
Value: App Server
UserData:
Fn::Base64: |
#!/bin/bash
yum update -y
yum install -y httpd.x86_64
systemctl start httpd.service
systemctl enable httpd.service
echo “Hello from $(hostname -f)” > /var/www/html/index.html
###########
# Outputs
###########
Outputs:
PublicDnsName:
Description: EC2 Instance Public DNS Name
Value: !GetAtt Instance.PublicDnsName
This particular template is divided into 5 sections:
- AWSTemplateFormatVersion: This is a string that describes the AWS CloudFormation template version that the template conforms to. It is denoted as a "version date" format.
- Description: It is a string that gives a short summary of the content of the template.
- Parameters: It contains the values that are passed at runtime.
- Resources: This is the most important (and compulsory) section on a template. It basically describes all the resources to be deployed and their properties.
- Outputs: These are values that are returned once a stack is created or updated. The outputs can be viewed from the AWS console. Or by running this command from your terminal/command line:
aws cloudformation describe-stacks --stack-name mystack --query "Stacks[0].Outputs" --output text
In this example, the output returns the public DNS name of the EC2 instance. You can copy this DNS name to your browser and it should direct you to a simple web page.
b) Stack: Once you upload this template, these resources are deployed as a single unit referred to as a stack. You can make changes to resources in a stack and in-case of any failures, these changes can be rolled-back. You can also delete a stack and therefore all the resources in a stack. When creating a new stack, make sure give each stack a unique name. You can watch a video tutorial on how to deploy a template from the AWS console. Or you can upload it through the AWS CLI:
aws cloudformation create-stack --stack-name mystack --template-url http://examplebucketname.s3.amazonaws.com/exampletemplate.yaml
You can delete the stack by running this from AWS CLI:
aws cloudformation delete-stack --stack-name mystack
c) Change Set: When updating a resource, you can simply upload an updated template and let CloudFormation make the necessary changes. This can be risky especially if the changes may delete or modify critical resources. A safer alternative is to use change sets. Change sets allow you to preview the proposed modifications to your current architecture before implementing them. We'll make a modification to our template switching the EC2 instance type from t2.micro
to t2.small
:
###########
# EC2 Instance
###########
Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: t2.small
.
.
.
You can watch a video tutorial on how to deploy a change set from the AWS console. Or you can upload the change stack through the CLI:
aws cloudformation create-change-set --stack-name mystack --change-set-name changeset-update --template-url http://examplebucketname.s3.amazonaws.com/updatedexampletemplate.yaml
To view the changes to be implemented in a change set, run this from the terminal:
aws cloudformation describe-change-set --stack-name mystack --change-set-name changeset-update
To execute a change set, run this command in the AWS CLI:
aws cloudformation execute-change-set --stack-name mystack --change-set-name changeset-update
Conclusion
Hope this helps you get started!
PS: Don't forget to delete your stack once you are through to avoid extra charges.
Posted on January 24, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.