Anatomy of AWS CloudFormation templates

Anatomy of AWS CloudFormation templates

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

Did you find this article valuable?

Support Keshav Bist by becoming a sponsor. Any amount is appreciated!