AWS CloudFormation
LearningTree ยท AWS ยท DevOps

AWS CloudFormation โ€”
Infrastructure as Code

Define your entire AWS infrastructure in declarative templates. Version-controlled, repeatable, and automated โ€” from a single EC2 instance to a multi-region architecture.

โšก CloudFormation in 30 Seconds

  • Write your infrastructure in YAML/JSON templates โ€” EC2, VPC, RDS, IAM, everything
  • CloudFormation creates and manages resources as a stack โ€” a single unit
  • Update a stack by modifying the template โ€” CloudFormation figures out the diff
  • Delete a stack โ†’ all resources cleaned up automatically (no orphaned resources)
  • Free to use โ€” you only pay for the AWS resources created
01
Chapter One

What is CloudFormation

Introduction Introductory

AWS CloudFormation is an Infrastructure as Code (IaC) service that lets you define AWS resources in a text file (a template) and have CloudFormation create, update, and delete those resources for you.

๐Ÿ‘‰ Think of CloudFormation as: A blueprint that AWS reads to automatically build your infrastructure

Instead of clicking through the AWS Console or writing imperative scripts, you declare what you want โ€” and CloudFormation handles the how: dependency ordering, parallel creation, rollback on failure.

Why CloudFormation Exists Introductory
โš ๏ธ

Manual Infrastructure

  • Click-through console = undocumented
  • Hard to reproduce across environments
  • Drift between dev/staging/prod
  • No audit trail of changes
  • Cleanup is error-prone (orphaned resources)
โœ…

CloudFormation Solves

  • Infrastructure defined in code (YAML/JSON)
  • Identical environments with one template
  • Version-controlled in Git
  • Full audit trail via CloudTrail
  • Delete stack โ†’ all resources cleaned up
Core Concepts Core
ConceptWhat It IsAnalogy
TemplateA YAML/JSON file describing AWS resourcesThe blueprint / recipe
StackA running instance of a template โ€” the actual deployed resourcesThe built house
Change SetA preview of what will change before you apply an updateA renovation proposal
Stack SetDeploy one template across multiple accounts/regionsBuild the same house in many cities
Drift DetectionDetect if actual resources differ from the templateCheck if someone modified the house without the blueprint
How It Works Core
CloudFormation โ€” Template to Stack Flow
TEMPLATE YAML / JSON Version controlled upload CLOUDFORMATION Parses template Resolves dependencies Provisions resources creates STACK (live resources) EC2 VPC S3 RDS Lambda SNS
Declarative vs Imperative Core
ApproachHow It WorksExample
Imperative (scripts)You describe how โ€” step by stepAWS CLI: aws ec2 run-instances ...
Then aws ec2 create-security-group ...
Then aws ec2 authorize-security-group-ingress ...
Declarative (CloudFormation)You describe what โ€” the desired stateTemplate says: "I want an EC2 instance in a VPC with this SG"
CloudFormation works out the order and creates everything

๐Ÿ‘‰ Declarative wins because CloudFormation handles dependency resolution, parallelism, error handling, and rollback. You don't write "create VPC, then subnet, then route table, then EC2" โ€” you declare all of them and CloudFormation figures out the order.

CloudFormation vs Terraform In-Depth
FeatureCloudFormationTerraform
ProviderAWS-native (first-party)HashiCorp (third-party, multi-cloud)
LanguageYAML / JSONHCL (HashiCorp Configuration Language)
State managementManaged by AWS (no state file to maintain)You manage state file (S3 + DynamoDB for locking)
RollbackAutomatic on failureManual โ€” you must handle it
Drift detectionBuilt-interraform plan shows drift
Multi-cloudAWS onlyAWS, Azure, GCP, and 3,000+ providers
CostFreeFree (OSS) / Paid (Terraform Cloud)
Best forPure AWS shops, AWS exam contextMulti-cloud, large teams with diverse infra
Where CloudFormation Fits Introductory
DevOps Lifecycle โ€” Where IaC Sits
CODE App + Infra BUILD CI Pipeline PROVISION CloudFormation IaC deploys infra DEPLOY App to infra RUN Monitor
๐Ÿ‘‰ Key Takeaway

CloudFormation turns infrastructure into code โ€” declarative, version-controlled, and automatically provisioned. You describe what you want; CloudFormation handles how to build it.

02
Chapter Two

Templates & Stacks

Template Anatomy Core

A CloudFormation template is a YAML (or JSON) file with a defined structure. Here are the key sections โ€” only Resources is required:

SectionRequired?Purpose
AWSTemplateFormatVersionNoTemplate version date (always "2010-09-09" โ€” hasn't changed)
DescriptionNoHuman-readable description of the template
ParametersNoInput values provided at deploy time (instance type, env name, etc.)
MappingsNoStatic key-value lookups (e.g., AMI IDs per region)
ConditionsNoConditional resource creation (e.g., only create in prod)
ResourcesYes โœ…The AWS resources to create (EC2, S3, VPC, etc.)
OutputsNoValues exported after stack creation (URLs, IDs, ARNs)
Template Example Core

๐Ÿ“„ Simple CloudFormation Template

AWSTemplateFormatVersion: "2010-09-09"
Description: A simple web server stack

Parameters:
  InstanceType:
    Type: String
    Default: t3.micro
    AllowedValues: [t3.micro, t3.small, t3.medium]

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

  WebServer:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: ami-0abcdef1234567890
      SecurityGroupIds:
        - !Ref WebServerSG
      UserData:
        Fn::Base64: |
          #!/bin/bash
          yum install -y httpd
          systemctl start httpd

Outputs:
  PublicIP:
    Value: !GetAtt WebServer.PublicIp
    Description: Public IP of the web server

Key things to notice:

  • !Ref InstanceType โ€” references the parameter value provided at deploy time
  • !Ref WebServerSG โ€” references another resource (CloudFormation resolves the ID)
  • !GetAtt WebServer.PublicIp โ€” gets an attribute from a created resource
  • CloudFormation creates the Security Group before the EC2 instance (it resolves the dependency automatically)
Resources Section Core

The Resources section is the heart of every template. Each resource has a logical name, a type, and properties:

๐Ÿท๏ธ

Logical Name

Your chosen name within the template (e.g., WebServer). Used for !Ref and cross-references. Must be unique in the template.

๐Ÿ“ฆ

Type

The AWS resource type (e.g., AWS::EC2::Instance, AWS::S3::Bucket). CloudFormation supports 800+ resource types.

โš™๏ธ

Properties

Configuration for the resource โ€” instance type, VPC ID, tags, etc. Each resource type has its own set of required and optional properties.

Intrinsic Functions In-Depth

CloudFormation provides built-in functions for dynamic values, references, and logic within templates:

FunctionShort FormWhat It DoesExample
Ref!RefReturns the value of a parameter or the ID of a resource!Ref MyBucket โ†’ bucket name
Fn::GetAtt!GetAttGets a specific attribute from a resource!GetAtt MyELB.DNSName
Fn::Sub!SubString substitution with variables!Sub "arn:aws:s3:::${BucketName}"
Fn::Join!JoinJoins values with a delimiter!Join ["-", [prod, app, sg]] โ†’ prod-app-sg
Fn::Select!SelectSelect an item from a list by index!Select [0, !GetAZs ""] โ†’ first AZ
Fn::Split!SplitSplit a string into a list!Split [",", "a,b,c"] โ†’ [a, b, c]
Fn::ImportValue!ImportValueImport an exported output from another stack!ImportValue NetworkStack-VpcId
Fn::FindInMap!FindInMapLook up a value in the Mappings section!FindInMap [RegionMap, !Ref "AWS::Region", AMI]
Condition Functions!If, !Equals, !And, !Or, !NotConditional logic in templates!If [IsProd, m5.large, t3.micro]
Pseudo Parameters In-Depth

CloudFormation provides built-in pseudo parameters that resolve at deploy time โ€” you don't need to define them:

Pseudo ParameterReturnsCommon Use
AWS::AccountIdThe AWS account ID (e.g., 123456789012)Building ARNs, policies
AWS::RegionThe region the stack is deployed inRegion-specific AMI lookups
AWS::StackNameName of the current stackTagging resources, naming conventions
AWS::StackIdFull ARN of the stackUnique identifiers
AWS::NoValueRemoves a property when used with !IfConditional property inclusion
What is a Stack? Core

A stack is a single unit of deployment โ€” the collection of AWS resources created from one template. Stacks are the operational unit you interact with.

๐Ÿ“ฆ

Stack Properties

  • Has a unique name within a region
  • Tracks all resources it created
  • Has a lifecycle: CREATE โ†’ UPDATE โ†’ DELETE
  • Emits events for every resource operation
  • Supports tags (propagated to resources)
๐Ÿ”„

Stack Operations

  • Create โ€” provision all resources from template
  • Update โ€” modify resources (CloudFormation computes the diff)
  • Delete โ€” tear down all resources (clean up)
  • Detect Drift โ€” find manual changes made outside CloudFormation
Stack Lifecycle Core
Stack Lifecycle โ€” State Machine
CREATE_IN_PROGRESS CREATE_COMPLETE โœ“ CREATE_FAILED error ROLLBACK_COMPLETE auto rollback UPDATE_IN_PROGRESS update stack UPDATE_COMPLETE โœ“ DELETE_IN_PROGRESS delete stack DELETE_COMPLETE โœ— Create fails โ†’ auto-rollback. Update fails โ†’ roll back to previous state. Delete removes all resources.
Stack Creation โ€” What Happens Core
Stack Creation Flow
Template Template YAML uploaded
โ†’
CloudFormation CloudFormation Parse & validate
โ†’
Dependency Graph Dependency Graph Resolve order
โ†’
Stack Stack Created Resources live

During creation, CloudFormation:

  • Validates the template syntax and resource types
  • Builds a dependency graph โ€” knows VPC must exist before subnet, subnet before EC2
  • Creates resources in parallel where no dependency exists (faster)
  • Rolls back all changes if any resource fails to create (all-or-nothing)
  • Emits events for each resource (CREATE_IN_PROGRESS โ†’ CREATE_COMPLETE or CREATE_FAILED)
Update Behaviour In-Depth

When you update a stack, CloudFormation determines how each resource is affected. The impact depends on the property you changed:

Update TypeWhat HappensDowntime?Example
No interruptionResource updated in-place, stays runningNoneChanging EC2 tags, SG rules, Lambda code
Some interruptionResource updated in-place, brief disruptionBriefChanging EC2 instance type (requires stop/start)
ReplacementResource deleted and recreated (new physical ID)YesChanging EC2 AMI, RDS engine, VPC CIDR

๐Ÿ‘‰ Always use Change Sets before updating production stacks. A Change Set shows you exactly which resources will be modified, replaced, or deleted โ€” before you commit. Never blindly update a production stack.

Rollback Behaviour Core
โœ…

Create Rollback

  • If any resource fails during creation
  • All previously created resources are deleted
  • Stack status: ROLLBACK_COMPLETE
  • You must delete the stack and fix the template
๐Ÿ”„

Update Rollback

  • If any resource fails during update
  • All changes are reverted to previous state
  • Stack status: UPDATE_ROLLBACK_COMPLETE
  • Stack remains operational at the old configuration
Deletion & Retain Policy In-Depth

When you delete a stack, all resources are deleted by default. But you can override this with a DeletionPolicy:

DeletionPolicyBehaviourUse For
Delete (default)Resource is deleted when stack is deletedEphemeral resources (dev, test)
RetainResource is kept even after stack deletionDatabases, S3 buckets with data, critical resources
SnapshotCreates a snapshot before deleting (EBS, RDS, Redshift)Databases where you want a backup before cleanup

๐Ÿ‘‰ Always set DeletionPolicy: Retain on production databases and S3 buckets with important data. Without it, deleting the stack deletes your data permanently.

๐Ÿ‘‰ Key Takeaway

Templates define what to build (Resources, Parameters, Outputs). Stacks are the live deployment โ€” supporting create, update (with change sets), delete (with rollback), and drift detection. Use DeletionPolicy to protect critical data.

03
Chapter Three

Template Deep Dive

Parameters Core

Parameters make templates reusable by accepting input values at deploy time. Instead of hardcoding an instance type or environment name, you declare a parameter and let the user choose.

Parameters:
  Environment:
    Type: String
    Default: dev
    AllowedValues: [dev, staging, prod]
    Description: Deployment environment

  InstanceType:
    Type: String
    Default: t3.micro
    AllowedValues: [t3.micro, t3.small, t3.medium, t3.large]

  KeyPairName:
    Type: AWS::EC2::KeyPair::KeyName
    Description: Select an existing EC2 key pair
PropertyPurposeExample
TypeData type of the parameterString, Number, CommaDelimitedList, AWS::EC2::VPC::Id
DefaultValue used if none providedt3.micro
AllowedValuesRestrict to a list of valid options[dev, staging, prod]
AllowedPatternRegex validation"[a-zA-Z0-9]*"
MinLength / MaxLengthString length constraintsMinLength: 1
MinValue / MaxValueNumeric range constraintsMinValue: 1, MaxValue: 100
NoEchoMask the value (for passwords)NoEcho: true
ConstraintDescriptionCustom error message on validation fail"Must be a valid environment name"
๐Ÿท๏ธ

AWS-Specific Parameter Types

  • AWS::EC2::VPC::Id โ€” dropdown of VPCs
  • AWS::EC2::Subnet::Id โ€” dropdown of subnets
  • AWS::EC2::KeyPair::KeyName โ€” dropdown of key pairs
  • AWS::EC2::SecurityGroup::Id โ€” dropdown of SGs
  • AWS::SSM::Parameter::Value<String> โ€” from SSM Parameter Store
๐Ÿ’ก

Best Practices

  • Use AllowedValues to prevent invalid inputs
  • Use Default so dev deploys need zero input
  • Use NoEcho: true for passwords/secrets
  • Use SSM parameter types to read live values from Parameter Store
  • Limit parameters โ€” too many makes templates hard to use
Mappings Core

Mappings are static lookup tables in the template โ€” hardcoded key-value pairs used to select values based on conditions like region or environment. Unlike parameters, mappings are fixed at template authoring time.

Mappings:
  RegionAMI:
    us-east-1:
      HVM64: ami-0abcdef1111111111
    eu-west-1:
      HVM64: ami-0abcdef2222222222
    ap-southeast-1:
      HVM64: ami-0abcdef3333333333

Resources:
  WebServer:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !FindInMap [RegionAMI, !Ref "AWS::Region", HVM64]

The !FindInMap function takes three arguments: map name, first-level key, second-level key. This pattern is most commonly used for region-specific AMI IDs.

Conditions In-Depth

Conditions let you create resources or set properties only when certain criteria are met โ€” typically based on parameter values.

Conditions:
  IsProd: !Equals [!Ref Environment, prod]
  CreateReadReplica: !And
    - !Equals [!Ref Environment, prod]
    - !Equals [!Ref EnableReplica, "true"]

Resources:
  ProdAlarm:
    Type: AWS::CloudWatch::Alarm
    Condition: IsProd          # Only created if Environment=prod
    Properties:
      AlarmName: HighCPU
      ...
Condition FunctionPurposeExample
!EqualsTrue if two values are equal!Equals [!Ref Env, prod]
!IfReturns one of two values based on a condition!If [IsProd, m5.large, t3.micro]
!NotNegates a condition!Not [!Equals [!Ref Env, dev]]
!AndTrue if ALL conditions are true!And [Condition: IsProd, Condition: HasDB]
!OrTrue if ANY condition is true!Or [Condition: IsProd, Condition: IsStaging]
DependsOn In-Depth

CloudFormation automatically resolves dependencies when you use !Ref or !GetAtt. But sometimes you need to explicitly declare a dependency that CloudFormation cannot infer:

โœ…

Automatic (No DependsOn Needed)

  • !Ref WebServerSG in an EC2 resource โ†’ CloudFormation knows to create the SG first
  • !GetAtt MyDB.Endpoint.Address โ†’ DB created before the resource referencing it
  • Any !Ref or !GetAtt creates an implicit dependency
๐Ÿ”—

Explicit DependsOn Required

  • Resource depends on another but doesn't reference it
  • Example: EC2 instance needs an IGW attachment to exist (but doesn't !Ref it)
  • RDS instance depends on a VPC gateway attachment
  • Lambda depends on a log group being created first
Resources:
  IGWAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref MyVPC
      InternetGatewayId: !Ref MyIGW

  WebServer:
    Type: AWS::EC2::Instance
    DependsOn: IGWAttachment     # Explicit โ€” wait for IGW attachment
    Properties:
      SubnetId: !Ref PublicSubnet
      ...
Outputs & Cross-Stack References In-Depth

Outputs export values from a stack โ€” making them visible in the console and importable by other stacks. This is how you build multi-stack architectures.

# Stack A โ€” Network Stack
Outputs:
  VpcId:
    Value: !Ref MyVPC
    Export:
      Name: NetworkStack-VpcId    # Globally unique export name

# Stack B โ€” App Stack (imports from Stack A)
Resources:
  AppServer:
    Type: AWS::EC2::Instance
    Properties:
      SubnetId: !ImportValue NetworkStack-SubnetId
Cross-Stack References โ€” Export & Import
NETWORK STACK VPC ยท Subnets ยท IGW Route Tables ยท NAT Export: VpcId, SubnetId !ImportValue APP STACK EC2 ยท ALB ยท ASG Security Groups Import: VpcId DB STACK RDS ยท Aurora ElastiCache Import: SubnetId Each stack has its own lifecycle โ€” update network without touching app or DB
Nested Stacks In-Depth

Nested stacks let you compose templates from reusable child templates. A parent template references child templates stored in S3. Each child becomes a resource of type AWS::CloudFormation::Stack.

๐Ÿงฉ

When to Use Nested Stacks

  • Reuse common components (VPC, SG, IAM roles)
  • Break large templates into manageable pieces
  • Share a standard VPC template across teams
  • Overcome the 500-resource limit per stack
โš–๏ธ

Nested vs Cross-Stack

  • Nested: Parent manages child lifecycle (coupled)
  • Cross-Stack: Independent stacks linked via exports (decoupled)
  • Use nested for tightly coupled components
  • Use cross-stack for shared infrastructure (VPC, DNS)
Nested vs Cross-Stack Comparison In-Depth
FeatureNested StacksCross-Stack References
LifecycleChild managed by parent (create/update/delete together)Independent stacks, independent lifecycles
CouplingTight โ€” child is a resource in the parentLoose โ€” only linked via exported values
Reuse patternTemplate reuse (same child template in many parents)Value sharing (one stack exports, another imports)
Update impactUpdating parent can trigger child updatesUpdating exporter doesn't touch importer
Deletion orderParent handles child deletion automaticallyMust delete importers before exporters
Best forComponent reuse (standard VPC module)Shared infra across teams/services
๐Ÿ‘‰ Key Takeaway

Parameters make templates reusable, Mappings provide static lookups (AMI per region), Conditions enable environment-specific resources, DependsOn handles non-obvious ordering, and Outputs + ImportValue enable multi-stack architectures. Use nested stacks for component reuse; use cross-stack references for shared infrastructure.

04
Chapter Four

Stack Operations

Change Sets Core

A Change Set is a preview of proposed changes before they are applied to a stack. It shows exactly which resources will be added, modified, or replaced โ€” without actually making any changes.

Change Set Workflow
MODIFIED TEMPLATE New version CREATE CHANGE SET No changes yet REVIEW Add: 2 resources Modify: 1 ยท Replace: 1 Remove: 0 EXECUTE Apply now or DELETE Discard Change Sets are safe โ€” creating one makes ZERO changes to your stack
โœ…

What Change Sets Show

  • Which resources will be Added
  • Which will be Modified (in-place)
  • Which will be Replaced (deleted + recreated)
  • Which will be Removed
  • Whether replacement will cause data loss
โš ๏ธ

What Change Sets Don't Show

  • Whether the update will succeed (permissions, limits)
  • Downstream impact on dependents
  • Cost impact of changes
  • Application-level impact (app downtime)
  • Still validate your changes in staging first!

๐Ÿ‘‰ Always use Change Sets in production. Direct update-stack applies immediately with no preview. Change Sets give you a safety net โ€” review, approve, then execute (or discard).

Stack Policies In-Depth

A Stack Policy is a JSON document that protects specific resources from unintended updates. Once applied, CloudFormation denies updates to protected resources unless you explicitly override.

๐Ÿ›ก๏ธ

How Stack Policies Work

  • Attached to a stack (one policy per stack)
  • Default: all updates allowed (no policy)
  • Once applied: cannot be removed, only replaced
  • Deny by default โ€” then whitelist what's allowed
  • Override temporarily during specific updates
๐ŸŽฏ

Common Use Case

  • Protect production RDS from accidental replacement
  • Protect S3 buckets with critical data
  • Allow updates to EC2/Lambda but block database changes
  • Prevent accidental deletion of IAM roles
Drift Detection Core

Drift occurs when the actual state of a resource differs from what CloudFormation expects (the template). Someone manually changed a Security Group rule, resized an instance, or modified a bucket policy outside of CloudFormation.

Drift Detection โ€” How It Works
EXPECTED STATE Template says: InstanceType: t3.micro SG: port 80 open Tags: Env=prod vs ACTUAL STATE AWS reality: InstanceType: t3.large โš ๏ธ SG: port 22 added โš ๏ธ Tags: Env=prod โœ“ DRIFT DETECTED 2 properties drifted Status: DRIFTED Action: fix or import Fix drift: update the template to match reality, or re-apply the template to restore expected state
Drift StatusMeaning
IN_SYNCResource matches the template โ€” no drift
DRIFTEDOne or more properties differ from template
NOT_CHECKEDDrift detection hasn't been run on this resource
DELETEDResource was deleted outside of CloudFormation
Stack Sets In-Depth

Stack Sets let you deploy a single template across multiple AWS accounts and regions with one operation. Essential for organisations using AWS Organizations.

Stack Sets โ€” One Template, Many Accounts & Regions
ADMIN ACCOUNT Stack Set created Template + config Single source of truth Account: Dev (us-east-1) Stack Instance โ†’ resources Account: Prod (us-east-1) Stack Instance โ†’ resources Account: Prod (eu-west-1) Stack Instance โ†’ resources IDENTICAL RESOURCES โœ“ CloudTrail enabled โœ“ Config rules deployed โœ“ GuardDuty enabled โœ“ IAM password policy โœ“ S3 block public access Same baseline in every account & region
๐Ÿข

Deployment Targets

  • Specific account IDs
  • All accounts in an OU
  • All accounts in the org
  • Specific regions per account
โš™๏ธ

Operation Settings

  • Max concurrent โ€” how many accounts at once
  • Failure tolerance โ€” how many can fail before stopping
  • Region order โ€” sequential or parallel
  • Automatic deployment for new accounts in OU
๐ŸŽฏ

Common Use Cases

  • Security baseline across all accounts
  • Enable CloudTrail/Config everywhere
  • Deploy IAM roles/policies org-wide
  • Compliance guardrails (Control Tower uses Stack Sets)
Termination Protection Core

Termination protection prevents accidental stack deletion. When enabled, any delete-stack call is rejected until protection is explicitly disabled.

๐Ÿ”’

Enable For

  • Production stacks
  • Stacks with databases or persistent data
  • Shared infrastructure stacks (VPC, IAM)
  • Any stack where accidental deletion = disaster
๐Ÿ“

How to Enable

  • At creation: --enable-termination-protection
  • After creation: update-termination-protection
  • Console: Stack settings โ†’ Termination protection
  • Disable first โ†’ then delete (deliberate two-step)
Import Existing Resources In-Depth

CloudFormation can import existing AWS resources (created manually or by other tools) into a stack โ€” without recreating them. This lets you bring unmanaged resources under IaC control.

StepAction
1Add the resource to your template with the correct type and properties
2Add a DeletionPolicy: Retain (required for import)
3Run create-change-set --change-set-type IMPORT with the resource identifier
4Review the change set and execute
5Resource is now managed by CloudFormation

๐Ÿ‘‰ Resource import is powerful for brownfield environments โ€” you don't need to tear down and rebuild existing infrastructure. Import it, and CloudFormation manages it going forward.

Stack Operations Summary Core
OperationPurposeKey Behaviour
Create StackDeploy new infrastructureAll-or-nothing; auto-rollback on failure
Update StackModify existing resourcesUse Change Sets first; rollback on failure
Delete StackTear down all resourcesRespects DeletionPolicy (Retain/Snapshot)
Change SetPreview changes before applyingSafe โ€” makes zero changes until executed
Drift DetectionFind manual/out-of-band changesCompares template vs actual state
Stack SetsDeploy across accounts/regionsSingle template, many stack instances
ImportBring existing resources into a stackNo recreation; requires DeletionPolicy: Retain
Termination ProtectionPrevent accidental deletionMust be explicitly disabled before delete
๐Ÿ‘‰ Key Takeaway

Change Sets preview updates safely. Stack Policies protect critical resources. Drift Detection catches manual changes. Stack Sets deploy across multi-account/multi-region. Termination Protection prevents accidental deletion. Resource Import brings existing infrastructure under IaC control.

05
Chapter Five

Advanced Features

cfn-init โ€” Instance Configuration In-Depth

cfn-init is CloudFormation's built-in configuration management tool. It runs on an EC2 instance at launch time and reads configuration instructions from the template's AWS::CloudFormation::Init metadata โ€” installing packages, writing files, starting services, and more.

๐Ÿ“ฆ

packages

Install software via yum, apt, pip, or rpm. E.g., install Apache, Node.js, or Python packages.

๐Ÿ“„

files

Write config files to disk with specific content, permissions, and ownership. E.g., write /etc/httpd/conf/httpd.conf.

โš™๏ธ

services

Enable and start system services. Restart them when specific files or packages change. E.g., auto-restart httpd on config change.

๐Ÿ”ง

commands

Run arbitrary shell commands in order. E.g., run migrations, set permissions, download artifacts from S3.

๐Ÿ‘ฅ

groups & users

Create Linux groups and users on the instance. E.g., create an appuser with specific UID/GID.

๐Ÿ“

sources

Download and extract archives (tar, zip) from URLs. E.g., pull app bundle from S3 and extract to /var/www.

cfn-init vs User Data In-Depth
FeatureUser Data (bash script)cfn-init
FormatShell script (imperative)Declarative metadata in template
Idempotent?No โ€” runs once, you manage idempotencyYes โ€” desired-state config
Service restartsManual handlingAuto-restart on file/package changes
Config setsNo conceptGroup configs into ordered sets
Error handlingCheck exit codes manuallyReports success/failure to CloudFormation
Best forSimple installs, quick scriptsComplex multi-step server configuration
cfn-signal & CreationPolicy In-Depth

cfn-signal tells CloudFormation whether an instance successfully completed configuration. Without it, CloudFormation marks an EC2 instance as CREATE_COMPLETE the moment it launches โ€” even if cfn-init hasn't finished or failed.

cfn-init + cfn-signal โ€” Coordinated Bootstrap
CFN creates EC2 instance cfn-init Install packages Write configs Start services App starts Health check passes cfn-signal Sends SUCCESS to CloudFormation (or FAILURE) CREATE COMPLETE โœ“ Only after signal Without cfn-signal, CFN marks instance complete immediately โ€” even if cfn-init hasn't finished
๐Ÿ“ก

CreationPolicy

  • Attached to the EC2 or ASG resource in the template
  • Tells CloudFormation: "wait for N signals within timeout"
  • If signals not received โ†’ CREATE_FAILED โ†’ rollback
  • For ASGs: wait for MinSuccessfulInstancesPercent signals
โฑ๏ธ

WaitCondition (Legacy)

  • Older mechanism โ€” same idea as CreationPolicy
  • Uses a separate WaitConditionHandle resource
  • Can receive signals from external sources (not just the instance)
  • Prefer CreationPolicy for EC2/ASG; use WaitCondition for external coordination
Custom Resources In-Depth

Custom Resources let you extend CloudFormation beyond its built-in resource types. They invoke a Lambda function (or SNS topic) during stack create/update/delete โ€” allowing you to do anything that AWS APIs can do.

Custom Resource โ€” Lambda-Backed Flow
CloudFormation invoke Lambda Function action Custom Action API call, DNS, cleanup third-party service response CFN receives SUCCESS / FAILED + output data Lambda must send response to pre-signed S3 URL โ€” CFN waits until it receives it (or times out)
๐ŸŽฏ

Common Use Cases

  • Populate an S3 bucket at stack creation (upload initial data)
  • Create DNS records in Route 53 hosted zones
  • Empty an S3 bucket before deletion (required โ€” CFN can't delete non-empty buckets)
  • Call external APIs (Datadog, PagerDuty, Slack notifications)
  • Look up the latest AMI ID dynamically
  • Provision resources in services not yet supported by CFN
โš ๏ธ

Gotchas

  • Lambda must send a response to the S3 presigned URL โ€” or CFN hangs
  • Handle all three events: Create, Update, Delete
  • If Lambda fails without sending response โ†’ stack stuck for 1 hour (timeout)
  • Always include error handling and logging
  • Prefer Custom::* type over AWS::CloudFormation::CustomResource
CloudFormation Helper Scripts Core
ScriptPurposeWhen to Use
cfn-initRead metadata and configure the instance (packages, files, services)Complex instance configuration instead of User Data scripts
cfn-signalSignal CloudFormation that configuration is complete (or failed)With CreationPolicy โ€” so CFN waits for app readiness
cfn-hupDaemon that detects metadata changes and re-runs cfn-initWhen you want instances to auto-update on stack update
cfn-get-metadataRetrieve metadata from a resource in the templateDebugging โ€” inspect what metadata a resource has

๐Ÿ‘‰ cfn-hup is the key to updating running instances. Without it, updating the Init metadata in a template only affects new instances. cfn-hup runs as a daemon, polls for metadata changes, and re-runs cfn-init โ€” so existing instances pick up updates.

CloudFormation Registry & Modules In-Depth
๐Ÿ“‹

CloudFormation Registry

  • Catalogue of resource types, modules, and hooks
  • Includes AWS resources + third-party resources
  • E.g., Datadog::Monitors::Monitor, MongoDB::Atlas::Cluster
  • Register your own custom types with schemas and handlers
  • Versioned, discoverable, and type-safe
๐Ÿงฉ

CloudFormation Modules

  • Reusable template fragments registered in the Registry
  • Package common patterns (e.g., "standard VPC" module)
  • Consumed as MODULE::* resource types in templates
  • Hides complexity โ€” users specify simple properties
  • Versioned and shareable across the organisation
๐Ÿ‘‰ Key Takeaway

cfn-init provides declarative instance configuration (packages, files, services); cfn-signal + CreationPolicy ensure CloudFormation waits for app readiness. Custom Resources extend CloudFormation via Lambda to handle any API call. cfn-hup keeps running instances in sync with template changes. The Registry enables third-party resources and reusable Modules.

06
Chapter Six

Patterns & Best Practices

Multi-Stack Architecture Core

In production, you should never put everything in one giant stack. Split your infrastructure into layered, loosely coupled stacks with independent lifecycles.

Recommended Multi-Stack Architecture
NETWORK STACK VPC ยท Subnets ยท IGW ยท NAT ยท Route Tables Exports: VpcId, PublicSubnetIds, PrivateSubnetIds SECURITY STACK Security Groups ยท IAM Roles ยท KMS Keys ยท WAF Exports: SGIds, RoleARNs, KMSKeyId DATA STACK RDS ยท ElastiCache ยท S3 Buckets APP STACK ALB ยท ASG ยท EC2 / ECS ยท Lambda MONITORING STACK โ€” CloudWatch Alarms ยท Dashboards ยท SNS Topics ยท Log Groups
โœ…

Why Split Stacks

  • Independent lifecycles โ€” update app without touching VPC
  • Blast radius โ€” a failed app stack update won't break networking
  • Team ownership โ€” network team owns VPC stack, app team owns app stack
  • Reuse โ€” same VPC stack for dev/staging/prod
  • Limits โ€” avoid the 500-resource-per-stack limit
โš ๏ธ

Anti-Patterns to Avoid

  • God stack โ€” everything in one template (fragile, slow updates)
  • Circular exports โ€” Stack A imports from B which imports from A
  • Hardcoded IDs โ€” use !ImportValue or SSM parameters instead
  • No DeletionPolicy on databases โ€” stack deletion = data loss
  • No Change Sets in production โ€” blind updates are dangerous
CI/CD Integration Core

CloudFormation integrates naturally into CI/CD pipelines for automated infrastructure deployment:

CloudFormation in a CI/CD Pipeline
Git Push Template Pipeline CodePipeline Validate cfn-lint + test Change Set Review preview Approve Manual Deploy Execute CodePipeline has a native CloudFormation deploy action โ€” creates Change Sets and executes them automatically
Template Best Practices Core
๐Ÿ“‹

Template Hygiene

  • Use YAML over JSON (more readable, supports comments)
  • Use Parameters โ€” never hardcode account IDs, AMIs, or env names
  • Use Mappings for region-specific values (AMI per region)
  • Use Conditions for env-specific resources (alarms only in prod)
  • Validate with cfn-lint before deploying
  • Store templates in Git โ€” full change history
๐Ÿ›ก๏ธ

Safety & Protection

  • Enable Termination Protection on all prod stacks
  • Set DeletionPolicy: Retain on databases and S3 buckets
  • Use Stack Policies to protect critical resources from update
  • Always use Change Sets before updating production
  • Run Drift Detection regularly (weekly or in CI)
  • Tag all stacks โ€” Environment, Team, CostCenter
Common Mistakes Introductory
MistakeWhy It's BadFix
Everything in one stackSlow updates, large blast radius, 500-resource limitSplit into network/security/data/app stacks
No DeletionPolicy on RDSDelete stack = delete database = data goneDeletionPolicy: Snapshot or Retain
Direct update without Change SetSurprise replacements can delete dataAlways create + review Change Set first
Hardcoded valuesTemplate only works in one region/accountUse Parameters, Mappings, and !Ref AWS::Region
No cfn-signal on EC2CFN marks instance complete before app startsAdd CreationPolicy + cfn-signal
Manual changes after deploymentDrift โ€” template no longer matches realityAll changes through CloudFormation; run drift detection
Not using SSM for secretsSecrets in plain text ParametersUse AWS::SSM::Parameter::Value or Secrets Manager dynamic references
CloudFormation Limits Core
LimitValueWorkaround
Resources per stack500Split into multiple stacks (nested or cross-stack)
Parameters per template200Use SSM parameters or Mappings instead
Outputs per template200Export only what's needed; use SSM for others
Template body size (inline)51,200 bytesUpload to S3 (up to 1 MB from S3)
Stacks per account per region2,000Request limit increase or consolidate
Exports per account per region200Use SSM parameters for sharing beyond 200

CloudFormation โ€” Complete Summary

  • Templates โ€” YAML/JSON files declaring infrastructure. Sections: Parameters, Mappings, Conditions, Resources (required), Outputs.
  • Stacks โ€” Live deployment of a template. Lifecycle: Create โ†’ Update โ†’ Delete. Auto-rollback on failure.
  • Intrinsic Functions โ€” !Ref, !GetAtt, !Sub, !FindInMap, !If, !ImportValue for dynamic templates.
  • Change Sets โ€” Preview updates before applying. Shows adds, modifies, replacements, removals.
  • Cross-Stack References โ€” Export/ImportValue for decoupled multi-stack architectures.
  • Stack Sets โ€” Deploy one template across multiple accounts and regions (org-wide governance).
  • Drift Detection โ€” Detect manual changes that diverge from the template.
  • cfn-init + cfn-signal โ€” Declarative instance config + readiness signalling to CloudFormation.
  • Custom Resources โ€” Lambda-backed extension for anything CloudFormation doesn't natively support.
  • Best Practices โ€” Split stacks, use Change Sets, enable termination protection, DeletionPolicy on data, CI/CD pipeline integration.
๐Ÿ‘‰ Key Takeaway

CloudFormation is the backbone of AWS infrastructure automation. Split infrastructure into layered stacks, protect production with Change Sets + Termination Protection + DeletionPolicy, integrate into CI/CD pipelines, and treat infrastructure with the same discipline as application code โ€” versioned, reviewed, and tested.