AWS CloudFormation – Designing Templates

In a serie of blog articles I’ll take a closer look at AWS CloudFormation. Read more about what AWS CloudFormation is in my previous blog article AWS CloudFormation – Templates, stacks and change sets. In this blog article I’ll take a closer look at Designing and writing templates.

Cloudformation Designer

You can write templates locally and upload it to CloudFormation or use the CloudFormation Designer. If you specify a template file stored locally, AWS CloudFormation uploads it to an S3 bucket in your AWS account. AWS CloudFormation creates a bucket for each region in which you upload a template file.

The CloudFormation Designer gives a graphical layout of the template. Basically it is just drag and drop of the resources. Configuring the individual resources is still done by editing the template. Let’s just focus on writing templates.

A template consists of several sections. Some of them are optional, like parameters and mapping. The resource section is the only mandatory part of a template.

Resource section

The resources in this section are declared with a logical name, type and a set of properties. We can call this an entity. To declare an entity you can use a fixed set of properties in your template. The Resource type reference describes them in detail, including what to expect when changing one of them (interruption or replacement). Each property has a certain type ( a string, Boolean etc.) resulting in a key/value notation. In addition, AWS provides some data types. Properties of this type are composed of their own set of properties. BlockDeviceMappings is an example of that.

When using multiple resources that are related to each other (ref), you don’t have to worry about ordering. CloudFormation will handle that for you when it executes the template.

Intrinsic functions

AWS CloudFormation provides several built-in functions that help you manage your stacks. Use intrinsic functions in your templates to assign values to properties that are not available until run time. Here is the complete list of the available AWS CloudFormation functions. Basically these functions provides you functionality to use logic in your template which eventually gives you more flexibility.

Pseudo parameters

Pseudo parameters in AWS are like environment variables. They are predefined and can be used in your template. For example, when you need to refer to the region where your resource is creating, there is a pseudo parameter AWS:Region.

AWSTemplateFormatVersion: "2010-09-09"
Description: A sample template
    Type: "AWS::EC2::Instance"
      ImageId: "ami-0ff8a91507f77f867"
      InstanceType: t2.micro
      AdditionalInfo: !Ref AWS::Region

A complete list of the available pseudo parameters can be found here. To give an idea how you can make use of pseudo parameters, here is one example of AWS::NoValue.

This pseudo parameter is used to remove the property of an resource. As seen below , an RDS instance is defined as a resource. In the properties of this resource the if condition states that if “UseDbSnapshot” is “True” , use the “DBSnapshotname” as “DBSnapshotIdentifier” property. Otherwise, set the “DBSnapshotIdentifier” property to “NoValue”.

"MyDB" : {
  "Type" : "AWS::RDS::DBInstance",
  "Properties" : {
    "DBSnapshotIdentifier" : {
      "Fn::If" : [
        {"Ref" : "DBSnapshotName"},
        {"Ref" : "AWS::NoValue"}

Mapping section

Mappings are useful to use input values to determine another value. First start with a mapping section in your template.

      "AMI": "ami-0b69ea66ff7391e80"
      "AMI": "ami-0245d318c6788de52"
      "AMI": "ami-0ce71448843cb18a1"

This mapping section describes for the specified regions the corresponding image id. The RegionMap consist of a key and the value pair. This example will deploy an Amazon Linux 2 instance.
Next we can use intrinsic functions and pseudo parameters to get the ImageId for the instance.

    Type: "AWS::EC2::Instance"
        - RegionMap
        - !Ref AWS::Region
        - AMI
      InstanceType: m1.small

Here we use the FindInMap function to find a specific value in a map based on the value of a pseudo parameter. FindInMap accepts three parameters. The first is the RegionMap, which is the logical name of the map. Next, we call the pseudo parameter AWS::Region. This is done by the Ref intrinsic function. The last parameter is ‘AMI’ which is the name of the value pair.

This is a good example of how to use one template across multiple regions in AWS.

In this example the input selection is handled by the CloudFormation via mappings. Sometimes you need to specify input parameters in your template because there is no logic for it. For example, when you want to select the instance type.

Parameters section

Parameters enable you to input custom values to your template each time you create or update a stack.

    Type: String
    Default: t2.micro
      - t2.micro
      - m1.small
      - m1.large
    Description: Enter t2.micro, m1.small, or m1.large. Default is t2.micro.

This results in a drop down menu in the CloudFormation console. To call the selected value in the template we can use the Ref intrinsic function again.

  Type: AWS::EC2::Instance
      Ref: InstanceTypeParameter

There are different types of input parameters. Above is a simple parameter of the type String with the allowed values. But there are also AWS specific parameter types, for example AWS::EC2::KeyPair::KeyName. This will call the specific resource in AWS to pull the correct values. In this case, the drop down menu presents the key pairs in your account within the region you are deploying a stack.

Another interesting parameter type is the SSM parameter. These types correspond to existing parameters in Systems Manager Parameter Store. You specify a Systems Manager parameter key as the value of the SSM parameter, and AWS CloudFormation fetches the latest value from Parameter Store to use for the stack. You can store data such as passwords, database strings, and license codes as parameter values. You can store values as plain text or encrypted data.

Outputs section

This section declares output values that you can import into other stacks, return in response or view in the console. For example, you can output a custom description to the output section in the CloudFormation console.

    Value: !GetAtt
    - Ec2Instance
    - PublicDnsName

Now you’ll find in the output section of the CloudFormation console a key value pair of OutputVariableName – dns name of the EC2 instance.

Writing templates can be challenging when you try to deploy multiple resources which are all related to each other. For example an instance with multiple security groups, a second interface and possibly a role may be attached to it. After deploying your stack from the command line, you’ll get feedback in the AWS console. When your deployment fails, the complete stack will be rolled back. The output in the CloudFormation console gives some usable feedback about the possible cause for this. Also you find a lot of information in the CloudFormation reference about resource and property types.

Next time I’ll get into more detail about customizing the OS of your instance during the deployment of a template and how this is all managed by CloudFormation helper scripts. Read this next blog about Bootstrapping an EC2 instance with userdata.

Vincent Lamers

Vincent Lamers, Linux-consultant @ AT Computing

Actieve filters: Wis alle filters