Part of my AWS learning journey — transitioning from Systems Engineer to Cloud/DevOps. CloudFormation is the foundation of infrastructure automation on AWS — the point where "clicking in the console" becomes "code that can be reviewed, versioned, and reproduced."
📋 Topics Covered
| # | Topic | Type |
|---|---|---|
| 1 | What is IaC and Why It Exists | Concept + Interview |
| 2 | IaC Benefits | Concept |
| 3 | What is CloudFormation | Concept + Interview |
| 4 | How CloudFormation Works in the Backend | Concept + Interview |
| 5 | CloudFormation Template Structure — All Sections with Limits | Concept + Lab |
| 6 | Template Section Plain-English Explanations | Concept |
| 7 | Template vs Stack — The Distinction | Concept + Interview |
| 8 | CloudFormation Building Blocks | Concept + Cert |
| 9 | YAML Basics for CF Templates | Concept + Lab |
| 10 | CF Parameters | Concept + Lab |
| 11 | CF Rules | Concept + Cert |
| 12 | CF Mappings | Concept + Cert |
| 13 | CF Outputs | Concept + Lab |
| 14 | CF Conditions | Concept + Cert |
| 15 | CF Intrinsic Functions | Concept + Cert |
| 16 | CF Service Roles | Concept + Interview |
| 17 | CF Stack Policies and Deletion Policies | Concept + Interview |
| 18 | CF Change Sets | Concept + Lab |
| 19 | CF Stack Sets | Concept + DevOps |
| 20 | Lab — Full Build-Up with Real Failures | Lab |
| 21 | Interview Questions | Interview |
| 22 | Assignment | Practice |
What is IaC and Why It Exists
Before IaC, infrastructure was managed manually — someone SSH'd into servers, clicked through console UIs, and hoped they remembered what they changed. When that person left, the knowledge went with them. When you needed three identical environments, you clicked through the console three times and hoped for no mistakes.
IaC (Infrastructure as Code) is the practice of defining and managing infrastructure through code or configuration files — so infrastructure can be created, changed, versioned, and reproduced automatically.
Instead of clicking "create EC2 instance" in the console, you write a file that says "I want an EC2 instance with these specs." You give that file to a tool. The tool creates the instance. The file goes into Git. Next time you need the same instance, you run the same file. Exact same infrastructure, zero manual steps.
The same principles that apply to application code now apply to infrastructure:
- Version control — track every change with a commit message
- Code review — a colleague reviews infrastructure changes before they're applied
- CI/CD pipelines — infrastructure changes tested and deployed automatically
- Reproducibility — the same template produces identical infrastructure every time
- Documentation — the template is the documentation
IaC Benefits
| Benefit | What it means in practice |
|---|---|
| Reproducibility | Same template in any region or account → identical infrastructure |
| Version control | Every change tracked in Git — who changed what, when, and why |
| Auditability | Full history of infrastructure changes — essential for compliance |
| Automation | CI/CD pipelines deploy infrastructure changes without human intervention |
| Drift detection | Compare actual infrastructure against the template — catch unauthorized manual changes |
| Disaster recovery | Recreate entire infrastructure in a new region in minutes |
| Consistency | Dev, staging, prod built from the same template — no more "works on staging, broken in prod" |
What is CloudFormation
AWS CloudFormation is AWS's native IaC service. You write a template (YAML or JSON), upload it, and CloudFormation creates, updates, and manages all resources on your behalf.
Think of CloudFormation as a construction manager working from a blueprint. Your YAML/JSON template is the blueprint — it describes exactly how your AWS infrastructure should look. CloudFormation reads the blueprint, builds the infrastructure, and remembers what it built. When you change the blueprint, the construction manager doesn't demolish the entire building — they identify what changed and modify only the affected parts.
Why CloudFormation over clicking in the console:
- Console clicks are not reproducible — the exact sequence is never recorded
- Templates can be reviewed, approved, and audited
- Same template creates identical infrastructure across dev/staging/prod
- Changes can be previewed before applying via Change Sets
- Automatic rollback if something goes wrong during deployment
How CloudFormation Works in the Backend
Understanding this makes troubleshooting CloudFormation failures significantly easier. This is the exact flow from class — represented as a numbered sequence.
The entire backend flow:
[1] Parse + Validate: Reads your YAML/JSON, checks for syntax errors, validates that resource types and properties are correct.
[2] Transform Expansion: Expands any transforms — SAM shorthand, Includes, Language Extensions, Modules — into full CloudFormation resource definitions.
[3] Pre-deployment Validation: Checks whether the requested resources and configuration make sense before deployment begins. Validates IAM permissions and quota limits.
[4] Build Dependency Graph (DAG): Determines resource dependencies — what depends on what and what needs to happen first. Independent resources are flagged for parallel execution. Dependent resources are ordered correctly.
[5] Compute Change Set: Compares the current AWS state (stored in CloudFormation's transactional state store) with the new template to determine exactly what needs to change — Add, Modify, Remove, Replace.
[6] Evaluate Hooks / Guardrails: Checks predefined organizational/security rules before making changes. Example: verifying every S3 bucket has encryption enabled before creation proceeds.
[7] Parallel Execution (by DAG topological order): Independent resources are created/updated simultaneously. Dependent resources follow the required order. For each resource: Resource Provider handles the actual Create/Update/Delete API call. Then → Stabilization Loop — CloudFormation polls until the resource reaches its required ready state. A successful API call doesn't mean the resource is ready. Stabilization can take 20–90 minutes for some resources (RDS, ElasticSearch, etc.).
[8] Success or Failure:
- Success → State Committed: Everything reaches the desired state → stack becomes
CREATE_COMPLETEorUPDATE_COMPLETE- Failure → Rollback: CloudFormation attempts to undo the changes in reverse DAG order → returns the stack toward its previous stable state
🎯 Why this matters for troubleshooting: When a stack gets stuck at
CREATE_IN_PROGRESS, it's in the Stabilization Loop — waiting for a resource to become available. Check the Events tab — it shows which resource is waiting and why. When it fails, the error comes from the underlying AWS API call in the Resource Provider step.
CloudFormation Template Structure — All Sections with Limits
A CloudFormation template is a YAML or JSON file with the following structure. Every section has limits you should know for production and for the SAA-C03 exam.
AWSTemplateFormatVersion: "2010-09-09" # optional, but always write it
Description: "..." # max 1024 bytes
Metadata: {} # console UI hints, cfn-init config
Parameters: {} # max 200
Rules: {} # UNDER-USED — param validation logic
Mappings: {} # max 200 mappings, 200 attrs each
Conditions: {} # max 512
Transform: [] # macro/SAM expansion
Resources: {} # REQUIRED — max 500
Outputs: {} # max 200
Only Resources is required. Every other section is optional.
Template Section Plain-English Explanations
From class — the clearest way to remember what each section does:
| Section | Plain-English Question It Answers |
|---|---|
AWSTemplateFormatVersion |
What template format? |
Description |
What is this blueprint for? |
Metadata |
Extra blueprint information |
Parameters |
What choices should the person deploying provide? |
Rules |
Are those choices valid? |
Mappings |
Lookup table for predefined values |
Conditions |
Should this part be built or not? |
Transform |
Expand/process the blueprint |
Resources |
⭐ What actually needs to be built? |
Outputs |
What useful information should I give back after construction? |
Template vs Stack — The Distinction
Template: A YAML or JSON file — the blueprint. A text file. By itself, it creates nothing. Lives in Git, S3, or locally.
Stack: What CloudFormation creates when it executes a template. A group of AWS resources managed together as one unit. The stack tracks every resource it created, their state, and the template that generated them.
The same template creates multiple stacks:
webapp.yaml(one file in Git)
→ Stack:webapp-dev→ dev resources in dev account
→ Stack:webapp-staging→ staging resources in staging account
→ Stack:webapp-prod→ prod resources in prod account
Three environments, identical configuration, zero manual effort.
CloudFormation Building Blocks
SAM (Serverless Application Model)
Shorthand syntax for serverless — Lambda, API Gateway, DynamoDB — written in a simplified form. The
Transform: AWS::Serverless-2016-10-31macro expands SAM into full CloudFormation at deploy time. Instead of 50 lines to define a Lambda with its role and log group, SAM lets you write 10.
Include
Pulls content from another template file into the current one — splits large templates into focused, maintainable files.
Language Extensions
Adds extra syntax features — native string operations, length functions,
ToJsonString— reducing repetitive code and making templates more flexible.
Modules
Reusable infrastructure components used across multiple templates. Define a "standard VPC setup" once as a module — reference it in every team's template without repeating 200 lines.
YAML Basics for CF Templates
# Comment in YAML
key: value # String
number: 42 # Integer
boolean: true # Boolean
list: # List/Array
- item1
- item2
nested: # Nested object/map
key1: value1
key2: value2
multiline: | # Multi-line string (preserves newlines)
line one
line two
Indentation is everything in YAML. Unlike JSON (curly braces), YAML uses 2-space indentation to show nesting. One wrong indent fails the entire template.
CF Parameters
Parameters let you avoid hardcoding values — instead the person deploying provides them at stack creation or update time.
The same template creates a
t3.microin dev and ac5.2xlargein prod — just by passing different values. No template changes needed.
Parameters:
InstanceType:
Type: String
Default: t3.micro
AllowedValues:
- t3.micro
- t3.small
- t3.medium
- t3.large
Description: "EC2 instance type for the web server"
Environment:
Type: String
AllowedValues:
- dev
- staging
- prod
Description: "Deployment environment"
Parameter types:
| Type | Use for |
|---|---|
String |
Text values, names, identifiers |
Number |
Numeric values |
CommaDelimitedList |
Multiple strings |
AWS::EC2::KeyPair::KeyName |
Validates the key pair exists before deploy |
AWS::EC2::VPC::Id |
Validates the VPC ID exists before deploy |
AWS::EC2::Subnet::Id |
Validates the subnet ID exists before deploy |
AWS::SSM::Parameter::Value<String> |
Pulls value directly from SSM Parameter Store |
🎯 Interview tip: AWS-specific parameter types (like
AWS::EC2::VPC::Id) are validated before the stack starts deploying — an invalid VPC ID gets rejected immediately, not halfway through.
Limit: max 200 parameters per template.
CF Rules
Rules are the validation layer for Parameters — they ensure parameter combinations are valid, going beyond what AllowedValues alone can check.
AllowedValuescan restrict a single parameter to a fixed list. But what if you need: "when Environment isprod, InstanceType must not bet3.micro"? That cross-parameter logic is what Rules handle.
Rules:
ProdRequiresLargeInstance:
Assertions:
- Assert:
!Or
- !Not [!Equals [!Ref Environment, prod]]
- !Not [!Equals [!Ref InstanceType, t3.micro]]
AssertDescription: "Production environment cannot use t3.micro"
🎯 Note from class: Rules are marked as "UNDER-USED" in practice — most teams use Parameters with
AllowedValuesfor simple validation and rely on Conditions for conditional resource creation. But Rules are the correct tool when you need to validate that multiple parameter values make sense together.
CF Mappings
Mappings are lookup tables baked into your template. The classic use case — AMI IDs per region, so the person deploying doesn't need to know them.
Mappings:
RegionAMIMap:
ap-south-1:
AMI: ami-0abcdef1234567890
us-east-1:
AMI: ami-0987654321fedcba
eu-west-1:
AMI: ami-0a1b2c3d4e5f67890
Resources:
MyEC2:
Type: AWS::EC2::Instance
Properties:
ImageId: !FindInMap [RegionAMIMap, !Ref AWS::Region, AMI]
When deployed in Mumbai → uses Mumbai AMI automatically. The deployer doesn't touch AMI IDs.
Other uses: environment-specific instance sizes (prod gets t3.large, dev gets t3.micro), region-specific endpoint URLs.
Limit: max 200 mappings, 200 attributes each.
CF Outputs
Outputs are values CloudFormation surfaces after a stack is created — important resource identifiers made easy to find and reuse.
Outputs:
BucketName:
Description: "Name of the created S3 bucket"
Value: !Ref MyBucket
BucketARN:
Description: "ARN of the S3 bucket"
Value: !GetAtt MyBucket.Arn
Export:
Name: !Sub "${AWS::StackName}-BucketARN"
Three uses:
- Console visibility — after stack creation, Outputs appear in CloudFormation console. Easy to find the ALB DNS name or RDS endpoint without digging through service consoles.
-
Cross-stack references — one stack exports an Output, another imports it with
Fn::ImportValue. Networking stack exports VPC ID → all application stacks import it. - Automation — scripts query Outputs to get resource identifiers dynamically.
Limit: max 200 outputs per template.
CF Conditions
Conditions add boolean logic — create resources or set property values only when certain conditions are true.
Parameters:
Environment:
Type: String
AllowedValues: [dev, prod]
Conditions:
IsProduction: !Equals [!Ref Environment, prod]
Resources:
MyBucket:
Type: AWS::S3::Bucket
Properties:
VersioningConfiguration:
Status: !If [IsProduction, Enabled, Suspended]
ReadReplica:
Type: AWS::RDS::DBInstance
Condition: IsProduction # Only created when IsProduction is true
Properties:
# read replica config...
Condition functions:
| Function | What it does |
|---|---|
!Equals [a, b] |
True if a equals b |
!Not [condition] |
Inverts a condition |
!And [c1, c2] |
True if both are true |
!Or [c1, c2] |
True if either is true |
!If [condition, true_value, false_value] |
Conditional value |
Limit: max 512 conditions per template.
CF Intrinsic Functions
Built-in functions that build dynamic values, reference resources, and manipulate strings.
| Function | Short form | What it does |
|---|---|---|
Ref |
!Ref |
Default identifier of a resource or parameter value |
Fn::GetAtt |
!GetAtt |
Specific attribute of a resource (ARN, DNS name, IP) |
Fn::Sub |
!Sub |
String substitution — inserts variable values |
Fn::Join |
!Join |
Joins a list with a delimiter |
Fn::Select |
!Select |
Returns one item from a list by index |
Fn::FindInMap |
!FindInMap |
Looks up a value in a Mappings table |
Fn::If |
!If |
Returns one of two values based on a Condition |
Fn::ImportValue |
— | Imports an Output exported by another stack |
Fn::Base64 |
!Base64 |
Encodes string as Base64 (used for EC2 User Data) |
Fn::Split |
!Split |
Splits a string into a list |
!Ref vs !GetAtt — the key distinction:
!Ref MyBucket→ bucket name (the default identifier for S3)
!GetAtt MyBucket.Arn→ bucket ARN (a specific attribute)
!GetAtt MyInstance.PublicIp→ public IP of EC2 (a specific attribute)
Practical example:
Resources:
MyInstance:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref InstanceTypeParam # value from Parameter
ImageId: !FindInMap [AMIMap, !Ref AWS::Region, AMI] # from Mappings
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-webserver" # string substitution
UserData:
!Base64 |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
Outputs:
PublicIP:
Value: !GetAtt MyInstance.PublicIp
FullDNS:
Value: !Join [".", ["api", !Ref Environment, "tejascloud.com"]]
CF Service Roles
By default, CloudFormation uses your own IAM permissions to create resources. A Service Role is an IAM Role that CloudFormation assumes instead — decoupling what humans can do from what CloudFormation can do.
Scenario: A developer needs to deploy a stack that creates VPCs, security groups, and EC2 instances. You could give the developer those IAM permissions directly — but then they could also manually create those resources outside CloudFormation, bypassing governance.
With a Service Role: The developer has
cloudformation:CreateStackandiam:PassRoleonly. The Service Role hasec2:*,vpc:*,s3:*— whatever the stack needs. CloudFormation assumes the role and creates resources. The developer gets the infrastructure without direct access to the underlying services.🎯 Security benefit: Least privilege for humans, necessary permissions for automation. Humans can't bypass the CloudFormation process to create resources manually.
CF Stack Policies and Deletion Policies
Stack Policy
A JSON document attached to a stack that controls which resources can be updated or replaced during a stack update.
{
"Statement": [{
"Effect": "Deny",
"Action": "Update:Replace",
"Principal": "*",
"Resource": "LogicalResourceId/ProductionDatabase"
}]
}
This blocks Replace operations on the ProductionDatabase resource — even if a template change would normally require it. CloudFormation fails the update rather than replace the database.
Deletion Policy
Set on individual resources inside the template — controls what happens when the stack is deleted or the resource is removed from the template.
| Deletion Policy | What happens when stack is deleted |
|---|---|
Delete (default) |
Resource is deleted |
Retain |
Resource stays, CloudFormation stops managing it |
Snapshot |
AWS takes a backup before deleting (RDS, EBS, Redshift) |
Resources:
MyDatabase:
Type: AWS::RDS::DBInstance
DeletionPolicy: Snapshot # backup before delete
Properties: {}
MyBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain # keep the bucket, just stop managing it
Properties: {}
🎯 Production rule: Always
DeletionPolicy: Snapshoton RDS. AlwaysDeletionPolicy: Retainon S3 buckets with important data. Losing a production database because of the defaultDeletepolicy is a real and painful mistake.
CF Change Sets
A Change Set is a preview of what CloudFormation will do before it actually does it — shows every resource action: Add, Modify, Remove, Replace.
A
Replaceaction means the resource is deleted and recreated — downtime for databases, EC2 instances, etc. A Change Set lets you catch this before it happens.
The Change Set workflow:
Modify your YAML template → Upload new template → Create Change Set → CloudFormation computes the diff → Review every proposed change → If correct: Execute → CloudFormation applies → If risky or wrong: Delete the Change Set → nothing applied, stack untouched.
When to always use Change Sets: Before updating any production stack — catching a Replace before it runs is the difference between planned maintenance and an unplanned outage.
CF Stack Sets
Deploys the same CloudFormation stack across multiple AWS accounts and/or regions in a single operation.
Without Stack Sets: log into 10 accounts, switch to 3 regions in each, deploy 30 times manually.
With Stack Sets: define target accounts and regions once → CloudFormation deploys to all 30 in parallel.
Common uses: security baseline (CloudTrail, Config, GuardDuty) to every account, centralized logging in every region, standard networking across all accounts.
Two modes:
| Mode | How targets are defined |
|---|---|
| Self-managed | You explicitly list account IDs and regions |
| Service-managed (AWS Organizations) | Auto-deploys to all accounts in an OU — new accounts added to the OU automatically get the stack |
Stack Instance = one deployed stack in one specific account + region combination.
🧪 Lab — Full Build-Up with Real Failures
This is the complete lab sequence from class — building a full networking + EC2 stack resource by resource using Change Sets. The failures are included because they're part of what makes CloudFormation real — and knowing how to fix them is the skill.
Overall Lab Flow
YAML Blueprint → Parameters → VPC → Subnet → Internet Gateway → Gateway Attachment → Route Table → Security Group → Key Pair Parameter → EC2 → Dependencies via
!Ref→ Change Sets → Execute → Failures → Fix Template/Parameter → New Change Set → Execute → Final Infrastructure ✅
Step-by-Step Lab — Exact Sequence
Start: Create VPC + CIDR
Create Stack → initial template with just VPC and CIDR →
CREATE_COMPLETE✅
Add Subnet via Change Set
Modify template — add Subnet resource referencing VPC via
!Ref→ Create Change Set → Execute Change Set
❌ FAILED: Invalid Availability Zone — AZ name in template was wrong
Fix AZ in template → Create New Change Set → Execute Change Set
Subnet Created ✅
Add Internet Gateway
Modify template — add
AWS::EC2::InternetGateway, addAWS::EC2::VPCGatewayAttachmentusing!Ref VPCand!Ref IGW→ Create Change Set → Execute
MyInternetGateway Created ✅
AttachGateway Created ✅
Internet Gateway Attached to VPC ✅
Add Route Table
Modify template — add
AWS::EC2::RouteTable, add Route with destination0.0.0.0/0→ IGW, add Subnet Route Table Association → Create Change Set → Execute
Route Table Created + Associated ✅
Add Security Group
Modify template — add
AWS::EC2::SecurityGroupwith inbound rules (SSH 22, HTTP 80) → Create Change Set → Execute
Security Group Created ✅
Add Key Pair as Parameter + Create EC2
Modify template — add KeyPair Parameter (
Type: AWS::EC2::KeyPair::KeyName), add EC2 instance referencing AMI from Mappings, SG from!Ref, subnet from!Ref, key pair from!Ref KeyPairParam→ Create Change Set → Execute
❌ FAILED: Invalid/Non-existent Key Pair — wrong key pair name entered
Correct Key Pair Parameter → Create New Change Set → Execute Change Set
EC2 Created ✅
What the Lab Teaches
These failures are not bugs in the process — they're the lesson:
Invalid AZ failure: Template contained a hardcoded AZ that doesn't exist in the target region. Fix: use a Parameter for AZ name, or use
!Select [0, !GetAZs !Ref AWS::Region]to dynamically pick the first available AZ.Invalid Key Pair failure: AWS-specific parameter types (
AWS::EC2::KeyPair::KeyName) validate that the key pair exists in the account — if you type a name that doesn't exist, it fails at parameter validation before any resource is created. Fix: enter the exact name of a key pair that exists in your account.
The Change Set → Execute → Fail → Fix → New Change Set → Execute cycle is normal production CloudFormation workflow. The key is that failures don't leave your infrastructure in an unknown state — CloudFormation's rollback mechanism returns you to the last stable state.
Final Template Structure (Everything Together)
AWSTemplateFormatVersion: "2010-09-09"
Description: "VPC + EC2 networking stack"
Parameters:
KeyPairName:
Type: AWS::EC2::KeyPair::KeyName
Description: "Name of an existing EC2 key pair"
AvailabilityZone:
Type: AWS::EC2::AvailabilityZone::Name
Description: "AZ to deploy the subnet in"
Mappings:
RegionAMI:
ap-south-1:
AMI: ami-0f5ee92e2d63afc18
us-east-1:
AMI: ami-0abcdef1234567890
Resources:
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: "10.0.0.0/16"
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-VPC"
MySubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: "10.0.1.0/24"
AvailabilityZone: !Ref AvailabilityZone
MapPublicIpOnLaunch: true
MyIGW:
Type: AWS::EC2::InternetGateway
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref MyVPC
InternetGatewayId: !Ref MyIGW
MyRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MyVPC
PublicRoute:
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref MyRouteTable
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: !Ref MyIGW
SubnetRouteTableAssoc:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref MySubnet
RouteTableId: !Ref MyRouteTable
MySecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "Allow SSH and HTTP"
VpcId: !Ref MyVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: "0.0.0.0/0"
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: "0.0.0.0/0"
MyEC2:
Type: AWS::EC2::Instance
Properties:
InstanceType: t2.micro
KeyName: !Ref KeyPairName
ImageId: !FindInMap [RegionAMI, !Ref AWS::Region, AMI]
SubnetId: !Ref MySubnet
SecurityGroupIds:
- !Ref MySecurityGroup
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-WebServer"
Outputs:
InstancePublicIP:
Description: "Public IP of the EC2 instance"
Value: !GetAtt MyEC2.PublicIp
VPCID:
Description: "VPC ID"
Value: !Ref MyVPC
Useful Pseudo Parameters
Available automatically — no declaration needed.
| Pseudo Parameter | Value |
|---|---|
!Ref AWS::Region |
Current region (e.g., ap-south-1) |
!Ref AWS::AccountId |
Current AWS account ID |
!Ref AWS::StackName |
Name of the current stack |
!Ref AWS::StackId |
Full ARN of the current stack |
!Ref AWS::NoValue |
Removes a property (used in Conditions) |
⚡ Quick Revision
IaC
- Define infrastructure as code → version, review, reproduce, automate
- Template is the blueprint. Stack is the deployed infrastructure.
- Same template → multiple stacks → identical environments
Template Structure (with limits)
-
AWSTemplateFormatVersion→ format version, always"2010-09-09" -
Metadata→ UI hints, cfn-init config -
Parameters→ max 200, user input at deploy time -
Rules→ cross-parameter validation logic (under-used but important) -
Mappings→ max 200 mappings × 200 attrs each, lookup tables -
Conditions→ max 512, boolean logic for conditional resources -
Transform→ SAM/macro expansion -
Resources→ REQUIRED, max 500, the actual AWS resources -
Outputs→ max 200, values surfaced after stack creation
CloudFormation Backend Flow
[1] Parse + Validate → [2] Transform Expansion → [3] Pre-deployment Validation → [4] Build DAG → [5] Compute Change Set → [6] Evaluate Hooks → [7] Parallel Execution (each resource: Resource Provider → API call → Stabilization Loop 20-90 min) → [8] Success: Commit State / Failure: Rollback in reverse DAG order
Key Intrinsic Functions
-
!Ref→ default identifier (bucket name, instance ID, parameter value) -
!GetAtt→ specific attribute (ARN, DNS, public IP) -
!Sub→ string substitution with variables -
!FindInMap→ lookup value in Mappings table -
!If→ conditional value -
!Base64→ encode string for User Data
Deletion Policy
-
Delete(default) → resource deleted with stack -
Retain→ resource stays, CloudFormation stops managing -
Snapshot→ backup before deletion (RDS, EBS)
Change Set
- Preview before applying — shows Add, Modify, Remove, Replace
- Replace = resource deleted and recreated = downtime
- Always use before updating production stacks
Stack Sets
- Same stack → multiple accounts/regions in one operation
- Service-managed mode: auto-deploys to new accounts in an OU
💼 Interview Questions
Q1: What is the difference between a CloudFormation Template and a Stack?
A template is a YAML or JSON file — the blueprint that creates nothing by itself. A stack is what CloudFormation creates when it executes a template — a group of AWS resources managed together as one unit. The same template can create multiple stacks (dev, staging, prod), each independently managed.
Q2: How does CloudFormation handle resource dependencies?
CloudFormation builds a Directed Acyclic Graph (DAG) from DependsOn attributes, !Ref references, and !GetAtt calls. Resources with no dependencies are created in parallel. Dependent resources are created in the correct order. On failure, rollback follows the reverse DAG order.
Q3: What happens during the Stabilization Loop?
After making a Create/Update/Delete API call through a Resource Provider, CloudFormation doesn't assume the resource is immediately ready. It polls the resource until it reaches its required stable state. Some resources like RDS or Elasticsearch can take 20–90 minutes to stabilize. This is why CloudFormation stacks spend a long time in CREATE_IN_PROGRESS — they're waiting for stabilization, not making slow API calls.
Q4: What is a Change Set and why should you use one before updating a production stack?
A Change Set previews every change CloudFormation will make — which resources will be Added, Modified, Removed, or Replaced. A Replace action deletes and recreates a resource, causing downtime. Using a Change Set catches this before applying, preventing unplanned outages.
Q5: What is the difference between a Stack Policy and a Deletion Policy?
A Stack Policy is a JSON document attached to a stack that prevents specific resources from being updated or replaced during stack updates — protecting critical resources from accidental replacement. A Deletion Policy is a property on individual resources inside the template that controls what happens when the stack is deleted: Delete (remove), Retain (keep), or Snapshot (backup before deleting).
Q6: What is the difference between CF Parameters and CF Rules?
Parameters define the input values a deployer provides at stack creation or update. AllowedValues can restrict a single parameter to a fixed list. Rules are validation logic that works across multiple parameters — for example, "when Environment is prod, InstanceType must not be t3.micro." Parameters control individual inputs; Rules validate that combinations of inputs make sense together.
Q7: What is !Ref vs !GetAtt?
!Ref returns the default identifier of a resource — for S3 it returns the bucket name, for EC2 it returns the instance ID. !GetAtt returns a specific named attribute — !GetAtt MyBucket.Arn returns the ARN, !GetAtt MyInstance.PublicIp returns the public IP. Use !Ref for the primary identifier, !GetAtt for everything else.
Q8: What is a CloudFormation Service Role and why would you use it?
A Service Role is an IAM Role that CloudFormation assumes to create resources, instead of using the deploying user's permissions. It enforces governance — developers can deploy CloudFormation stacks without having direct IAM permissions to create EC2s or VPCs. CloudFormation assumes the role and creates resources, keeping least privilege for humans while enabling necessary automation.
📝 Assignment
Create a CloudFormation stack that deploys an Auto Scaling Group with a Launch Template and hosts a web server using a User Data script. The web server should be accessible via an Application Load Balancer. All resources created and managed by a single CloudFormation template.
AWS Session 16 — AWS CloudFormation | Cloud + DevOps learning journey — Systems Engineer → Cloud/DevOps Engineer
Top comments (0)