CloudFormation - Infrastructure as Code
What is CloudFormation?
CloudFormation allows you to define AWS infrastructure as code using JSON or YAML templates. This enables version control, repeatability, and automation of infrastructure provisioning.
Key Concepts
Template - JSON or YAML file defining resources Stack - Collection of AWS resources created from a template Change Set - Preview of changes before updating a stack
CloudFormation Template Structure
AWSTemplateFormatVersion: '2010-09-09'
Description: 'CloudFormation template description'
Parameters:
# Input parameters
Resources:
# AWS resources to create
Outputs:
# Values to export
Basic Example: EC2 Instance
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Simple EC2 instance'
Parameters:
InstanceType:
Type: String
Default: t3.micro
AllowedValues:
- t3.micro
- t3.small
- t3.medium
Description: EC2 instance type
KeyName:
Type: AWS::EC2::KeyPair::KeyName
Description: SSH key pair name
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref InstanceType
ImageId: ami-0c55b159cbfafe1f0 # Amazon Linux 2 (us-east-1)
KeyName: !Ref KeyName
SecurityGroupIds:
- !Ref MySecurityGroup
Tags:
- Key: Name
Value: MyWebServer
MySecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow SSH and HTTP
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
Outputs:
InstanceId:
Description: Instance ID
Value: !Ref MyEC2Instance
PublicIP:
Description: Public IP address
Value: !GetAtt MyEC2Instance.PublicIp
VPC with Public and Private Subnets
AWSTemplateFormatVersion: '2010-09-09'
Description: 'VPC with public and private subnets'
Resources:
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: MyVPC
PublicSubnet:
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
PrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: 10.0.2.0/24
AvailabilityZone: !Select [0, !GetAZs '']
Tags:
- Key: Name
Value: Private Subnet
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: MyIGW
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref MyVPC
InternetGatewayId: !Ref InternetGateway
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MyVPC
Tags:
- Key: Name
Value: Public Route Table
PublicRoute:
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
SubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet
RouteTableId: !Ref PublicRouteTable
Outputs:
VPCId:
Description: VPC ID
Value: !Ref MyVPC
Export:
Name: !Sub '${AWS::StackName}-VPC'
PublicSubnetId:
Description: Public Subnet ID
Value: !Ref PublicSubnet
Export:
Name: !Sub '${AWS::StackName}-PublicSubnet'
Deploying CloudFormation Stacks
Using AWS CLI:
# Create stack
aws cloudformation create-stack \
--stack-name my-stack \
--template-body file://template.yaml \
--parameters ParameterKey=KeyName,ParameterValue=my-key
# Update stack
aws cloudformation update-stack \
--stack-name my-stack \
--template-body file://template.yaml
# Delete stack
aws cloudformation delete-stack \
--stack-name my-stack
# Describe stack
aws cloudformation describe-stacks \
--stack-name my-stack
# List all stacks
aws cloudformation list-stacks
Using AWS Console:
- Navigate to CloudFormation service
- Click "Create stack"
- Upload template file or paste template
- Enter stack name and parameters
- Review and create
CloudFormation Best Practices
1. Use Parameters for Flexibility
Parameters:
Environment:
Type: String
Default: dev
AllowedValues: [dev, staging, prod]
2. Use Intrinsic Functions
# !Ref - Reference parameters or resources
InstanceType: !Ref InstanceTypeParameter
# !GetAtt - Get attribute of resource
PublicIp: !GetAtt MyEC2Instance.PublicIp
# !Sub - String substitution
Name: !Sub '${AWS::StackName}-instance'
# !Join - Join strings
SecurityGroupIds: !Join [',', !Ref SecurityGroups]
3. Export Values for Cross-Stack References
Outputs:
VPCId:
Value: !Ref MyVPC
Export:
Name: SharedVPC
# In another stack:
Resources:
MyInstance:
Type: AWS::EC2::Instance
Properties:
SubnetId: !ImportValue SharedVPC
4. Use Nested Stacks for Modularity
Resources:
NetworkStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/bucket/network.yaml
Parameters:
VPCCidr: 10.0.0.0/16
Master Infrastructure as Code with CloudFormation for repeatable, version-controlled AWS deployments!