- CloudFormation Introduction
- Getting Started with CloudFormation
- Parameters
- Resources
- Mappings
- Outputs
- Conditions
- Rules
- Metadata
- Cloudformation Init and EC2 User Data
- CloudFormation Drift
- Nested Stacks
- StackSets
CloudFormation Introduction
- CloudFormation - A declarative way of outlining your AWS Infrastructure for most available resources. CloudFormation creates these for you in the right order with the exact configuration you specified.
Benefits of AWS CloudFormation:
- Infrastructure as Code (IaC)
- No resources are manually created, excellent for control
- Code can be version controlled using Git
- Changes to the infrastructure are reviewed through code
- Cost
- Each resource within the stack is tagged with an identifier so you can see how much a stack costs you
- You can estimate the costs of your resources using the CloudFormation template
- You could automate creation/deletion to save costs
- Productivity
- Ability to destroy and re-create on the fly
- Automated generation of diagram for your templates
- Declarative programming (no need to order or orchestrate tasks)
- Separation of concerns - Create many stacks for many apps and many layers
- Don't reinvent the wheel - You can leverage existing templates
How does CloudFormation work?
- Templates are uploaded to S3
- CloudFormation references template in S3 to create stack
- Stack creates AWS resources
- To update a template you must re-upload the new version to S3
- Stacks are identified by a name
- Deleting a stack deletes every single artifact that was created by CloudFormation
Getting Started with CloudFormation
- YAML and JSON are languages you can use for CloudFormation, with YAML being preferred
- YAML supports:
- Key-value pairs
- Nested objects
- Support Arrays
- Multi-line strings
- Comments
To create an S3 bucket (full list of properties here):
Resources:
BucketName:
Type: AWS::S3::Bucket
Properties: {}
CloudFormation update behavior depends on which property you update for a resource:
- Update with No Interruption - Updates without disrupting resources' operation & without changing physical ID, eg. updating the IAM instance profile of an EC2 instance
- Update with Some Interruption - eg. updating an EC2 instance type
- Replacement - Recreating the resource with a new physical ID. Creates the new resources, changes references in other resources to the new resource, deletes the old resource
CloudFormation Template Options:
- Tags - Passed onto every resource in stack
- Permissions - IAM role used to create stack
- Notification Options - SNS
- Timeout - How long to wait before CloudFormation operation is seen as a failure
- Rollback on Failure
- Rollback Configuration (Monitoring time & CloudWatch Alarm)
- Stack Policy
- Termination Protection
- Quick-start Link
- AWS Application Composer - Visually design and build serverless applications quickly in AWS
- Generates IaC using CloudFormation
- Allows visualization of existing CloudFormation code
CloudFormation Template Components
- AWSTemplateFormatVersion - "2010-09-09"
- Description - Comments about the template
- Transform - Specifies one or more macros used to process the template
- Metadata
- Resources - The AWS resources you wish to specify
- Parameters - The dynamic inputs for your template
- Mappings - Static variables for your template
- Outputs - References to what has been created
- Conditionals - List of conditions to perform resource creation
- Rules - Validate a parameter during stack creation/update
Deploying CloudFormation templates
- Manual: Edit templates in Application Composer/code editor, use console to input parameters, etc
- Automatic: Edit templates in YAML file, use the AWS CLI to deploy the templates or use a Continuous Deliver (CD) tool.
Parameters
- Parameters are a way to provide inputs to your CF template
- They're important to know about if:
- You want to reuse your templates across the company
- Some inputs can not be determined ahead of time
- Parameters are extremely powerful, controlled and can prevent errors thanks to types
- Parameters can be cross-validated using Rules
- Use a parameter if the CF resource is likely to change in the future.
- You don't have to re-upload templates to change parameter values
- Parameter settings:
- Type:
- String
- Number
- CommaDelimitedList
- List<Number>
- AWS-Specific Parameter (matches with existing values in the AWS account. Supported types listed here)
- List<AWS-Specific Parameter>
- SSM Parameter (get parameter value from SSM Parameter store)
- Description
- ConstraintDescription
- Min/MaxLength
- Min/MaxValue
- Default
- AllowedValues (array)
- AllowedPattern (regex)
- NoEcho (Boolean)
- Type:
- Parameters can be used anywhere in a template except:
- AWSTemplateFormatVersion
- Description
- Transform
- Mappings
- Reference Parameters using
Fn::Ref
or YAML's shorthand!Ref <parameter-name>
- Use
!Select[<index>, <parameter-name>]
to select from a List parameter
SSM Parameter Type
- CloudFormation always fetches the latest value
- CloudFormation doesn't store Secure String values
- Validation done on SSM parameter keys but not values Example:
Parameters:
InstanceType:
Description: WebServer EC2 instance type
Type: AWS::SSM::Parameter::Value<String>
Default: /dev/ec2/instanceType
ImageId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
Resources
- Resources are mandatory in CloudFormation templates. They represent the different AWS components that will be created and configured.
- Resources are declared and can reference each other.
- There are over 700 types of resources
- Resource type identifiers are of the form
AWS::<product-name>::<data-type-name>
- You can create a dynamic number of resources using CloudFormation Macros and Transform
- Almost every AWS Service is supported, but a few still aren't. You can work around these using Custom Resources
Optional attributes for Resources include:
- DependsOn - Creates a dependency between resources, e.g. ensure an ECS cluster is only created after creating an ASG
- DeletionPolicy - Protect resources from being deleted even if the CloudFormation stack is deleted
- UpdateReplacePolicy - Protect resources from being replaced during a CloudFormation update
- CreationPolicy
- UpdatePolicy
- Metadata - Anything you want
DependsOn
Resources:
MyS3Bucket:
Type: AWS::S3::Bucket
MyInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref ImageId
InstanceType: t2.micro
DependsOn: MyS3Bucket
DeletionPolicy
- Can be used with any resource
- Options:
Retain
- Specify what resources should be preserved/backed up in case of CloudFormation deletionSnapshot
- EBS Volume, ElastiCache Cluster, ElastiCache ReplicationGroup, RDS DBInstance, RDS DBCluster, Redshift Cluster, Neptune DBClusterDelete
- (default behaviour)
UpdateReplacePolicy
- Controls what happens to a resource if you update a property whose update behaviour is Replacement
- Can be used with any resource
- Options:
Delete
- Deletes the old resource and creates a new one with a physical ID (default behaviour)Retain
- Keeps the resourceSnapshot
- EBS Volume, ElastiCache Cluster, ElastiCache ReplicationGroup, RDS DBInstance, RDS DBCluster, Redshift Cluster, Neptune DBCluster
Mappings
- Mappings are fixed variables hardcoded within your CloudFormation template
- Handy to differentiate between different environments, regions, AMI types, etc
- Mappings are great when you know in advance all the values that can be taken and can be deduced from variables like Region, Availability Zone, AWS Account, Environment, etc. Use parameters when values cannot be predicted ahead of time.
- To Access Map Values:
Fn::FindInMap
, or!FindInMap[MapName, TopLevelKey, SecondLevelKey]
Pseudo Parameters
- Pseudo-Parameters are variables that can be used in any CloudFormation template at any time and are enabled by default
Reference Value Example Returned Value AWS::AccountId 123456789012 AWS::Region us-east-1 AWS::StackId arn:aws:cloudformation:us-east-1:123456789012:stack/MyStack/1c2fa620-982a-11e3-aff7-50e2416294e0
AWS::StackName MyStack AWS::NotificationARNs [arn:aws:sns:us-east-1:123456789012:MyTopic] AWS::NoValue Doesn't return a value AWS::Partition aws, aws-cn, aws-us-gov AWS::URLSuffix amazonaws.com / amazonaws.com.cn
Outputs
- The
Outputs
section declares optional outputs that can be imported into other stacks Example:
Outputs:
StackSSHSecurityGroup:
Description: The SSH Security Group for our company
Value: !Ref MyCompanyWideSSHSecurityGroup
Export:
Name: SSHSecurityGroup
- Outputs can be viewed in the AWS Console or using the AWS CLI
- Outputs are the best way to perform cross-stack collaboration, eg.
resources:
MySecureInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref ImageId
InstanceType: t2.micro
SecurityGroups:
- !ImportValue SSHSecurityGroup
Conditions
- Conditions are used to control the creation of resources or outputs based on a condition
- Can be whatever you want them to be but common ones are:
- Environment (dev/test/prod)
- AWS Region
- Any parameter value
Example usage
Conditions:
# Defining a condition
# True if parameter 'EnvType' is equal to the word 'prod'
CreateProdResources: !Equals [!Ref EnvType, prod]
Resources:
MountPoint:
Type: AWS::EC2::VolumeAttachment
# Using a condition
# 'MountPoint' will only be created if condition is true
Condition: CreateProdResources
The intrinstic function can be any of the following (use with either the Fn::
prefix or !
):
!And
!Equals
!If
!Not
!Or
Fn::GetAtt
- Attributes are attached to any resources you create
- You can reference attributes of resources in your template with
!GetAtt <resource-name>.<attribute>
Rules
- Rules are used to perform parameter validations based on the values of other parameters (cross-parameter validation)
- Each Rule consists of:
- Condition (optional) under which a rule will be applied
- Assertions - Describes what values are allowed for a particular parameter. Can contain one or more assertions
- If you don't define a Rule Condition the rule's assertions will take effect with every create/update operation Example:
Rules:
IsSSLCertificate:
RuleCondition: !Equals
- !Ref UseSSL
- Yes
Assertions:
- Assert: !Not
- !Equals
- !Ref ALBSSLCertificateARN
- ''
AssertDescription: 'ACM certificate value can not be empty if SSL is required'
- Supported functions:
Fn::And
Fn::Contains
Fn::EachMemberEquals
Fn::EachMemberIn
Fn::Equals
Fn::If
Fn::Not
Fn::Or
Fn::RefAll
Fn::ValueOf
Fn::ValueOfAll
Metadata
- You can use the optional metadata section to include arbitrary YAML that provides details about the template or its resources
- Meaningful Metadata keys:
- Interface - Define grouping and ordering of input parameters when they're displayed in the AWS Console
- Authentication - Used to specify authentication credentials for files or sources that you specify in Init
- Init - Define configuration tasks for cfn-lint.
Example Interface
usage:
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: 'Network Configuration'
Parameters:
- SubnetID
- SecurityGroupID
- Label:
default: 'Amazon EC2 Configuration'
Parameters:
- InstanceType
-
Cloudformation Init and EC2 User Data
- CloudFormation Init and EC2 user data both enable you to fully automate your EC2 fleet state
UserData
is defines the commands EC2 instances run on startup. Scripts can be passed through using the FunctionFn::Base64
, eg.
Resources:
WebServer:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref ImageId
InstanceType: t2.micro
KeyName: !Ref KeyName
SecurityGroups:
- !Ref WebServerSecurityGroup
UserData:
Fn::Base64: |
#! /bin/bash
echo "Hello world!"
apt install ...
WebServerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Enable HTTP access via port 80 + SSH access
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
IpProtocol: tcp
FromPort: 80
ToPort: 80
- CidrIp: !Ref SSHLocation
IpProtocol: tcp
FromPort: 22
ToPort: 22
-
User data script logs are stored at
/var/log/cloud-init-output.log
-
Issues with EC2 User Data
- What if we want to have a very large instance configuration?
- What if we want to evolve the state of the EC2 instance without terminating it and creating a new one?
- How do we make EC2 user-data more readable?
- How do we know or signal that our EC2 user-data script completed successfully?
-
There are 4 cloudformation helper scripts that come with Amazon Linux 2 AMIs or can be installed using
yum
cfn-init
- Used to retrieve and interpret the resource metadata, installing packages, creating files and starting services. Logs to/var/log/cfn-init.log
cfn-signal
- A simple wrapper to signal a CreationPolicy or WaitCondition to CloudFormation, enabling you to synchronize other resources in the stack with the application being ready. Logs to/var/log/cfn-signal
cfn-get-metadata
- A wrapper script making it easy to retrieve either all metadata defined for a resource or path to a specific key or subtree of the resource metadata. Relies on configuration files at/etc/cfn/cfn-hyp.conf
and/etc/cfn/hooks.d/cfn-auto-reloader.conf
cfn-hup
- A daemon to check for updates to the metadata and execute custom hooks when the changes are detected
-
Usual script flow:
cfn-init
->cfn-signal
-> (optionally)cfn-hup
-
A CloudFormation::Init
config
contains the following (executed in this order);- Packages - Used to download an install pre-packaged apps and components on Linux/Windows. Specify the package manager and a list of packages, along with their versions.
- Groups - Define user groups
- Users - Define users and which group they belong to
- Sources - Download files and archives and place them on the EC2 instance
- Files - Create files on the EC2 isntance using inline or can be pulled from a URL
- Commands - Run a series of commands
- Services - Launch a list of
sysvinit
services. Services will be started when files are changed or relevant packages are updated bycfn-init
AWS::CloudFormation::Init:
config:
packages:
yum:
node: ['21.1.2']
httpd: [] # empty array = get latest
groups:
groupOne: {}
groupTwo:
gid: '45'
users:
myUser:
groups:
- 'groupOne'
- 'groupTwo'
uid: '50'
homeDir: '/tmp'
sources:
/etc/myapp: https://s3.amazonaws.com/mybucket/myapp.tar.gz
/etc/puppet: https://github.com/user1/cfn-demo/tarball/main
files:
/tmp/example.txt:
content: Hello!
mode: 000644
owner: root
group: root
# authentication (optional; tied to AWS::CloudFormation::Authentication)
# source (optional)
commands:
test:
command: echo "${MAGIC}" > test.txt
env:
MAGIC: I come from the environment!
cwd: '~' # working directory to run command in
test: test ! -e ~/test.txt # tests if test.txt was created
ignoreErrors: false
services:
sysvinit:
nginx:
enable: true
ensureRunning: true
files:
- '/etc/nginx/nginx.conf'
sources:
- /var/www/html
php-fastcgi:
enabled: true
ensureRunning: true
packages:
yum:
- php
- spawn-fcgi
- You can have multiple configs in your Init by creating
configSets
invoked from your EC2 user data
AWS::CloudFormation::Authentication
Example:
AWS::CloudFormation::Authentication:
S3AccessCreds:
type: S3
buckets:
- !Sub ${MyS3BucketName}
roleName: !Ref InstanceRole
InstanceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: 'sts:AssumeRole'
Principal:
Service: ec2.amazonaws.com
Effect: Allow
Sid: ''
Policies:
- PolicyName: AuthenticatedS3GetObjects
PolicyDocument:
Version 2012-10-17
Statement:
- Action:
- s3:GetObject
Resource: !Sub 'arn:aws:s3:::${MyS3BucketName}/*'
Effect: Allow
Fn::Sub
allows you to substitute variables from a text, for example with references or AWS Pseudo variables
CloudFormation Drift
- Drifting - Resource configurations being manually changed after creation. The resource is 'drifting' from the specification.
- CloudFormation Drift is a service that can detect drift for an entire stack or on individual stack resources.
- Stack/resource drift can be resolved by using Resource Import
Nested Stacks
- Nested Stacks are stacks that are part of other stacks.
- They allow you to isolate repeated patterns / common components in separate stacks and call them from other stacks
- Helpful when stack components must be re-used
- To update a nested stack, ensure the updated nested stacks are uploaded onto S3, then re-upload your root stack template
- To delete a nested stack, delete the root stack.
- If your stacks have different lifecycles or import/export values from other stacks, use cross stacks instead
StackSets
- StackSets allow you to create, update or delete stacks across multiple accounts and regions with a single operation/template
- Admins create StackSets, target accounts create, update, delete stack instances from StackSets
- When you update a StackSet, all associated stack instances are updated throughout all accounts and regions
- Can be applied into all accounts of an AWS organization
- StackSet operations:
- Create - Provide template + target accounts/regions
- Update - Updates always affect all stacks
- Delete Stacks - Delete stack and its resources from target accounts/regions or from its stack
- Delete StackSet - Must delete all stack instances within StackSet to delete it
- StackSet deployment options:
- Deployment Order
- Maximum concurrent accounts
- Failure tolerance