AWS CloudFormation Basics: Ultimate Developer’s Cheatsheet

Introduction: What is CloudFormation and Why It Matters

AWS CloudFormation is an Infrastructure as Code (IaC) service that allows you to model, provision, and manage AWS and third-party resources by treating infrastructure as code. CloudFormation enables you to:

  • Define infrastructure in code: Create templates describing all your AWS resources and their properties
  • Automate deployments: Provision resources in a safe, repeatable manner
  • Manage the entire lifecycle: Create, update, and delete resources as a single unit (stack)
  • Track changes: Version control your infrastructure just like application code
  • Save time and reduce errors: Eliminate manual processes and configuration drift

Core Concepts and Principles

ConceptDescription
TemplateJSON or YAML file that describes the AWS resources and their properties
StackCollection of AWS resources created and managed as a single unit
Change SetSummary of proposed changes to a stack before executing them
Stack SetFeature allowing you to create stacks across multiple accounts and regions
Drift DetectionProcess to identify when resources have been changed outside of CloudFormation
Nested StackStack created as part of another stack, enabling resource reuse
Custom ResourcesResources that enable you to write custom provisioning logic
ParameterInput values that can be specified when creating or updating a stack
OutputValues exported from a stack that can be imported into other stacks
MappingWay to define lookup tables for use within a template

Template Structure

CloudFormation templates have the following main sections:

AWSTemplateFormatVersion: "2010-09-09"
Description: "Description of the template"
Metadata: 
  # Template metadata
Parameters: 
  # Input parameters
Mappings: 
  # Key-value mappings for lookup
Conditions: 
  # Conditions that control resource creation
Transform: 
  # For serverless applications (e.g., AWS SAM)
Resources: 
  # The AWS resources to create (REQUIRED)
Outputs: 
  # Values to return

Step-by-Step Process: Creating and Deploying CloudFormation Templates

Method 1: AWS Management Console

  1. Create template:

    • Write your template in JSON or YAML format
    • Save the file with a .json or .yml extension
  2. Create stack:

    • Open AWS Management Console and navigate to CloudFormation
    • Click “Create stack” and choose “With new resources”
    • Upload your template file or specify an S3 URL
    • Provide a stack name and any required parameters
    • Configure stack options (tags, permissions, rollback configuration)
    • Review and create the stack
  3. Monitor stack creation:

    • View the “Events” tab to track progress
    • Check the “Resources” tab to see created resources
    • View the “Outputs” tab to see any exported values
  4. Update stack (when needed):

    • Select the stack and click “Update”
    • Choose to update with current or new template
    • Modify parameters if needed
    • Review changes and update

Method 2: AWS CLI

  1. Create template file (template.yml)

  2. Validate template:

    aws cloudformation validate-template --template-body file://template.yml
    
  3. Create stack:

    aws cloudformation create-stack \
      --stack-name MyStack \
      --template-body file://template.yml \
      --parameters ParameterKey=KeyName,ParameterValue=MyKey
    
  4. Monitor stack creation:

    aws cloudformation describe-stacks --stack-name MyStack
    aws cloudformation describe-stack-events --stack-name MyStack
    
  5. Update stack:

    aws cloudformation update-stack \
      --stack-name MyStack \
      --template-body file://updated-template.yml
    
  6. Delete stack:

    aws cloudformation delete-stack --stack-name MyStack
    

Key Techniques and Resources

Resource Declaration

Resources:
  MyEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      ImageId: ami-0abcdef1234567890
      SecurityGroups:
        - !Ref MySecurityGroup

Intrinsic Functions

FunctionDescriptionExample
!RefReferences a resource or parameter!Ref MyParameter
!GetAttGets an attribute from a resource!GetAtt MyInstance.PrivateIp
!JoinJoins values with a delimiter!Join [":", [a, b, c]] → “a:b:c”
!SplitSplits a string by a delimiter!Split [",", "a,b,c"] → [“a”, “b”, “c”]
!SubSubstitutes variables in a string!Sub "Hello ${Name}"
!CidrReturns CIDR address blocks!Cidr [ipBlock, count, cidrBits]
!FindInMapReturns a named value from a mapping!FindInMap [MapName, TopKey, SecondKey]
!SelectSelects an item from a list!Select [index, listOfObjects]
!IfReturns one value if condition is true, another if false!If [condition, valueIfTrue, valueIfFalse]
!EqualsReturns true if two values are equal!Equals [value1, value2]

Parameters

Parameters:
  InstanceType:
    Type: String
    Default: t2.micro
    AllowedValues:
      - t2.micro
      - t2.small
      - t3.micro
    Description: EC2 instance type
  
  KeyName:
    Type: AWS::EC2::KeyPair::KeyName
    Description: Name of an existing EC2 KeyPair

Outputs

Outputs:
  WebsiteURL:
    Description: URL for the website
    Value: !Join ["", ["http://", !GetAtt WebServer.PublicDnsName]]
    Export:
      Name: !Sub "${AWS::StackName}-URL"  # Can be imported in other stacks

Resource Dependencies

CloudFormation automatically creates dependencies based on references between resources. You can also create explicit dependencies:

Resources:
  MyDatabase:
    Type: AWS::RDS::DBInstance
    Properties:
      # properties here

  MyWebServer:
    Type: AWS::EC2::Instance
    DependsOn: MyDatabase  # Explicit dependency
    Properties:
      # properties here

Parameter Types and Constraints

Parameter TypeDescription
StringA literal string
NumberAn integer or float
List<Number>An array of integers or floats
CommaDelimitedListAn array of literal strings separated by commas
AWS::EC2::KeyPair::KeyNameAn existing EC2 key pair name
AWS::EC2::SecurityGroup::IdAn existing security group ID
AWS::EC2::Subnet::IdAn existing subnet ID
AWS::EC2::VPC::IdAn existing VPC ID
AWS::SSM::Parameter::NameAn existing Systems Manager parameter name
AWS::SSM::Parameter::Value<Type>An existing Systems Manager parameter value

Comparisons: CloudFormation vs. Other IaC Tools

FeatureCloudFormationTerraformAWS CDK
LanguageJSON/YAMLHCLTypeScript, Python, Java, C#
Provider SupportAWS (primarily)Multi-cloudAWS (primarily)
State ManagementManaged by AWSLocal or remote state fileSame as CloudFormation
ModularityNested stacks, custom resourcesModulesConstructs
Imperative OperationsLimitedLimitedSupported
Learning CurveModerateModerateSteep (requires programming)
Drift DetectionYesYesYes (via CloudFormation)
Community EcosystemAWS-focusedLarger, multi-cloudGrowing

Common Challenges and Solutions

ChallengeSolution
Template size limitsUse nested stacks to break down large templates
Stack update failuresUse Change Sets to preview changes, implement proper rollback triggers
Resource replacement during updatesUse UpdatePolicy and CreationPolicy to control resource lifecycle
Managing secretsUse AWS Secrets Manager or Parameter Store for sensitive data
Cross-stack referencesUse Export and Fn::ImportValue for sharing outputs
Slow stack creation/updatesParallelize independent resources, optimize dependencies
Template reusabilityUse Mappings, Parameters, and nested stacks
API rate limitingImplement exponential backoff in custom resources
Manual resource modificationsUse drift detection to identify changes

Best Practices and Tips

Template Design

  • Validate templates before deployment using aws cloudformation validate-template
  • Use YAML instead of JSON for better readability and support for comments
  • Organize templates into logical components (networking, compute, storage)
  • Use descriptive names for resources and parameters
  • Document templates with comments and descriptions

Security

  • Use IAM roles with minimum permissions for CloudFormation
  • Enable stack termination protection for production stacks
  • Review all changes using Change Sets before applying
  • Avoid hardcoding credentials in templates
  • Use parameter constraints to enforce security requirements

Operations

  • Tag all resources for cost tracking and identification
  • Use stack policies to prevent updates to critical resources
  • Implement monitoring for stack operations
  • Use deletion policies to retain important resources when stacks are deleted
  • Automate stack deployments using CI/CD pipelines

Performance

  • Initialize required services before deployment to avoid API throttling
  • Test templates in dev/test environments before production
  • Use nested stacks to improve deployment performance

Advanced Features

Stack Policies

Stack policies control which resources can be updated and how:

{
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "Update:*",
      "Principal": "*",
      "Resource": "*"
    },
    {
      "Effect": "Deny",
      "Action": "Update:Replace",
      "Principal": "*",
      "Resource": "LogicalResourceId/ProductionDatabase"
    }
  ]
}

Drift Detection

To detect if resources have been changed outside CloudFormation:

# Detect drift on entire stack
aws cloudformation detect-stack-drift --stack-name MyStack

# Get drift details
aws cloudformation describe-stack-resource-drifts --stack-name MyStack

Custom Resources

Custom resources allow you to include resources not natively supported by CloudFormation:

Resources:
  MyCustomResource:
    Type: Custom::MyResource
    Properties:
      ServiceToken: !GetAtt MyLambdaFunction.Arn
      # Custom properties here

CloudFormation Template Examples

Basic EC2 Instance

Resources:
  MyEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      ImageId: ami-0abcdef1234567890
      SecurityGroups:
        - !Ref MySecurityGroup
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash -xe
          yum update -y
          yum install -y httpd
          systemctl start httpd
          systemctl enable httpd

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

VPC with Subnets

Resources:
  MyVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: MyVPC

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: Public Subnet 1

  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: 10.0.2.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      Tags:
        - Key: Name
          Value: Private Subnet 1

S3 Bucket with Website Configuration

Resources:
  MyS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      AccessControl: PublicRead
      WebsiteConfiguration:
        IndexDocument: index.html
        ErrorDocument: error.html
      LifecycleConfiguration:
        Rules:
          - Id: DeleteOldObjects
            Status: Enabled
            ExpirationInDays: 365

  BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref MyS3Bucket
      PolicyDocument:
        Statement:
          - Action: s3:GetObject
            Effect: Allow
            Resource: !Join ['', ['arn:aws:s3:::', !Ref MyS3Bucket, '/*']]
            Principal: '*'

Resources for Further Learning

Official Documentation

Tools

Learning Resources

Community Resources

Scroll to Top