Background
AWS CloudFormation is an Infrastructure as a code (IaC) service that offers easy modeling, provisioning, and management of the AWS and third-party resources using templates written in YAML or JSON files. Writing CloudFormation templates for the first time could be tricky especially if you don't have previous experience with cloud services. In this article, I will be sharing my learning experience with AWS CloudFormation and hope it would help others to accelerate in creating the resources using CloudFormation.
When I joined CloudFactory (aka Sprout Technology Service in Nepal) as a Software Engineer in April 2021, I had no prior experience with any of the services provided by AWS. I had four years of experience writing production code, used one or two AWS services from the console, and wrote terraform code to provision infrastructure, except that I knew nothing about the AWS cloud ecosystem. But at CloudFactory we heavily use AWS cloud services to empower our apps, and CloudFormation is used to model, provision, and manage the infrastructures. Writing new or updating existing CloudFormation templates was already a part of my day-to-day job.
When I started my journey of learning the CloudFormation it was all confusing and I was kind of lost for a few days. Then, with my colleague's help, I figured I was doing it all wrong. I was trying to dissect and understand CloudFormation templates for heavy service. I should have started writing templates with very simple services like AWS SNS, SQS, and Lambda and then move to more complex infrastructures. What I found was provisioning AWS SQS was the simplest of all, and writing the first template on my own opened the door to an accelerated learning path.
Anatomy of CloudFormation Template
To understand the CloudFormation template we should understand the template components. Let's look at the template below for creating AWS SQS and try to understand each component. AWS CloudFormation templates have five components in general.
Components of AWS CloudFormation template
AWSTemplateFormatVersion
This is the first and compulsory component of the AWS CloudFormation template and it simply means template version and generally has a date in the format YYYY-MM-DD
as a value.
Description
It is an optional parameter and simply describes the infrastructure's purpose and usage. It can be later used for reference to figure out the purpose of the resource.
These two parameters are the first two lines of the AWS CloudFormation template.
AWSTemplateFormatVersion: '2010-09-09'
Description: A simple queue for the demo purpose
Parameters
These are the variables that can be passed from CLI while creating the stack. One can understand these as the command line params in the program. These are used to alter the stack names or behaviors. We can define one or more parameters for the given template.
Each parameter can have its data type defined by the Type
key and an optional default value defined by the Default
key. We can also define restrictions on allowed values for the parameter with the AllowedValues
key of the type list (array).
In the template below the parameter QueueNameParam
can be used to create a different queue. Similarly, the parameter QueueEnvParam
has the default value dev
. Its value can either be dev
, staging
, or prod
. A parameter logical name can be any alphanumeric combination.
Parameters:
QueueNameParam:
Type: String
Description: Queue name passed from CLI
QueueEnvParam:
Default: dev
Type: String
Description: The environment of the Infra
AllowedValues: ["prod", "staging", "dev"]
Resources
These are actual AWS infrastructure/resources that are created while invoking CloudFormation templates. The resource can have any logical name that is used to reference within a template, TestQueue
in the template snippet below. The Type
key in the Resource defines which infrastructure needs to be created. Again the resource can have multiple values listed under it.
Resources:
TestQueue:
Type: AWS::SQS::Queue
Properties:
VisibilityTimeout: 300
QueueName: !Ref QueueNameParam
Tags:
- Key: Name
Value: !Sub 'test-sqs-${QueueNameParam}'
Output
The output section exposes variables that are scoped to a single AWS account environment. These variables can be imported into another CloudFormation template. The Name
value under the Export
key should be used to import these values into another CloudFormation template.
In the example below, a key with the name dev:sqs:test-queue:QueueArn
is exported from the template. In another template, it can be imported using Fn::ImportValue: dev:sqs:test-queue:QueueArn
.
Outputs:
TestQueueArn:
Value: !GetAtt TestQueue.Arn
Description: Arn for test-queue
Export:
Name: !Join [ ':', [!Ref QueueEnvParam, 'sqs', !Ref QueueNameParam, QueueArn ] ]
CloudFormation Functions
An AWS CloudFormation function can be referenced with either Fn::
or as shorthand form !
. CloudFormation functions can be used for a variety of operations from referencing a resource to obtaining resource attributes. More on the intrinsic functions can be found here.
CloudFormation for AWS SQS
The complete template for provisioning the AWS SQS is given below.
AWSTemplateFormatVersion: '2010-09-09'
Description: A simple queue for the demo purpose
Parameters:
QueueNameParam:
Type: String
Description: Queue name passed from CLI
QueueEnvParam:
Default: dev
Type: String
Description: The environment of the Infra
AllowedValues: ["prod", "staging", "dev"]
Resources:
TestQueue:
Type: AWS::SQS::Queue
Properties:
VisibilityTimeout: 300
QueueName: !Ref QueueNameParam
Tags:
- Key: Name
Value: !Sub '${QueueEnvParam}-sqs-${QueueNameParam}'
Outputs:
TestQueueArn:
Value: !GetAtt TestQueue.Arn
Description: Arn for test-queue
Export:
Name: !Join [ ':', [!Ref QueueEnvParam, 'sqs', !Ref QueueNameParam, QueueArn ] ]
TestQueueURL:
Value: !Ref TestQueue
Description: URL for for test-queue
Export:
Name: !Join [ ':', [ !Ref QueueEnvParam, 'sqs', !Ref QueueNameParam, QueueURL ] ]
Creating Resource
The AWS resource can be created by invoking the following command:
aws cloudformation create-stack --stack-name <some-stack-name-here> --template-body file://sqs.yaml --profile <aws-profile> --region <region> --parameters ParameterName=QueueNameParam, ParameterValue=test-queue-name