CloudFormation

  • CloudFormation is a service that allows you to manage, configure and provision your AWS infrastructure as a code (IaaC).

  • Resources are defined using a CloudFormation template.

  • CloudFormation interpretes and makes the appropriate API calls to create the resources you have defined.

  • Supports YAML or JSON.

Benefits

  • Infrastructure provisioned consistently, with fewer mistakes

  • Less time and effort than configuring things manually

  • You can version control and peer review your templates

  • Free to use (charged only for what you create)

  • Can be used to manage updates and dependencies

  • Can be used to rollback and delete the entire stack

Template

  • YAML or JSON used to describe the end state of the infrastructure you are either provisioning or changing

  • After creating the template, you upload it to CloudFormation using S3

  • CloudFormation reads the template and makes the API calls on your behalf

  • The resulting resources are called a Stack

  • Resources is the only mandatory section of the CloudFormation template

  • Transform section is used to reference additional code stored in S3, allowing for code reuse

  • All keys in the template file are CASE SENSITIVE, if there is a mistake in the template stack creation/update will fail.

AWSTemplateFormatVersion: 2010-09-09
Description: |
  
Parameters:
  
Metadata:
  
Mappings:
  
Conditions:
  
Resources: # required
  
Transform:
  
Outputs:

  • Resources are key components of the stack

  • Resources section is a required section that need to be defined in CloudFormation template

Resources:
  LogicalID:
    Type: Resource type
    Properties:
      Set of properties

Important: You can't nest short form functions consecutively.

Invalid:

AvailabilityZone: !Select 
  - 0
  - !GetAZs !Ref 'AWS::Region'

Valid:

AvailabilityZone: !Select 
  - 0
  - Fn::GetAZs: !Ref 'AWS::Region'
  • Ref - The intrinsic function Ref returns the value of the specified parameter or resource.

  • Fn::FindInMap - returns the value corresponding to keys in a two-level map that is declared in the Mappings section.

Mappings: 
  RegionMap: 
    us-east-1: 
      HVM64: "ami-0ff8a91507f77f867"
      HVMG2: "ami-0a584ac55a7631c0c"
    us-west-1: 
      HVM64: "ami-0bdb828fd58c52235"
      HVMG2: "ami-066ee5fd4a9ef77f1"
    eu-west-1: 
      HVM64: "ami-047bb4163c506cd98"
      HVMG2: "ami-31c2f645"
    ap-southeast-1: 
      HVM64: "ami-08569b978cc4dfa10"
      HVMG2: "ami-0be9df32ae9f92309"
    ap-northeast-1: 
      HVM64: "ami-06cd52961ce9f0d85"
      HVMG2: "ami-053cdd503598e4a9d"
Resources: 
  myEC2Instance: 
    Type: "AWS::EC2::Instance"
    Properties: 
      ImageId: !FindInMap
        - RegionMap
        - !Ref 'AWS::Region'
        - HVM64
      InstanceType: m1.small
  • Fn::Select - returns a single object from a list of objects by index.

Parameters: 
  DbSubnetIpBlocks: 
    Description: "Comma-delimited list of three CIDR blocks"
    Type: CommaDelimitedList
    Default: "10.0.48.0/24, 10.0.112.0/24, 10.0.176.0/24"

Subnet0: 
  Type: "AWS::EC2::Subnet"
  Properties: 
    VpcId: !Ref VPC
    CidrBlock: !Select [ 0, !Ref DbSubnetIpBlocks ]
  • Fn::GetAtt - returns the value of an attribute from a resource in the template. To find what properties a specific resource can return with Fn::GetAtt, refer to that Resource documentation (for instance, EC2 Instance Return Values)

!GetAtt myELB.DNSName
  • 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.

Fn::ImportValue:
  !Sub "${NetworkStackName}-SecurityGroupID"
  • 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.

!Sub 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:vpc/${vpc}'
  • Fn::Join - appends a set of values into a single value, separated by the specified delimiter. If a delimiter is the empty string, the set of values are concatenated with no delimiter.

!Join
  - ''
  - - 'arn:'
    - !Ref AWS::Partition
    - ':s3:::elasticbeanstalk-*-'
    - !Ref 'AWS::AccountId'
  • Fn::Split - To split a string into a list of string values so that you can select an element from the resulting string list, use the Fn::Split intrinsic function. Specify the location of splits with a delimiter, such as , (a comma). After you split a string, use the Fn::Select function to pick a specific element.

!Select [2, !Split [",", !ImportValue AccountSubnetIDs]]
  • Fn::Base64 - returns the Base64 representation of the input string. This function is typically used to pass encoded data to Amazon EC2 instances by way of the UserData property.

Resources:
  SimpleEC2Instance:
    Type: "AWS::EC2::Instance"
    Properties:
      ImageId: ami-0d6621c01e8c2de2c
      InstanceType: t3.nano
      KeyName: test-cfn-kp
      SecurityGroups:
        - default
      UserData: 
        !Base64 |
          #!/bin/bash
          yum update -y
          amazon-linux-extras install -y lamp-mariadb10.2-php7.2 php7.2
          yum install -y httpd mariadb-server
          systemctl start httpd
          systemctl enable httpd
          usermod -a -G apache ec2-user
          chown -R ec2-user:apache /var/www
          chmod 2775 /var/www
          find /var/www -type d -exec chmod 2775 {} \;
          find /var/www -type f -exec chmod 0664 {} \;
          echo "<?php phpinfo(); ?>" > /var/www/html/phpinfo.php
      Tags:
        - Key: Name 
          Value: SimpleEC2
  • Fn::GetAZs - returns an array that lists Availability Zones for a specified region. Because customers have access to different Availability Zones, the intrinsic function Fn::GetAZs enables template authors to write templates that adapt to the calling user's access. That way you don't have to hard-code a full list of Availability Zones for a specified region.

AvailabilityZone: !Select 
  - 0
  - Fn::GetAZs: !Ref 'AWS::Region'
  • Fn::Cidr - returns an array of CIDR address blocks. The number of CIDR blocks returned is dependent on the count parameter.

!Cidr [ "192.168.0.0/24", 6, 5 ]
  • Fn::Transform - specifies a macro to perform custom processing on part of a stack template. Macros enable you to perform custom processing on templates, from simple actions like find-and-replace operations to extensive transformations of entire templates.

  • Fn::Equals - Compares if two values are equal. Returns true if the two values are equal or false if they aren't.

  • Fn::If - Returns one value if the specified condition evaluates to true and another value if the specified condition evaluates to false.

  • Fn::And - Returns true if all the specified conditions evaluate to true, or returns false if any one of the conditions evaluates to false. Fn::And acts as an AND operator. The minimum number of conditions that you can include is 2, and the maximum is 10.

  • Fn::Not - Returns true for a condition that evaluates to false or returns false for a condition that evaluates to true. Fn::Not acts as a NOT operator.

  • Fn::Or - Returns true if any one of the specified conditions evaluate to true, or returns false if all of the conditions evaluates to false. Fn::Or acts as an OR operator. The minimum number of conditions that you can include is 2, and the maximum is 10.

Pseudo parameters are parameters that are predefined by AWS CloudFormation. You do not declare them in your template. Use them the same way as you would a parameter, as the argument for the Ref function.

  • AWS::AccountId - Current account ID

  • AWS::NotificationARNs - List of notification ARNs for current stack

  • AWS::NoValue - Removes resource property. Used with Fn::If

  • AWS::Partition - Partition that the resource is in

  • AWS::Region - Current region

  • AWS::StackId - Current stack ID

  • AWS::StackName - Current name of the stack

  • AWS::URLSuffix - Suffix for a domain, typically amazonaws.com

  • Enable us to input custom values to our template each time when we create or update the stack

  • There can be maximum of 60 parameters in the template

  • Each parameter must be given a logical name (logical ID), which must be alphanumeric and unique among all logical names within the template

  • Each parameter must be assigned a parameter type that is supported by AWS CloudFormation

  • Each parameter must be assigned a value at runtime for AWS CloudFormation to successfully provision the stack. We can optionally specify a default value to use unless another value is provided

  • Parameters must be declared and referenced from within the same template. You can reference parameters from the Resources and Outputs sections of the template

  • Parameter type can one of the supported built-in types, like String, List, etc, or AWS-specific parameters, like AWS::EC2::KeyPair::KeyName or parameters that are linked to SSM Parameter Store (AWS::SSM::Parameter::Value)

Parameters:
  ParameterLogicalID:
    Type: DataType
    ParameterProperty: value

  • The optional Mappings section matches a key to a corresponding set of named values. 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 to retrieve values in a map.

Mappings: 
  Mapping01: 
    Key01: 
      Name: Value01
    Key02: 
      Name: Value02
    Key03: 
      Name: Value03

  • The optional Conditions section contains statements that define the circumstances under which entities are created or configured. For example, you can create a condition and then associate it with a resource or output so that AWS CloudFormation only creates the resource or output if the condition is true. Similarly, you can associate the condition with a property so that AWS CloudFormation only sets the property to a specific value if the condition is true. If the condition is false, AWS CloudFormation sets the property to a different value that you specify.

Conditions:
  Logical ID:
    Intrinsic function
  • Conditions are evaluated based on predefined pseudo parameters or input parameter values that we specify when we create or update stack

  • Within each condition we can reference other condition

  • We can associate these conditions in three places

    • Resources

    • Resource properties

    • Outputs

  • At stack creation or stack update, CloudFormation evaluates all condifitions in our template. During stack update, Resources that are now associated with a false condition are deleted.

  • Note: During stack update we can't update conditions by themselves. We can update conditions only when we include changes that add, modify or delete resources.

  • Output section declares output values that we can

    • Import into another stack (to create cross-stack references)

    • When using nested stacks, we can see how outputs of a nested stack are used in Root Stack

    • We can view outputs in the CloudFormation console

  • We can declare maximum of 60outputs in a template

Outputs:
  Logical ID:
    Description: Information about the value
    Value: Value to return
    Export:
      Name: Value to export
  • Export (optional property)

    • Export contain resource output used for cross-stack reference

    • For each AWS account, Export name must be unique within the region. As it should be unique, we create the export name as "AWS::StackName"-ExportName

    • We can't create cross-stack references across regions

    • We can use the intrinsic function Fn::ImportValue to import values that have been exported within the same region

    • For outputs, the value of the Name property of an Export can't use Ref of GetAtt function that depend on a resource

    • We can't delete a stack if another stack references one of it's outputs

    • We can't modify of remove an output value that is referenced by another stack

    • We can use Outputs in combination with Conditions.

  • You can use the optional Metadata section to include arbitrary JSON or YAML objects that provide details about the template. For example, you can include template implementation details about specific resources. During a stack update, you cannot update the Metadata section by itself. You can update it only when you include changes that add, modify, or delete resources.

    • AWS::CloudFormation::Init - Defines configuration tasks for the cfn-init helper script. This script is useful for configuring and installing applications on EC2 instances.

    • AWS::CloudFormation::Interface - Defines the grouping and ordering of input parameters when they are displayed in the AWS CloudFormation console. By default, the AWS CloudFormation console alphabetically sorts parameters by their logical ID.

    • AWS::CloudFormation::Designer - Describes how your resources are laid out in AWS CloudFormation Designer (Designer). Designer automatically adds this information when you use it to create and update templates.

AWS CloudFormation provides the following Python helper scripts that you can use to install software and start services on an Amazon EC2 instance that you create as part of your stack:

  • cfn-init: Use to retrieve and interpret resource metadata, install packages, create files, and start services.

  • cfn-signal: Use to signal with a CreationPolicy or WaitCondition, so you can synchronize other resources in the stack when the prerequisite resource or application is ready.

  • cfn-get-metadata: Use to retrieve metadata for a resource or path to a specific key.

  • cfn-hup: Use to check for updates to metadata and execute custom hooks when changes are detected.

You call the scripts directly from your template. The scripts work in conjunction with resource metadata that's defined in the same template. The scripts run on the Amazon EC2 instance during the stack creation process.

  • Use the AWS::CloudFormation::Init type to include metadata on an Amazon EC2 instance for the cfn-init helper script. If your template calls the cfn-init script, the script looks for resource metadata rooted in the AWS::CloudFormation::Init metadata key.

  • The metadata is organized into config keys, which you can group into configsets. You can specify a configset when you call cfn-init in your template. If you don't specify a configset, cfn-init looks for a single config key named config.

  • The cfn-init helper script processes these configuration sections in the following order: packages, groups, users, sources, files, commands, and then services. If you require a different order, separate your sections into different config keys, and then use a configset that specifies the order in which the config keys should be processed.

Resources: 
  MyInstance: 
    Type: AWS::EC2::Instance
    Metadata: 
      AWS::CloudFormation::Init: 
        config: 
          packages: 
            :
          groups: 
            :
          users: 
            :
          sources: 
            :
          files: 
            :
          commands: 
            :
          services: 
            :
    Properties: 
      :

Last updated