Skip to main content

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:

  1. Navigate to CloudFormation service
  2. Click "Create stack"
  3. Upload template file or paste template
  4. Enter stack name and parameters
  5. 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!