Cloudformation
AWS CloudFormation infrastructure-as-code for provisioning and managing AWS resources declaratively
You are an expert in AWS CloudFormation for defining, provisioning, and managing AWS infrastructure as code using declarative YAML or JSON templates. ## Key Points - **Applying updates without change sets** -- Direct `update-stack` in production risks unintended resource replacements and data loss. Always preview changes first. - **Building a single 500-resource mega-template** -- This exceeds stack limits, slows deployments, and makes rollbacks fragile. Decompose into nested stacks with clear dependency boundaries. - **Ignoring stack drift** -- Manual console changes that diverge from the template create a shadow infrastructure. Run drift detection regularly and reconcile differences back into templates. - **Always use change sets** for production updates. Review the changes before executing. - **Set `DeletionPolicy: Retain`** on stateful resources (databases, S3 buckets) to prevent accidental data loss on stack deletion. - **Use `!Sub` and `AWS::StackName`** for naming resources to avoid collisions between stacks. - **Parameterize environments**: Use parameters and conditions so the same template works for dev, staging, and prod. - **Export outputs** for cross-stack references, but be cautious: exported values create dependencies that block stack deletion. - **Use `cfn-lint`** to validate templates before deploying: `cfn-lint template.yaml`. - **Enable termination protection** on production stacks: `aws cloudformation update-termination-protection --enable-termination-protection --stack-name prod`. - **Keep templates modular** using nested stacks. Separate network, compute, database, and monitoring into reusable templates. - **Use stack policies** to prevent replacement or deletion of critical resources during updates. ## Quick Example ```bash aws cloudformation detect-stack-drift --stack-name my-app-prod aws cloudformation describe-stack-drift-detection-status --stack-drift-detection-id <id> aws cloudformation describe-stack-resource-drifts --stack-name my-app-prod ```
skilldb get aws-services-skills/CloudformationFull skill: 278 linesAWS CloudFormation — Cloud Services
You are an expert in AWS CloudFormation for defining, provisioning, and managing AWS infrastructure as code using declarative YAML or JSON templates.
Core Philosophy
Infrastructure belongs in code, not in click-ops. CloudFormation templates are the single source of truth for your AWS environment. Every resource -- from VPCs to Lambda functions -- should be declared in version-controlled templates so that environments are reproducible, auditable, and recoverable. If a resource exists in the console but not in a template, it is technical debt waiting to cause a production incident.
Change sets are your safety net. Never apply changes to production stacks directly. Always create a change set, review the planned modifications (especially replacements and deletions), and only then execute. This discipline catches destructive changes -- like an RDS engine swap that triggers resource replacement -- before they destroy data. Combine change sets with termination protection and stack policies for defense in depth.
Templates should be modular and parameterized. A single monolithic template with 400 resources is unmaintainable. Break infrastructure into nested stacks by concern (networking, compute, data, monitoring) and wire them together with outputs and cross-stack references. Use parameters and conditions so the same templates serve dev, staging, and production without forking.
Anti-Patterns
- Applying updates without change sets -- Direct
update-stackin production risks unintended resource replacements and data loss. Always preview changes first. - Hardcoding account IDs, regions, and resource names -- Use pseudo parameters (
AWS::AccountId,AWS::Region) andAWS::StackNamefor dynamic naming. Hardcoded values break multi-account and multi-region deployments. - Omitting DeletionPolicy on stateful resources -- Databases, S3 buckets, and encryption keys should have
DeletionPolicy: RetainorSnapshotto prevent accidental data destruction on stack deletion. - Building a single 500-resource mega-template -- This exceeds stack limits, slows deployments, and makes rollbacks fragile. Decompose into nested stacks with clear dependency boundaries.
- Ignoring stack drift -- Manual console changes that diverge from the template create a shadow infrastructure. Run drift detection regularly and reconcile differences back into templates.
Overview
CloudFormation lets you model AWS resources in templates that are deployed as stacks. It handles dependency ordering, rollback on failure, drift detection, and change sets for safe updates. Templates declare resources, parameters, outputs, mappings, and conditions. Nested stacks and stack sets support modular and multi-account deployments.
Setup & Configuration
Template Structure
AWSTemplateFormatVersion: "2010-09-09"
Description: My application infrastructure
Parameters:
Environment:
Type: String
AllowedValues: [dev, staging, prod]
Default: dev
VpcId:
Type: AWS::EC2::VPC::Id
Conditions:
IsProd: !Equals [!Ref Environment, prod]
Mappings:
RegionConfig:
us-east-1:
AMI: ami-0abcdef1234567890
eu-west-1:
AMI: ami-0fedcba9876543210
Resources:
# Resources defined here
Outputs:
ApiEndpoint:
Description: API Gateway endpoint URL
Value: !GetAtt Api.Endpoint
Export:
Name: !Sub "${AWS::StackName}-ApiEndpoint"
Deploy a Stack
# Create stack
aws cloudformation create-stack \
--stack-name my-app-prod \
--template-body file://template.yaml \
--parameters ParameterKey=Environment,ParameterValue=prod \
--capabilities CAPABILITY_NAMED_IAM \
--tags Key=Team,Value=platform
# Wait for completion
aws cloudformation wait stack-create-complete --stack-name my-app-prod
# Update stack via change set (safe preview)
aws cloudformation create-change-set \
--stack-name my-app-prod \
--change-set-name update-v2 \
--template-body file://template-v2.yaml \
--parameters ParameterKey=Environment,ParameterValue=prod \
--capabilities CAPABILITY_NAMED_IAM
aws cloudformation describe-change-set \
--stack-name my-app-prod \
--change-set-name update-v2
aws cloudformation execute-change-set \
--stack-name my-app-prod \
--change-set-name update-v2
Core Patterns
VPC with Public and Private Subnets
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub "${AWS::StackName}-vpc"
PublicSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.1.0/24
AvailabilityZone: !Select [0, !GetAZs ""]
MapPublicIpOnLaunch: true
PrivateSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.10.0/24
AvailabilityZone: !Select [0, !GetAZs ""]
InternetGateway:
Type: AWS::EC2::InternetGateway
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
NatGatewayEIP:
Type: AWS::EC2::EIP
DependsOn: AttachGateway
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGatewayEIP.AllocationId
SubnetId: !Ref PublicSubnetA
Lambda Function with API Gateway
Resources:
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
MyFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub "${AWS::StackName}-handler"
Runtime: python3.12
Handler: index.handler
Role: !GetAtt LambdaExecutionRole.Arn
Code:
ZipFile: |
def handler(event, context):
return {"statusCode": 200, "body": "Hello"}
Environment:
Variables:
TABLE_NAME: !Ref DynamoTable
DynamoTable:
Type: AWS::DynamoDB::Table
DeletionPolicy: Retain
Properties:
TableName: !Sub "${AWS::StackName}-data"
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: PK
AttributeType: S
KeySchema:
- AttributeName: PK
KeyType: HASH
Intrinsic Functions
Resources:
Bucket:
Type: AWS::S3::Bucket
Properties:
# !Sub - string interpolation
BucketName: !Sub "${AWS::StackName}-${AWS::Region}-assets"
# !If - conditional resource properties
Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: !If [IsProd, m5.xlarge, t3.micro]
ImageId: !FindInMap [RegionConfig, !Ref "AWS::Region", AMI]
# !GetAtt - get attribute from another resource
# !Ref - reference a parameter or resource
# !Join, !Split, !Select - string manipulation
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref Bucket
PolicyDocument:
Statement:
- Effect: Allow
Principal:
AWS: !GetAtt LambdaExecutionRole.Arn
Action: s3:GetObject
Resource: !Sub "${Bucket.Arn}/*"
Nested Stacks
Resources:
NetworkStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/my-templates/network.yaml
Parameters:
Environment: !Ref Environment
AppStack:
Type: AWS::CloudFormation::Stack
DependsOn: NetworkStack
Properties:
TemplateURL: https://s3.amazonaws.com/my-templates/app.yaml
Parameters:
VpcId: !GetAtt NetworkStack.Outputs.VpcId
SubnetIds: !GetAtt NetworkStack.Outputs.PrivateSubnetIds
Drift Detection
aws cloudformation detect-stack-drift --stack-name my-app-prod
aws cloudformation describe-stack-drift-detection-status --stack-drift-detection-id <id>
aws cloudformation describe-stack-resource-drifts --stack-name my-app-prod
Best Practices
- Always use change sets for production updates. Review the changes before executing.
- Set
DeletionPolicy: Retainon stateful resources (databases, S3 buckets) to prevent accidental data loss on stack deletion. - Use
!SubandAWS::StackNamefor naming resources to avoid collisions between stacks. - Parameterize environments: Use parameters and conditions so the same template works for dev, staging, and prod.
- Export outputs for cross-stack references, but be cautious: exported values create dependencies that block stack deletion.
- Use
cfn-lintto validate templates before deploying:cfn-lint template.yaml. - Enable termination protection on production stacks:
aws cloudformation update-termination-protection --enable-termination-protection --stack-name prod. - Keep templates modular using nested stacks. Separate network, compute, database, and monitoring into reusable templates.
- Use stack policies to prevent replacement or deletion of critical resources during updates.
Common Pitfalls
- Circular dependencies: Resource A depends on B and B depends on A. Break the cycle with
DependsOnrestructuring or by splitting into separate stacks. - Replacement vs. update: Changing certain properties (e.g., RDS
Engine, LambdaFunctionName) causes resource replacement, destroying the old resource. Check the CloudFormation docs for "Update requires: Replacement". - Forgetting
CAPABILITY_NAMED_IAM: Stacks that create IAM resources require explicit acknowledgment via capabilities. - Stack update rollback stuck in
UPDATE_ROLLBACK_FAILED: Usecontinue-update-rollbackwith--resources-to-skipto skip problematic resources. - Template size limits: Template body max 51,200 bytes inline, 460,800 bytes from S3. Use nested stacks for large architectures.
- Resource limit per stack: 500 resources per stack. Plan modular architecture for large deployments.
- Hard-coded account IDs and regions: Use
AWS::AccountId,AWS::Regionpseudo parameters instead.
Install this skill directly: skilldb add aws-services-skills
Related Skills
API Gateway
AWS API Gateway for building, deploying, and managing RESTful and WebSocket APIs
Cognito
AWS Cognito user authentication and authorization for web and mobile applications
Dynamodb
AWS DynamoDB NoSQL database for high-performance key-value and document workloads
Ecs Fargate
AWS ECS and Fargate for running containerized applications without managing servers
Rds Aurora
AWS RDS and Aurora managed relational databases for production SQL workloads
S3
AWS S3 object storage service for scalable, durable file and data storage