CloudFormation Basics

Template Structure

AWSTemplateFormatVersion: '2010-09-09' Description: 'My application stack' Parameters: Environment: Type: String AllowedValues: [dev, staging, prod] Default: dev Mappings: RegionAMI: us-east-1: ami: ami-0abcdef1234567890 us-west-2: ami: ami-0987654321fedcba0 Conditions: IsProd: !Equals [!Ref Environment, prod] Resources: MyBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub 'my-app-${Environment}-${AWS::AccountId}' Outputs: BucketArn: Value: !GetAtt MyBucket.Arn Export: Name: !Sub '${AWS::StackName}-BucketArn'

Parameters & Pseudo Parameters

Parameters: InstanceType: Type: String Default: t3.micro AllowedValues: [t3.micro, t3.small, t3.medium] Description: EC2 instance type DBPassword: Type: String NoEcho: true # Mask in console MinLength: 8 SubnetIds: Type: List<AWS::EC2::Subnet::Id> # Pseudo parameters (always available) # AWS::AccountId - 123456789012 # AWS::Region - us-east-1 # AWS::StackName - my-stack # AWS::StackId - arn:aws:cloudformation:... # AWS::NoValue - removes property when used # Intrinsic functions !Ref ParameterName # reference parameter/resource !Sub 'Hello ${AWS::Region}' # string substitution !GetAtt Resource.Attribute # get resource attribute !Select [0, !Ref SubnetIds] # select from list !If [IsProd, t3.large, t3.micro] # conditional

Resource Examples

Resources: WebServerSG: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Web server SG VpcId: !Ref VpcId SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 WebServer: Type: AWS::EC2::Instance DependsOn: WebServerSG Properties: InstanceType: !Ref InstanceType ImageId: !FindInMap [RegionAMI, !Ref AWS::Region, ami] SecurityGroupIds: [!Ref WebServerSG] UserData: Fn::Base64: !Sub | #!/bin/bash yum install -y httpd systemctl start httpd WebEIP: Type: AWS::EC2::EIP Properties: InstanceId: !Ref WebServer

Cross-Stack References

# Stack A exports Outputs: VpcId: Value: !Ref MyVPC Export: Name: NetworkStack-VpcId SubnetIds: Value: !Join [',', [!Ref SubnetA, !Ref SubnetB]] Export: Name: NetworkStack-SubnetIds # Stack B imports Resources: AppServer: Type: AWS::EC2::Instance Properties: SubnetId: !Select - 0 - !Split [',', !ImportValue NetworkStack-SubnetIds] # CLI: list exports aws cloudformation list-exports

Stack Operations & Change Sets

# Create stack aws cloudformation create-stack \ --stack-name my-stack \ --template-body file://template.yaml \ --parameters ParameterKey=Environment,ParameterValue=prod \ --capabilities CAPABILITY_IAM # Update with change set (review before applying) aws cloudformation create-change-set \ --stack-name my-stack \ --change-set-name my-changes \ --template-body file://template.yaml aws cloudformation describe-change-set \ --stack-name my-stack \ --change-set-name my-changes aws cloudformation execute-change-set \ --stack-name my-stack \ --change-set-name my-changes # Rollback on failure aws cloudformation continue-update-rollback --stack-name my-stack # Delete stack aws cloudformation delete-stack --stack-name my-stack

Stack Policies & Drift Detection

# Protect resources from update/delete aws cloudformation set-stack-policy \ --stack-name my-stack \ --stack-policy-body '{ "Statement": [{ "Effect": "Deny", "Action": "Update:Replace", "Principal": "*", "Resource": "LogicalResourceId/ProductionDB" }] }' # Detect configuration drift aws cloudformation detect-stack-drift --stack-name my-stack aws cloudformation describe-stack-drift-detection-status \ --stack-drift-detection-id abc123