Skip to content

Instantly share code, notes, and snippets.

@dahjohnson
Last active December 3, 2022 15:49
Show Gist options
  • Save dahjohnson/05a5d4c9b63c559c8f6e8e90456f836c to your computer and use it in GitHub Desktop.
Save dahjohnson/05a5d4c9b63c559c8f6e8e90456f836c to your computer and use it in GitHub Desktop.
Deploy an Auto Scaling Group behind an Application Load Balancer and NAT Gateway using AWS CloudFormation
Description: This template deploys the following
- VPC with three separate private and public subnets spread across three Availability Zones
- Internet gateway with a default route on the public subnets
- NAT gateway in the public subnet of the first availability zone with a default route on the private subnets
- Security Group allowing HTTP inbound only from 0.0.0.0/0
- EC2 Launch Template
- Auto Scaling Group using Launch Template
- Application Load Balancer
Parameters:
EnvironmentName:
Description: An environment name that is prefixed to resource names
Type: String
VpcCIDR:
Description: Please enter the IP range (CIDR notation) for this VPC
Type: String
Default: 10.10.0.0/16
PrivateSubnet1CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone
Type: String
Default: 10.10.1.0/24
PrivateSubnet2CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone
Type: String
Default: 10.10.2.0/24
PrivateSubnet3CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the third Availability Zone
Type: String
Default: 10.10.3.0/24
PublicSubnet1CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone
Type: String
Default: 10.10.10.0/24
PublicSubnet2CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone
Type: String
Default: 10.10.20.0/24
PublicSubnet3CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the third Availability Zone
Type: String
Default: 10.10.30.0/24
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-VPC
InternetGateway:
Type: AWS::EC2::InternetGateway
DependsOn: VPC
Properties:
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-InternetGateway
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
DependsOn: InternetGateway
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 0, !GetAZs '' ]
CidrBlock: !Ref PrivateSubnet1CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Subnet (AZ1)
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 1, !GetAZs '' ]
CidrBlock: !Ref PrivateSubnet2CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Subnet (AZ2)
PrivateSubnet3:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 2, !GetAZs '' ]
CidrBlock: !Ref PrivateSubnet3CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Subnet (AZ3)
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 0, !GetAZs '' ]
CidrBlock: !Ref PublicSubnet1CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Subnet (AZ1)
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 1, !GetAZs '' ]
CidrBlock: !Ref PublicSubnet2CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Subnet (AZ2)
PublicSubnet3:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 2, !GetAZs '' ]
CidrBlock: !Ref PublicSubnet3CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Subnet (AZ3)
ElasticIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
NatGateway:
Type: AWS::EC2::NatGateway
DependsOn: PublicSubnet1
Properties:
ConnectivityType: public
AllocationId: !GetAtt ElasticIP.AllocationId
SubnetId: !GetAtt PublicSubnet1.SubnetId
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-NatGateway
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-PublicRouteTable
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-PrivateRouteTable
DefaultPublicRoute:
Type: AWS::EC2::Route
DependsOn: InternetGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
DependsOn: DefaultPublicRoute
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet1
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
DependsOn: DefaultPublicRoute
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet2
PublicSubnet3RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
DependsOn: DefaultPublicRoute
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet3
DefaultPrivateRoute:
Type: AWS::EC2::Route
DependsOn: NatGateway
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway
PrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
DependsOn: DefaultPrivateRoute
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet1
PrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
DependsOn: DefaultPrivateRoute
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet2
PrivateSubnet3RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
DependsOn: DefaultPrivateRoute
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet3
HTTPIngressSecurityGroup:
Type: AWS::EC2::SecurityGroup
DependsOn: VPC
Properties:
GroupName: !Sub ${EnvironmentName}-SecurityGroup
GroupDescription: "Security group with HTTP ingress rule"
VpcId: !Ref VPC
HTTPIngressSecurityGroupRule:
Type: AWS::EC2::SecurityGroupIngress
DependsOn: HTTPIngressSecurityGroup
Properties:
CidrIp: 0.0.0.0/0
Description: "Allow HTTP"
GroupId: !Ref HTTPIngressSecurityGroup
IpProtocol: tcp
FromPort: 80
ToPort: 80
myLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
DependsOn: HTTPIngressSecurityGroup
Properties:
LaunchTemplateName: !Sub ${EnvironmentName}-LaunchTemplate
LaunchTemplateData:
ImageId: ami-0b0dcb5067f052a63
InstanceType: t2.micro
NetworkInterfaces:
- DeviceIndex: 0
AssociatePublicIpAddress: false
Groups:
- !Ref HTTPIngressSecurityGroup
UserData:
Fn::Base64:
!Sub |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
EC2AZ=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)
echo '<center><h1>This Amazon EC2 instance is located in Availability Zone: AZID </h1></center>' > /var/www/html/index.txt
sed "s/AZID/$EC2AZ/" /var/www/html/index.txt > /var/www/html/index.html
ApplicationLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
DependsOn: InternetGatewayAttachment
Properties:
Name: !Sub ${EnvironmentName}-LoadBalancer
Type: application
IpAddressType: ipv4
Scheme: internet-facing
SecurityGroups:
- !GetAtt HTTPIngressSecurityGroup.GroupId
Subnets:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
- !Ref PublicSubnet3
Tags:
- Key: Name
Value: !Ref EnvironmentName
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${EnvironmentName}-TargetGroup
HealthCheckIntervalSeconds: 30
HealthCheckPath: /
Port: 80
Protocol: HTTP
HealthyThresholdCount: 5
UnhealthyThresholdCount: 2
TargetType: instance
Matcher:
HttpCode: "200"
VpcId: !Ref VPC
HTTPListener:
Type: AWS::ElasticLoadBalancingV2::Listener
DependsOn: TargetGroup
Properties:
LoadBalancerArn: !Ref ApplicationLoadBalancer
Port: 80
Protocol: HTTP
DefaultActions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
myAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
DependsOn: myLaunchTemplate
Properties:
AutoScalingGroupName: !Sub ${EnvironmentName}-AutoScaleGroup
DesiredCapacity: 2
MinSize: 2
MaxSize: 5
LaunchTemplate:
LaunchTemplateId: !Ref myLaunchTemplate
Version: !GetAtt myLaunchTemplate.LatestVersionNumber
TargetGroupARNs:
- !Ref TargetGroup
VPCZoneIdentifier:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
- !Ref PrivateSubnet3
Outputs:
VPC:
Description: A reference to the created VPC
Value: !Ref VPC
PrivateSubnet1:
Description: A reference to the private subnet in the 1st Availability Zone
Value: !Ref PrivateSubnet1
PrivateSubnet2:
Description: A reference to the private subnet in the 2nd Availability Zone
Value: !Ref PrivateSubnet2
PrivateSubnet3:
Description: A reference to the private subnet in the 3rd Availability Zone
Value: !Ref PrivateSubnet3
PublicSubnet1:
Description: A reference to the public subnet in the 1st Availability Zone
Value: !Ref PublicSubnet1
PublicSubnet2:
Description: A reference to the public subnet in the 2nd Availability Zone
Value: !Ref PublicSubnet2
PublicSubnet3:
Description: A reference to the public subnet in the 3rd Availability Zone
Value: !Ref PublicSubnet1
HTTPIngressSecurityGroup:
Description: A reference to the Security Group allowing HTTP only inbound
Value: !Ref HTTPIngressSecurityGroup
myLaunchTemplate:
Description: A reference to the Launch Template
Value: !Ref myLaunchTemplate
myAutoScalingGroup:
Description: A reference to the Auto Scaling Group
Value: !Ref myAutoScalingGroup
ApplicationLoadBalancer:
Description: A reference to the Application Load Balancer
Value: !Ref ApplicationLoadBalancer
LoadBalancerURL:
Description: The URL of the Application Load Balancer
Value: !GetAtt ApplicationLoadBalancer.DNSName
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment