Reusable Patterns in CloudFormation

At Rocket, we use a variety of tools to provision infrastructure in the cloud. In this post we take a look at some the reusable patterns we've developed using AWS CloudFormation.

What is CloudFormation?

If you've ever created infrastructure and/or resources in AWS then there's good chance you've used or at least heard of CloudFormation. For those who are unfamiliar, CloudFormation is an AWS service that allows you to provision and configure almost all AWS resources using yaml (or json) templates.

Here's an example template:

The template above creates a simple ECS (EC2 Container Service) resource with one ECS Fargate container task.

The template itself isn't revolutionary but there are few references within the template that make structuring reusable templates easy.

Pseudo Parameters and Intrinsic Functions

Pseudo parameters are basically aliases for common AWS specific configuration data. Utilizing pseudo parameters is critical for composing AWS account and regionally agnostic templates.

Intrinsic functions are helpers that resolve different bits of data within a template. This is useful for a number of things including importing values from other CloudFormation stacks or applying simple string substitutions.

Both pseudo parameters and intrinsic functions can be used together to dynamically resolve more complex configs. Here are some examples.

Render the AWS region using the Ref intrinsic function and the pseudo parameter AWS::Region:

- Name: "AWS_DEFAULT_REGION"
  Value: { Ref: "AWS::Region" }

Simple string substitution using the Fn::Sub intrinsic function and the pseudo parameter AWS::AccountId and AWS::Region:

Image: { "Fn::Sub": "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRRepo}:${ENV}" }

Import a value from the ECS Cluster CloudFormation Stack using the Fn::ImportValue intrinsic function:

Cluster: {"Fn::ImportValue" : {"Fn::Sub" : "${ECSStackName}-ClusterName"}}

Import and split a list of subnets from the VPC CloudFormation Stack using the Fn::ImportValue and Fn::Split intrinsic functions:

Subnets: { "Fn::Split": [ "," , {"Fn::ImportValue" : {"Fn::Sub" : "${VPCStackName}-PrivateSubnetList"}}]}

ResolvedValue Parameters

A more recent feature we've leveraged in CloudFormation templates is ResolvedValue parameters. This special parameter type allows for referencing parameter values in the the AWS Systems Manager (SSM) Parameter Store.

From the example template above:

ENV:
  Description: Name of the environment
  Type: AWS::SSM::Parameter::Value<String>
  Default: /cloudformation/parameters/env

This renders the value of the SSM Parameter located at the param store path /cloudformation/parameters/env.

By leveraging SSM parameter values in CloudFormation templates, you can easily separate environments across multiple AWS accounts and re-use the same CloudFormation template to provision infrastructure in each account without having to alter or override any template parameters!

Final thoughts

By putting each of these features to use, composing reusable account and regional agnostic CloudFormation templates becomes trivial.

This is extremely useful and efficient if you'd like to create isolated and identical environments (think development, QA, staging, production, etc) in separate AWS accounts.

If building cloud infrastructure and supporting tools interests you, please reach out! We're always looking for talented and impassioned software engineers to work with at Rocket.