Ir al contenido

AWS CloudFormation Cheat Sheet

Overview

AWS CloudFormation is Amazon’s native infrastructure as code service that allows you to model, provision, and manage AWS resources by writing declarative templates in JSON or YAML. You describe your desired infrastructure state in a template, and CloudFormation handles the creation, updating, and deletion of resources in the correct order, managing dependencies automatically. CloudFormation is free to use—you only pay for the resources it creates.

CloudFormation organizes resources into stacks, which are deployed as a single unit. Stacks can reference other stacks through nested stacks or cross-stack references using exports. Change sets let you preview modifications before applying them. CloudFormation supports drift detection to identify manual changes, stack policies to protect critical resources, and StackSets for deploying across multiple accounts and regions. The CloudFormation Registry extends support to third-party resources through custom resource providers.

Installation

AWS CLI Setup

# Install AWS CLI
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

# Configure credentials
aws configure

# Install cfn-lint for template validation
pip install cfn-lint

# Install rain (improved CloudFormation CLI)
brew install rain

Core Commands

CommandDescription
aws cloudformation create-stackCreate a new stack
aws cloudformation update-stackUpdate an existing stack
aws cloudformation delete-stackDelete a stack
aws cloudformation describe-stacksList/describe stacks
aws cloudformation describe-stack-eventsView stack events
aws cloudformation validate-templateValidate template syntax
aws cloudformation create-change-setPreview changes before applying
aws cloudformation detect-stack-driftCheck for manual changes
aws cloudformation list-exportsList cross-stack exports
aws cloudformation packagePackage local artifacts for deployment

Stack Operations

# Create stack
aws cloudformation create-stack \
  --stack-name my-app \
  --template-body file://template.yaml \
  --parameters ParameterKey=Environment,ParameterValue=production \
  --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \
  --tags Key=Project,Value=MyApp

# Update stack
aws cloudformation update-stack \
  --stack-name my-app \
  --template-body file://template.yaml \
  --parameters ParameterKey=Environment,ParameterValue=production

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

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

# Describe stack outputs
aws cloudformation describe-stacks --stack-name my-app --query 'Stacks[0].Outputs'

Change Sets

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

# Describe change set
aws cloudformation describe-change-set \
  --stack-name my-app \
  --change-set-name update-v2

# Execute change set
aws cloudformation execute-change-set \
  --stack-name my-app \
  --change-set-name update-v2

Template Structure

AWSTemplateFormatVersion: '2010-09-09'
Description: 'Production web application infrastructure'

Parameters:
  Environment:
    Type: String
    Default: dev
    AllowedValues: [dev, staging, production]
  InstanceType:
    Type: String
    Default: t3.micro
    AllowedValues: [t3.micro, t3.small, t3.medium]

Mappings:
  RegionAMI:
    us-east-1:
      AMI: ami-0abcdef1234567890
    us-west-2:
      AMI: ami-0fedcba0987654321

Conditions:
  IsProduction: !Equals [!Ref Environment, production]

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-vpc'

  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      MapPublicIpOnLaunch: true

  WebServer:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !If [IsProduction, t3.medium, !Ref InstanceType]
      ImageId: !FindInMap [RegionAMI, !Ref 'AWS::Region', AMI]
      SubnetId: !Ref PublicSubnet
      SecurityGroupIds:
        - !Ref WebSG
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          yum update -y
          yum install -y httpd
          systemctl start httpd

  WebSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Web server security group
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0

  DataBucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    Properties:
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256

Outputs:
  VpcId:
    Value: !Ref VPC
    Export:
      Name: !Sub '${AWS::StackName}-VpcId'
  WebServerIP:
    Value: !GetAtt WebServer.PublicIp
    Description: Public IP of the web server

Intrinsic Functions

FunctionUsageDescription
!Ref!Ref MyResourceReturns resource ID or parameter value
!GetAtt!GetAtt MyBucket.ArnGet resource attribute
!Sub!Sub 'arn:aws:s3:::${Bucket}'String substitution
!Join!Join ['-', [a, b, c]]Join strings with delimiter
!Select!Select [0, !GetAZs '']Select item from list
!Split!Split [',', 'a,b,c']Split string into list
!If!If [IsProd, t3.large, t3.micro]Conditional value
!ImportValue!ImportValue SharedVpcIdCross-stack reference
!FindInMap!FindInMap [Map, Key1, Key2]Lookup in mappings

Configuration

Stack Policy

{
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "Update:*",
      "Principal": "*",
      "Resource": "*"
    },
    {
      "Effect": "Deny",
      "Action": "Update:Replace",
      "Principal": "*",
      "Resource": "LogicalResourceId/Database"
    }
  ]
}
aws cloudformation set-stack-policy \
  --stack-name my-app \
  --stack-policy-body file://policy.json

Advanced Usage

StackSets (Multi-Account/Region)

# Create stack set
aws cloudformation create-stack-set \
  --stack-set-name security-baseline \
  --template-body file://baseline.yaml \
  --permission-model SERVICE_MANAGED \
  --auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false

# Deploy to accounts
aws cloudformation create-stack-instances \
  --stack-set-name security-baseline \
  --deployment-targets OrganizationalUnitIds=ou-abc123 \
  --regions us-east-1 us-west-2 eu-west-1

Nested Stacks

Resources:
  NetworkStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://s3.amazonaws.com/mybucket/network.yaml
      Parameters:
        VpcCidr: 10.0.0.0/16

  AppStack:
    Type: AWS::CloudFormation::Stack
    DependsOn: NetworkStack
    Properties:
      TemplateURL: https://s3.amazonaws.com/mybucket/app.yaml
      Parameters:
        VpcId: !GetAtt NetworkStack.Outputs.VpcId

Drift Detection

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

# Check drift status
aws cloudformation describe-stack-drift-detection-status \
  --stack-drift-detection-id <id>

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

Troubleshooting

IssueSolution
ROLLBACK_COMPLETE stateStack failed creation; delete it and fix the template errors before re-creating
UPDATE_ROLLBACK_FAILEDUse continue-update-rollback with --resources-to-skip for stuck resources
Circular dependencyUse DependsOn carefully; break cycles with !ImportValue across stacks
Resource replacement unexpectedCheck change set before applying; some property changes force replacement
CAPABILITY_IAM requiredAdd --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM to create/update commands
Template validation failsRun cfn-lint template.yaml for detailed error messages
Stack deletion stuckCheck for S3 buckets with data or ENIs attached to Lambda in VPC