Skip to content
intermediate Phase 5 · AWS DevOps Tools

CloudFormation

Provision infrastructure as code with AWS CloudFormation templates.

1h 30m
0 problems
Topic Progress 0%

CloudFormation Fundamentals

CloudFormation Fundamentals

AWS CloudFormation models and provisions AWS resources using template files (Infrastructure as Code).

Template Structure

AWSTemplateFormatVersion: '2010-09-09'
Description: 'Simple EC2 Instance'

Parameters:
  InstanceType:
    Type: String
    Default: t3.micro
    AllowedValues:
      - t3.micro
      - t3.small
      - t3.medium
    Description: EC2 instance type

Resources:
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: ami-0c55b159cbfafe1f0
      KeyName: my-key-pair
      SecurityGroups:
        - !Ref MySecurityGroup
      Tags:
        - Key: Name
          Value: MyWebServer

  MySecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow HTTP
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0

Outputs:
  InstanceId:
    Value: !Ref MyInstance
  PublicIP:
    Value: !GetAtt MyInstance.PublicIp

Template Components

Component Purpose
Parameters Input values (user-provided)
Resources AWS resources to create
Outputs Values to return
Conditions Conditional resource creation
Mappings Static lookup tables
Metadata Additional information

Intrinsic Functions

Intrinsic Functions

Common Functions

# !Ref - Reference a resource or parameter
ImageId: !Ref LatestAmiId

# !GetAtt - Get attribute from a resource
VpcId: !GetAtt MyVPC.VpcId

# !Sub - String substitution
ResourceName: !Sub '${AWS::StackName}-instance'
DNSName: !Sub 'https://${DomainName}/api'

# !Join - Concatenate values
Arn: !Sub 'arn:aws:s3:::${BucketName}/*'

# !Select - Select item from list
Subnet: !Select [0, !GetAZs '']

# !GetAZs - Get availability zones
AZs: !GetAZs Ref: 'AWS::Region'

# !If - Conditional
InstanceType: !If [IsProd, m5.large, t3.micro]

# !Not, !Equals, !And, !Or
Condition: !Not [!Equals [!Ref Env, dev]]

Conditions

Conditions:
  IsProd: !Equals [!Ref Env, production]
  IsDev: !Equals [!Ref Env, development]
  CreateBackup: !Or [!Condition IsProd, !Equals [!Ref EnableBackup, true]]

Resources:
  BackupVolume:
    Type: AWS::EC2::Volume
    Condition: CreateBackup
    Properties:
      AvailabilityZone: !Select [0, !GetAZs '']
      Size: 100
      VolumeType: gp3

Mappings

Mappings:
  RegionMap:
    us-east-1:
      AMI: ami-0c55b159cbfafe1f0
      InstanceType: t3.micro
    eu-west-1:
      AMI: ami-0d71ea30421e2c917
      InstanceType: t3.micro
    ap-southeast-1:
      AMI: ami-0dbbe3f2db8a1c51a
      InstanceType: t3.small

Resources:
  Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !FindInMap [RegionMap, !Ref 'AWS::Region', AMI]
      InstanceType: !FindInMap [RegionMap, !Ref 'AWS::Region', InstanceType]

Stacks and Stack Sets

Stacks and Stack Sets

Create and Manage Stacks

# Create a stack
aws cloudformation create-stack \
  --stack-name my-stack \
  --template-body file://template.yaml \
  --parameters ParameterKey=InstanceType,ParameterValue=t3.micro \
  --capabilities CAPABILITY_NAMED_IAM \
  --tags Key=Environment,Value=Dev

# Wait for completion
aws cloudformation wait stack-create-complete --stack-name my-stack

# Update a stack
aws cloudformation update-stack \
  --stack-name my-stack \
  --template-body file://template.yaml

# Delete a stack
aws cloudformation delete-stack --stack-name my-stack

# List stacks
aws cloudformation list-stacks --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE

# Get stack events
aws cloudformation describe-stack-events --stack-name my-stack

Change Sets

Preview changes before applying:

# Create change set
aws cloudformation create-change-set \
  --stack-name my-stack \
  --change-set-name my-changes \
  --template-body file://template.yaml

# Describe change set
aws cloudformation describe-change-set \
  --stack-name my-stack \
  --change-set-name my-changes

# Execute change set
aws cloudformation execute-change-set \
  --stack-name my-stack \
  --change-set-name my-changes

# Delete change set
aws cloudformation delete-change-set \
  --stack-name my-stack \
  --change-set-name my-changes

Stack Sets

Deploy across multiple accounts and regions:

# Create stack set
aws cloudformation create-stack-set \
  --stack-set-name my-stackset \
  --template-body file://template.yaml \
  --permission-model SERVICE_MANAGED

# Deploy to accounts
aws cloudformation create-stack-instances \
  --stack-set-name my-stackset \
  --accounts '123456789012,987654321098' \
  --regions us-east-1 eu-west-1

# Check status
aws cloudformation describe-stack-set-operation \
  --stack-set-name my-stackset \
  --operation-id xxx

Drift Detection and Stack Policies

Drift Detection and Stack Policies

Drift Detection

# Detect drift
aws cloudformation detect-stack-drift \
  --stack-name my-stack

# Describe drift status
aws cloudformation describe-stack-drift-detection-status \
  --stack-drift-detection-id xxx

# List drifted resources
aws cloudformation describe-stack-resource-drifts \
  --stack-name my-stack \
  --stack-resource-drift-status-filters MODIFIED DELETED

Stack Policies

{
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "Update:*",
      "Principal": "*",
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "ResourceType": [
            "AWS::RDS::DBInstance",
            "AWS::ElasticLoadBalancerV2::LoadBalancer"
          ]
        }
      }
    }
  ]
}
# Set stack policy
aws cloudformation set-stack-policy \
  --stack-name my-stack \
  --stack-policy-body file://policy.json

# Get stack policy
aws cloudformation get-stack-policy --stack-name my-stack

Nested Stacks

# Parent template
Resources:
  VPCStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://s3.amazonaws.com/my-bucket/vpc.yaml
      Parameters:
        VpcCIDR: 10.0.0.0/16

  WebStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://s3.amazonaws.com/my-bucket/web.yaml
      Parameters:
        VpcId: !GetAtt VPCStack.Outputs.VpcId
        SubnetId: !GetAtt VPCStack.Outputs.PublicSubnet

CloudFormation Best Practices

CloudFormation Best Practices

Template Best Practices

# Use parameters for reusable templates
Parameters:
  Environment:
    Type: String
    AllowedValues: [dev, staging, prod]
    Default: dev

# Use mappings for region-specific values
# Use conditions for environment-specific resources
# Use outputs to export values

Outputs:
  VpcId:
    Value: !Ref MyVPC
    Export:
      Name: !Sub '${AWS::StackName}-VpcId'

  SubnetId:
    Value: !Ref PublicSubnet
    Export:
      Name: !Sub '${AWS::StackName}-SubnetId'

CLI Commands

# Validate template
aws cloudformation validate-template --template-body file://template.yaml

# Estimate costs
aws cloudformation estimate-template-cost --template-body file://template.yaml

# Package local templates
aws cloudformation package \
  --template-file template.yaml \
  --s3-bucket my-template-bucket \
  --output-template-file packaged.yaml

# Deploy with guided prompts
aws cloudformation deploy \
  --template-file packaged.yaml \
  --stack-name my-stack \
  --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \
  --parameter-overrides Env=prod InstanceType=m5.large

Security

  • Never store secrets in templates
  • Use SSM Parameter Store or Secrets Manager
  • Use least-privilege IAM roles
  • Enable CloudTrail for audit logging
  • Use stack policies to protect critical resources