AWS CloudFormation Template, Functions, and Commands

aws
Some useful notes on AWS CloudFormation template sections, intrinsic functions, and other tips.
Published

February 28, 2022

About

This post is a collection of useful notes on various sections of AWS CloudFormation template, and intrinsic functions. Knowledge about them is often tested in AWS certifications. For more details on this subject refer to its user guide (https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html)

Template Anatomy

The following is an example of AWS CloudFormation template and its sections in YAML format. There is no sequence to writing these sections besides that if there is a Description section then it must be put after AWSTemplateFormatVersion.

AWSTemplateFormatVersion: "version date"

Description:
  String

Metadata:
  template metadata

Parameters:
  set of parameters

Rules:
  set of rules

Mappings:
  set of mappings

Conditions:
  set of conditions

Transform:
  set of transforms

Resources:
  set of resources

Outputs:
  set of outputs

Template Sections

AWSTemplateFormatVersion (optional)

The AWS CloudFormation template version that the template conforms to. ### Syntax

AWSTemplateFormatVersion: "2010-09-09"

Description (optional)

A text string that describes the template. This section must always follow the template format version section. ### Syntax

Description: >
  Here are some
  details about
  the template.

Metadata (optional)

Objects that provide additional information about the template.

  • Difference between Metadata and Description is that some cloudformation features can refer to the objects that are defined in Metadata section. For example, you can use a metadata key AWS::CloudFormation::Interface to define how parameters are grouped and sorted on AWS cloudformation console. By default, cloudformation console alphbetically sorts the parameters by their logical ID.
  • AWS strongly recommends not to use this section for storing sensitive information such as passwords or secrets.

Syntax

Metadata:
  Instances:
    Description: "Information about the instances"
  Databases: 
    Description: "Information about the databases"

Parameters (optional)

Parameters enable you to input custom values to your template each time you create or update a stack. You can refer to parameters from the Resources and Outputs sections of the template using Ref intrinsic function.

CloudFormation currently supports the following parameter types

  • String – A literal string
  • Number – An integer or float
  • List<Number> – An array of integers or floats
  • CommaDelimitedList – An array of literal strings that are separated by commas
  • AWS::EC2::KeyPair::KeyName – An Amazon EC2 key pair name
  • AWS::EC2::SecurityGroup::Id – A security group ID
  • AWS::EC2::Subnet::Id – A subnet ID
  • AWS::EC2::VPC::Id – A VPC ID
  • List<AWS::EC2::VPC::Id> – An array of VPC IDs
  • List<AWS::EC2::SecurityGroup::Id> – An array of security group IDs
  • List<AWS::EC2::Subnet::Id> – An array of subnet IDs

Syntax

The following example declares a parameter named InstanceTypeParameter. This parameter lets you specify the Amazon EC2 instance type for the stack to use when you create or update the stack.

Note that InstanceTypeParameter has a default value of t2.micro. This is the value that AWS CloudFormation will use to provision the stack unless another value is provided.

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

Referencing a parameter in template (Ref function)

In the following example, the InstanceType property of the EC2 instance resource references the InstanceTypeParameter parameter value.

Ec2Instance:
  Type: AWS::EC2::Instance
  Properties:
    InstanceType:
      Ref: InstanceTypeParameter
    ImageId: ami-0ff8a91507f77f867

Rules (optional)

Validates a parameter or a combination of parameters that are passed to a template during a stack creation or stack update.

You can use the following rule-specific intrinsic functions to define rule conditions and assertions: * Fn::And * Fn::Contains * Fn::EachMemberEquals * Fn::EachMemberIn * Fn::Equals * Fn::If * Fn::Not * Fn::Or * Fn::RefAll * Fn::ValueOf * Fn::ValueOfAll

Syntax

In the following example, the rule checks the value of the InstanceType parameter. The user must specify a1.medium, if the value of the environment parameter is test.

Rules:
  testInstanceType:
    RuleCondition: !Equals 
      - !Ref Environment
      - test
    Assertions:
      - Assert:
          'Fn::Contains':
            - - a1.medium
            - !Ref InstanceType
        AssertDescription: 'For a test environment, the instance type must be a1.medium'

Mappings (optional)

The optional Mappings section matches a key to a corresponding set of named values similar to a lookup table. For example, if you want to set values based on a region, you can create a mapping that uses the region name as a key and contains the values you want to specify for each specific region. You use the Fn::FindInMap intrinsic function in the Resources and Outputs to retrieve values in a map. Note that you can’t include parameters, pseudo parameters, or intrinsic functions in the Mappings section.

Fn::FindInMap

The intrinsic function Fn::FindInMap returns the value corresponding to keys in a two-level map that’s declared in the Mappings section.

Syntax for the short form:

!FindInMap [ MapName, TopLevelKey, SecondLevelKey ] 

Parameters * MapName * The logical name of a mapping declared in the Mappings section that contains the keys and values. * TopLevelKey * The top-level key name. Its value is a list of key-value pairs. * SecondLevelKey * The second-level key name, which is set to one of the keys from the list assigned to TopLevelKey.

A more concrete example

Mappings: 
  RegionMap: 
    us-east-1: 
      HVM64: "ami-0ff8a91507f77f867"
      HVMG2: "ami-0a584ac55a7631c0c"
Resources: 
  myEC2Instance: 
    Type: "AWS::EC2::Instance"
    Properties: 
      ImageId: !FindInMap
        - RegionMap
        - !Ref 'AWS::Region' # us-east-1
        - HVM64
      InstanceType: m1.small

Conditions (optional)

Conditions that control whether certain resources are created or whether certain resource properties are assigned a value during stack creation or update. For example, you could conditionally create a resource that depends on whether the stack is for a production or test environment.

Conditions are defined in Conditions section, and are then applied in following sections. * Parameters * Resources * Outputs

You can use following intrinsic functions to define your conditions * Fn::And * Fn::Equals * Fn::If * Fn::Not * Fn::Or

Syntax

Conditions:
  Logical ID:
    Intrinsic function

A more concrete example

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  EnvType:
    Description: Environment type.
    Default: test
    Type: String
    AllowedValues:
      - prod
      - test
    ConstraintDescription: must specify prod or test.
Conditions:
  CreateProdResources: !Equals 
    - !Ref EnvType
    - prod
Resources:
  EC2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: ami-0ff8a91507f77f867
  MountPoint:
    Type: 'AWS::EC2::VolumeAttachment'
    Condition: CreateProdResources
    Properties:
      InstanceId: !Ref EC2Instance
      VolumeId: !Ref NewVolume
      Device: /dev/sdh
  NewVolume:
    Type: 'AWS::EC2::Volume'
    Condition: CreateProdResources
    Properties:
      Size: 100
      AvailabilityZone: !GetAtt 
        - EC2Instance
        - AvailabilityZone

Difference between Rules and Conditions usage?

  • Rules are used to evaluate the input given by the user in Parameters
  • Conditions turn come after all rules have been evaluated
  • Conditions are not limited to Parameters and can also work with Resources and Outputs

Transform (optional)

For serverless applications (also referred to as Lambda-based applications), specifies the version of the AWS Serverless Application Model (AWS SAM) to use. When you specify a transform, you can use AWS SAM syntax to declare resources in your template. The model defines the syntax that you can use and how it's processed.

You can also use AWS::Include transforms to work with template snippets that are stored separately from the main AWS CloudFormation template. You can store your snippet files in an Amazon S3 bucket and then reuse the functions across multiple templates.

Syntax

Transform:
  - MyMacro
  - 'AWS::Serverless'

AWS::Include transform

Use the AWS::Include transform, which is a macro hosted by AWS CloudFormation, to insert boilerplate content into your templates. The AWS::Include transform lets you create a reference to a template snippet in an Amazon S3 bucket. The AWS::Include function behaves similarly to an include, copy, or import directive in programming languages.

Example
Transform:
  Name: 'AWS::Include'
  Parameters:
    Location: 's3://MyAmazonS3BucketName/MyFileName.yaml'

Resources (required)

Specifies the stack resources and their properties, such as an Amazon Elastic Compute Cloud instance or an Amazon Simple Storage Service bucket. You can refer to resources in the Resources and Outputs sections of the template.

Syntax

Resources:
  Logical ID:
    Type: Resource type
    Properties:
      Set of properties

A more concrete example

Resources:
  MyEC2Instance:
    Type: "AWS::EC2::Instance"
    Properties:
      ImageId: "ami-0ff8a91507f77f867"

Outputs (optional)

The optional Outputs section declares output values that you can import into other stacks (to create cross-stack references), return in response (to describe stack calls), or view on the AWS CloudFormation console. For example, you can output the S3 bucket name from a stack to make the bucket easier to find.

Notes * You can declare a maximum of 200 outputs in a template. * AWS strongly recommend you don’t use this section to output sensitive information, such as passwords or secrets * Output values are available after the stack operation is complete. Stack output values aren’t available when a stack status is in any of the IN_PROGRESS status. * AWS also does not recommend establishing dependencies between a service runtime and the stack output value because output values might not be available at all times.

Syntax

Outputs:
  Logical ID:
    Description: Information about the value
    Value: Value to return
    Export:
      Name: Name of resource to export

A more concrete example where certain values are shown as output at the end of stack creation.

Outputs:
  BackupLoadBalancerDNSName:
    Description: The DNSName of the backup load balancer
    Value: !GetAtt BackupLoadBalancer.DNSName
    Condition: CreateProdResources
  InstanceID:
    Description: The Instance ID
    Value: !Ref EC2Instance

For Cross-Stack output use Export tag. Values outputed with “Export” tag can be imported in other stacks “in the same region”. Then, use the Fn::ImportValue intrinsic function to import the value in another stack “in the same region”.

Outputs:
  StackVPC:
    Description: The ID of the VPC
    Value: !Ref MyVPC
    Export:
      Name: !Sub "${AWS::StackName}-VPCID"

Some other important Intrinsic Functions

Fn::GetAtt

The Fn::GetAtt intrinsic function returns the value of an attribute from a resource in the template.

Syntax

!GetAtt logicalNameOfResource.attributeName

  • logicalNameOfResource
    • The logical name (also called logical ID) of the resource that contains the attribute that you want.
  • attributeName
    • The name of the resource-specific attribute whose value you want. See the resource’s reference page for details about the attributes available for that resource type.
  • Return value
    • The attribute value.

A more concrete example

!GetAtt myELB.DNSName

Notes: * For the Fn::GetAtt logical resource name, you can’t use functions. You must specify a string that’s a resource’s logical ID. * For the Fn::GetAtt attribute name, you can use the Ref function.

Fn::ImportValue

The intrinsic function Fn::ImportValue returns the value of an output exported by another stack. You typically use this function to create cross-stack references.

Notes: * For each AWS account, Export names must be unique within a region. * You can’t create cross-stack references across regions. You can use the intrinsic function Fn::ImportValue to import only values that have been exported within the same region. * You can’t delete a stack if another stack references one of its outputs. * You can’t modify or remove an output value that is referenced by another stack.

Syntax

!ImportValue sharedValueToImport

A more concrete example.

Fn::ImportValue:
  !Sub "${NetworkStackName}-SecurityGroupID"

Fn::Sub

The intrinsic function Fn::Sub substitutes variables in an input string with values that you specify. In your templates, you can use this function to construct commands or outputs that include values that aren’t available until you create or update a stack.

Syntax

!Sub
  - String
  - VarName: VarValue

Parameters

  • String
    • A string with variables that AWS CloudFormation substitutes with their associated values at runtime. Write variables as ${MyVarName}. Variables can be template parameter names, resource logical IDs, resource attributes, or a variable in a key-value map.
  • VarName
    • The name of a variable that you included in the String parameter.
  • VarValue
    • The value that CloudFormation substitutes for the associated variable name at runtime.

A more concrete example. The following example uses a mapping to substitute the ${Domain} variable with the resulting value from the Ref function.

Name: !Sub 
  - 'www.${Domain}'
  - Domain: !Ref RootDomainName

Important CloudFormation CLI Commands

  • Package a template using aws cloudformation package command
  • Validate a CloudFormation template using aws cloudformation validate-template command
  • Deploy a template using the aws cloudformation deploy command