Skip to content

Instantly share code, notes, and snippets.

@igorlg
Last active April 20, 2017 18:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save igorlg/af4d3ef48705c1919242 to your computer and use it in GitHub Desktop.
Save igorlg/af4d3ef48705c1919242 to your computer and use it in GitHub Desktop.
AWS CloudFormation VPC Templates
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Template for a VPC with High Availability NAT for ECS",
"Parameters": {
"NATInstanceType": {
"Description": "NAT instance type",
"Type": "String",
"Default": "t2.micro",
"AllowedValues": [
"t2.micro",
"t2.small",
"m3.medium",
"m3.large",
"c3.large"
],
"ConstraintDescription": "must be a valid EC2 instance type."
},
"NATInstanceKeyName": {
"Description": "Name of an existing EC2 KeyPair to enable SSH access to the NAT instance",
"Type": "AWS::EC2::KeyPair::KeyName",
"ConstraintDescription": "must be the name of an existing EC2 KeyPair."
}
},
"Mappings": {
"SubnetAZs": {
"us-east-1": {
"Net1": "us-east-1a",
"Net2": "us-east-1c",
"Net3": "us-east-1d"
},
"us-west-2": {
"Net1": "us-west-2a",
"Net2": "us-west-2b",
"Net3": "us-west-2c"
},
"eu-west-1": {
"Net1": "eu-west-1a",
"Net2": "eu-west-1b",
"Net3": "eu-west-1c"
},
"sa-east-1": {
"Net1": "sa-east-1a",
"Net2": "sa-east-1b",
"Net3": "sa-east-1c"
}
},
"CIDRs": {
"VPC": { "Value": "10.1.0.0/16" },
"PubNet1": { "Value": "10.1.10.0/24" },
"PubNet2": { "Value": "10.1.11.0/24" },
"PubNet3": { "Value": "10.1.12.0/24" },
"PrivNet1": { "Value": "10.1.20.0/24" },
"PrivNet2": { "Value": "10.1.21.0/24" },
"PrivNet3": { "Value": "10.1.22.0/24" }
},
"NATInstanceAMI": {
"us-east-1": {
"AMI": "ami-184dc970"
},
"us-west-2": {
"AMI": "ami-69ae8259"
},
"eu-west-1": {
"AMI": "ami-6975eb1e"
},
"sa-east-1": {
"AMI": "ami-fbfa41e6"
}
},
"NATInstanceTimeouts": {
"NumberOfPings": { "Value": "3" },
"PingTimeout": { "Value": "1" },
"WaitBetweenPings": { "Value": "2" },
"WaitForInstanceStop": { "Value": "60" },
"WaitForInstanceStart": { "Value": "300" }
}
},
"Resources": {
"VPC": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": { "Fn::FindInMap": [ "CIDRs", "VPC", "Value" ] },
"Tags": [
{
"Key": "Name",
"Value": {
"Ref": "AWS::StackName"
}
}
]
}
},
"InternetGateway": {
"Type": "AWS::EC2::InternetGateway",
"Properties": {
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"IGW"
]
]
}
}
]
}
},
"AttachGateway": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"InternetGatewayId": {
"Ref": "InternetGateway"
}
}
},
"SubnetPublic1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": { "Fn::FindInMap": [ "CIDRs", "PubNet1", "Value" ] },
"AvailabilityZone": {
"Fn::FindInMap": [
"SubnetAZs",
{
"Ref": "AWS::Region"
},
"Net1"
]
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"PublicNet",
"1"
]
]
}
}
]
}
},
"SubnetPublic2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": { "Fn::FindInMap": [ "CIDRs", "PubNet2", "Value" ] },
"AvailabilityZone": {
"Fn::FindInMap": [
"SubnetAZs",
{
"Ref": "AWS::Region"
},
"Net2"
]
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"PublicNet",
"2"
]
]
}
}
]
}
},
"SubnetPublic3": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": { "Fn::FindInMap": [ "CIDRs", "PubNet3", "Value" ] },
"AvailabilityZone": {
"Fn::FindInMap": [
"SubnetAZs",
{
"Ref": "AWS::Region"
},
"Net3"
]
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"PublicNet",
"3"
]
]
}
}
]
}
},
"SubnetPrivate1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": { "Fn::FindInMap": [ "CIDRs", "PrivNet1", "Value" ] },
"AvailabilityZone": {
"Fn::FindInMap": [
"SubnetAZs",
{
"Ref": "AWS::Region"
},
"Net1"
]
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"PrivateNet",
"1"
]
]
}
}
]
}
},
"SubnetPrivate2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": { "Fn::FindInMap": [ "CIDRs", "PrivNet2", "Value" ] },
"AvailabilityZone": {
"Fn::FindInMap": [
"SubnetAZs",
{
"Ref": "AWS::Region"
},
"Net2"
]
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"PrivateNet",
"2"
]
]
}
}
]
}
},
"SubnetPrivate3": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": { "Fn::FindInMap": [ "CIDRs", "PrivNet3", "Value" ] },
"AvailabilityZone": {
"Fn::FindInMap": [
"SubnetAZs",
{
"Ref": "AWS::Region"
},
"Net3"
]
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"PrivateNet",
"3"
]
]
}
}
]
}
},
"RouteTabPublic": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"RouteTable",
"Public"
]
]
}
}
]
}
},
"RouteTabPrivate1": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"RouteTable",
"Private",
"1"
]
]
}
}
]
}
},
"RouteTabPrivate2": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"RouteTable",
"Private",
"2"
]
]
}
}
]
}
},
"RoutePublic": {
"Type": "AWS::EC2::Route",
"Properties": {
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "InternetGateway"
},
"RouteTableId": {
"Ref": "RouteTabPublic"
}
}
},
"RoutePrivate1": {
"Type": "AWS::EC2::Route",
"Properties": {
"DestinationCidrBlock": "0.0.0.0/0",
"InstanceId": {
"Ref": "NATInstance1"
},
"RouteTableId": {
"Ref": "RouteTabPrivate1"
}
}
},
"RoutePrivate2": {
"Type": "AWS::EC2::Route",
"Properties": {
"DestinationCidrBlock": "0.0.0.0/0",
"InstanceId": {
"Ref": "NATInstance2"
},
"RouteTableId": {
"Ref": "RouteTabPrivate2"
}
}
},
"SubnetPublic1RouteTable": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "RouteTabPublic"
},
"SubnetId": {
"Ref": "SubnetPublic1"
}
}
},
"SubnetPublic2RouteTable": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "RouteTabPublic"
},
"SubnetId": {
"Ref": "SubnetPublic2"
}
}
},
"SubnetPublic3RouteTable": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "RouteTabPublic"
},
"SubnetId": {
"Ref": "SubnetPublic3"
}
}
},
"SubnetPrivate1RouteTable": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "RouteTabPrivate1"
},
"SubnetId": {
"Ref": "SubnetPrivate1"
}
}
},
"SubnetPrivate2RouteTable": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "RouteTabPrivate2"
},
"SubnetId": {
"Ref": "SubnetPrivate2"
}
}
},
"SubnetPrivate3RouteTable": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "RouteTabPrivate1"
},
"SubnetId": {
"Ref": "SubnetPrivate3"
}
}
},
"NATSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Security Group for the NAT Instance",
"VpcId": {
"Ref": "VPC"
},
"SecurityGroupIngress": [
{
"CidrIp": { "Fn::FindInMap": [ "CIDRs", "VPC", "Value" ] },
"IpProtocol": "-1",
"FromPort": "-1",
"ToPort": "-1"
}
],
"Tags": [
{
"Key": "Name",
"Value": { "Fn::Join": [ "-", [ { "Ref": "AWS::StackName" }, "NAT", "SG" ] ] }
},
{
"Key": "Role",
"Value": "NAT"
}
]
}
},
"IAMRoleNAT": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [ {
"Effect": "Allow",
"Principal": {
"Service": [ "ec2.amazonaws.com" ]
},
"Action": [ "sts:AssumeRole" ]
} ]
},
"Path": "/",
"Policies": [
{
"PolicyName": {"Fn::Join": ["-", [ { "Ref": "AWS::StackName" }, "nat", "role" ] ] },
"PolicyDocument": {
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeRouteTables",
"ec2:CreateRoute",
"ec2:ReplaceRoute",
"ec2:StartInstances",
"ec2:StopInstances"
],
"Resource": "*"
}
]
}
}
]
}
},
"IAMInstanceProfileNAT": {
"Type": "AWS::IAM::InstanceProfile",
"Properties": {
"Path": "/",
"Roles": [ { "Ref": "IAMRoleNAT" } ]
}
},
"NATInstance1": {
"Type": "AWS::EC2::Instance",
"Properties": {
"InstanceType": { "Ref": "NATInstanceType" },
"SourceDestCheck": "false",
"Monitoring": "true",
"KeyName": { "Ref": "NATInstanceKeyName" },
"IamInstanceProfile" : { "Ref" : "IAMInstanceProfileNAT" },
"ImageId": { "Fn::FindInMap": [ "NATInstanceAMI", { "Ref": "AWS::Region" }, "AMI" ] },
"SecurityGroupIds": [
{
"Ref": "NATSecurityGroup"
}
],
"SubnetId": {
"Ref": "SubnetPublic1"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"NAT",
"1"
]
]
}
}
],
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"",
[
"#!/bin/bash -v\n",
"yum update -y aws*\n",
". /etc/profile.d/aws-apitools-common.sh\n",
"/sbin/iptables -t nat -A POSTROUTING -o eth0 -s 0.0.0.0/0 -j MASQUERADE\n",
"/sbin/iptables-save > /etc/sysconfig/iptables\n",
"echo 1 > /proc/sys/net/ipv4/ip_forward && echo 0 > /proc/sys/net/ipv4/conf/eth0/send_redirects\n",
"mkdir -p /etc/sysctl.d/\n",
"cat <<EOF > /etc/sysctl.d/nat.conf\n",
"net.ipv4.ip_forward = 1\n",
"net.ipv4.conf.eth0.send_redirects = 0\n",
"EOF\n",
"cd /root\n",
"wget http://media.amazonwebservices.com/articles/nat_monitor_files/nat_monitor.sh\n",
"NAT_ID=\n",
"while [ \"$NAT_ID\" == \"\" ]; do\n",
" sleep 60\n",
" NAT_ID=`/opt/aws/bin/ec2-describe-route-tables ",
{ "Ref": "RouteTabPrivate2" },
" -U https://ec2.",
{ "Ref": "AWS::Region" },
".amazonaws.com | grep 0.0.0.0/0 | awk '{print $2;}'`\n",
" #echo `date` \"-- NAT_ID=$NAT_ID\" >> /tmp/test.log\n",
"done\n",
"sed \"s/NAT_ID=/NAT_ID=$NAT_ID/g\" /root/nat_monitor.sh > /root/nat_monitor.tmp\n",
"sed \"s/NAT_RT_ID=/NAT_RT_ID=",
{ "Ref": "RouteTabPrivate2" },
"/g\" /root/nat_monitor.tmp > /root/nat_monitor.sh\n",
"sed \"s/My_RT_ID=/My_RT_ID=",
{ "Ref": "RouteTabPrivate1" },
"/g\" /root/nat_monitor.sh > /root/nat_monitor.tmp\n",
"sed \"s/EC2_URL=/EC2_URL=https:\\/\\/ec2.",
{ "Ref": "AWS::Region" },
".amazonaws.com",
"/g\" /root/nat_monitor.tmp > /root/nat_monitor.sh\n",
"sed \"s/Num_Pings=3/Num_Pings=",
{ "Fn::FindInMap": [ "NATInstanceTimeouts", "NumberOfPings", "Value" ] },
"/g\" /root/nat_monitor.sh > /root/nat_monitor.tmp\n",
"sed \"s/Ping_Timeout=1/Ping_Timeout=",
{ "Fn::FindInMap": [ "NATInstanceTimeouts", "PingTimeout", "Value" ] },
"/g\" /root/nat_monitor.tmp > /root/nat_monitor.sh\n",
"sed \"s/Wait_Between_Pings=2/Wait_Between_Pings=",
{ "Fn::FindInMap": [ "NATInstanceTimeouts", "WaitBetweenPings", "Value" ] },
"/g\" /root/nat_monitor.sh > /root/nat_monitor.tmp\n",
"sed \"s/Wait_for_Instance_Stop=60/Wait_for_Instance_Stop=",
{ "Fn::FindInMap": [ "NATInstanceTimeouts", "WaitForInstanceStop", "Value" ] },
"/g\" /root/nat_monitor.tmp > /root/nat_monitor.sh\n",
"sed \"s/Wait_for_Instance_Start=300/Wait_for_Instance_Start=",
{ "Fn::FindInMap": [ "NATInstanceTimeouts", "WaitForInstanceStart", "Value" ] },
"/g\" /root/nat_monitor.sh > /root/nat_monitor.tmp\n",
"mv /root/nat_monitor.tmp /root/nat_monitor.sh\n",
"chmod a+x /root/nat_monitor.sh\n",
"echo '@reboot /root/nat_monitor.sh > /tmp/nat_monitor.log' | crontab\n",
"/root/nat_monitor.sh > /tmp/nat_monitor.log &\n"
]
]
}
}
}
},
"NATInstance2": {
"Type": "AWS::EC2::Instance",
"Properties": {
"InstanceType": { "Ref": "NATInstanceType" },
"SourceDestCheck": "false",
"Monitoring": "true",
"KeyName": { "Ref": "NATInstanceKeyName" },
"IamInstanceProfile" : { "Ref" : "IAMInstanceProfileNAT" },
"ImageId": {
"Fn::FindInMap": [
"NATInstanceAMI",
{
"Ref": "AWS::Region"
},
"AMI"
]
},
"SecurityGroupIds": [
{
"Ref": "NATSecurityGroup"
}
],
"SubnetId": {
"Ref": "SubnetPublic2"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"NAT",
"2"
]
]
}
}
],
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"",
[
"#!/bin/bash -v\n",
"yum update -y aws*\n",
"# Configure iptables\n",
"/sbin/iptables -t nat -A POSTROUTING -o eth0 -s 0.0.0.0/0 -j MASQUERADE\n",
"/sbin/iptables-save > /etc/sysconfig/iptables\n",
"# Configure ip forwarding and redirects\n",
"echo 1 > /proc/sys/net/ipv4/ip_forward && echo 0 > /proc/sys/net/ipv4/conf/eth0/send_redirects\n",
"mkdir -p /etc/sysctl.d/\n",
"cat <<EOF > /etc/sysctl.d/nat.conf\n",
"net.ipv4.ip_forward = 1\n",
"net.ipv4.conf.eth0.send_redirects = 0\n",
"EOF\n",
"# Download nat_monitor.sh and configure\n",
"cd /root\n",
"wget http://media.amazonwebservices.com/articles/nat_monitor_files/nat_monitor.sh\n",
"# Update NAT_ID, NAT_RT_ID, and My_RT_ID\n",
"sed \"s/NAT_ID=/NAT_ID=",
{ "Ref": "NATInstance1" },
"/g\" /root/nat_monitor.sh > /root/nat_monitor.tmp\n",
"sed \"s/NAT_RT_ID=/NAT_RT_ID=",
{ "Ref": "RouteTabPrivate1" },
"/g\" /root/nat_monitor.tmp > /root/nat_monitor.sh\n",
"sed \"s/My_RT_ID=/My_RT_ID=",
{ "Ref": "RouteTabPrivate2" },
"/g\" /root/nat_monitor.sh > /root/nat_monitor.tmp\n",
"sed \"s/EC2_URL=/EC2_URL=https:\\/\\/ec2.",
{ "Ref": "AWS::Region" },
".amazonaws.com",
"/g\" /root/nat_monitor.tmp > /root/nat_monitor.sh\n",
"sed \"s/Num_Pings=3/Num_Pings=",
{ "Fn::FindInMap": [ "NATInstanceTimeouts", "NumberOfPings", "Value" ] },
"/g\" /root/nat_monitor.sh > /root/nat_monitor.tmp\n",
"sed \"s/Ping_Timeout=1/Ping_Timeout=",
{ "Fn::FindInMap": [ "NATInstanceTimeouts", "PingTimeout", "Value" ] },
"/g\" /root/nat_monitor.tmp > /root/nat_monitor.sh\n",
"sed \"s/Wait_Between_Pings=2/Wait_Between_Pings=",
{ "Fn::FindInMap": [ "NATInstanceTimeouts", "WaitBetweenPings", "Value" ] },
"/g\" /root/nat_monitor.sh > /root/nat_monitor.tmp\n",
"sed \"s/Wait_for_Instance_Stop=60/Wait_for_Instance_Stop=",
{ "Fn::FindInMap": [ "NATInstanceTimeouts", "WaitForInstanceStop", "Value" ] },
"/g\" /root/nat_monitor.tmp > /root/nat_monitor.sh\n",
"sed \"s/Wait_for_Instance_Start=300/Wait_for_Instance_Start=",
{ "Fn::FindInMap": [ "NATInstanceTimeouts", "WaitForInstanceStart", "Value" ] },
"/g\" /root/nat_monitor.sh > /root/nat_monitor.tmp\n",
"mv /root/nat_monitor.tmp /root/nat_monitor.sh\n",
"chmod a+x /root/nat_monitor.sh\n",
"echo '@reboot /root/nat_monitor.sh > /tmp/nat_monitor.log' | crontab\n",
"/root/nat_monitor.sh >> /tmp/nat_monitor.log &\n"
]
]
}
}
}
},
"NATInstance1EIP": {
"Type": "AWS::EC2::EIP",
"Properties" : {
"InstanceId" : { "Ref": "NATInstance1" },
"Domain" : "vpc"
}
},
"NATInstance2EIP": {
"Type": "AWS::EC2::EIP",
"Properties" : {
"InstanceId" : { "Ref": "NATInstance2" },
"Domain" : "vpc"
}
}
},
"Outputs": {
"VPC": {
"Description": "The VPC Id",
"Value": {
"Ref": "VPC"
}
},
"NATInstances1IP": {
"Description": "The Elastic IP of NAT Instance #1",
"Value": { "Ref": "NATInstance1EIP" }
},
"NATInstances2IP": {
"Description": "The Elastic IP of NAT Instance #2",
"Value": { "Ref": "NATInstance2EIP" }
}
}
}
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Template for a VPC with 3 Public and 3 Private subnets and a NAT Instance",
"Parameters": {
"NATInstanceType": {
"Description": "NAT instance type",
"Type": "String",
"Default": "t2.micro",
"AllowedValues": [
"t2.micro",
"t2.small",
"m3.medium",
"m3.large",
"c3.large"
],
"ConstraintDescription": "must be a valid EC2 instance type."
},
"NATInstanceKeyName": {
"Description": "Name of an existing EC2 KeyPair to enable SSH access to the NAT instance",
"Type": "AWS::EC2::KeyPair::KeyName",
"ConstraintDescription": "must be the name of an existing EC2 KeyPair."
}
},
"Mappings": {
"SubnetAZs": {
"us-east-1": {
"Net1": "us-east-1a",
"Net2": "us-east-1c",
"Net3": "us-east-1d"
},
"us-west-2": {
"Net1": "us-west-2a",
"Net2": "us-west-2b",
"Net3": "us-west-2c"
},
"eu-west-1": {
"Net1": "eu-west-1a",
"Net2": "eu-west-1b",
"Net3": "eu-west-1c"
},
"sa-east-1": {
"Net1": "sa-east-1a",
"Net2": "sa-east-1b",
"Net3": "sa-east-1c"
}
},
"CIDRs": {
"VPC": { "Value": "10.1.0.0/16" },
"PubNet1": { "Value": "10.1.10.0/24" },
"PubNet2": { "Value": "10.1.11.0/24" },
"PubNet3": { "Value": "10.1.12.0/24" },
"PrivNet1": { "Value": "10.1.20.0/24" },
"PrivNet2": { "Value": "10.1.21.0/24" },
"PrivNet3": { "Value": "10.1.22.0/24" }
},
"NATInstanceAMI": {
"us-east-1": {
"AMI": "ami-184dc970"
},
"us-west-2": {
"AMI": "ami-69ae8259"
},
"eu-west-1": {
"AMI": "ami-6975eb1e"
},
"sa-east-1": {
"AMI": "ami-fbfa41e6"
}
}
},
"Resources": {
"VPC": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": { "Fn::FindInMap": [ "CIDRs", "VPC", "Value" ] },
"Tags": [
{
"Key": "Name",
"Value": {
"Ref": "AWS::StackName"
}
}
]
}
},
"InternetGateway": {
"Type": "AWS::EC2::InternetGateway",
"Properties": {
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"IGW"
]
]
}
}
]
}
},
"AttachGateway": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"InternetGatewayId": {
"Ref": "InternetGateway"
}
}
},
"SubnetPublic1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": { "Fn::FindInMap": [ "CIDRs", "PubNet1", "Value" ] },
"AvailabilityZone": {
"Fn::FindInMap": [
"SubnetAZs",
{
"Ref": "AWS::Region"
},
"Net1"
]
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"PublicNet",
"1"
]
]
}
}
]
}
},
"SubnetPublic2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": { "Fn::FindInMap": [ "CIDRs", "PubNet2", "Value" ] },
"AvailabilityZone": {
"Fn::FindInMap": [
"SubnetAZs",
{
"Ref": "AWS::Region"
},
"Net2"
]
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"PublicNet",
"2"
]
]
}
}
]
}
},
"SubnetPublic3": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": { "Fn::FindInMap": [ "CIDRs", "PubNet3", "Value" ] },
"AvailabilityZone": {
"Fn::FindInMap": [
"SubnetAZs",
{
"Ref": "AWS::Region"
},
"Net3"
]
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"PublicNet",
"3"
]
]
}
}
]
}
},
"SubnetPrivate1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": { "Fn::FindInMap": [ "CIDRs", "PrivNet1", "Value" ] },
"AvailabilityZone": {
"Fn::FindInMap": [
"SubnetAZs",
{
"Ref": "AWS::Region"
},
"Net1"
]
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"PrivateNet",
"1"
]
]
}
}
]
}
},
"SubnetPrivate2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": { "Fn::FindInMap": [ "CIDRs", "PrivNet2", "Value" ] },
"AvailabilityZone": {
"Fn::FindInMap": [
"SubnetAZs",
{
"Ref": "AWS::Region"
},
"Net2"
]
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"PrivateNet",
"2"
]
]
}
}
]
}
},
"SubnetPrivate3": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": { "Fn::FindInMap": [ "CIDRs", "PrivNet3", "Value" ] },
"AvailabilityZone": {
"Fn::FindInMap": [
"SubnetAZs",
{
"Ref": "AWS::Region"
},
"Net3"
]
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"PrivateNet",
"3"
]
]
}
}
]
}
},
"RouteTabPublic": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"RouteTable",
"Public"
]
]
}
}
]
}
},
"RouteTabPrivate": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"RouteTable",
"Private"
]
]
}
}
]
}
},
"RoutePublic": {
"Type": "AWS::EC2::Route",
"Properties": {
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "InternetGateway"
},
"RouteTableId": {
"Ref": "RouteTabPublic"
}
}
},
"RoutePrivate": {
"Type": "AWS::EC2::Route",
"Properties": {
"DestinationCidrBlock": "0.0.0.0/0",
"InstanceId": {
"Ref": "NATInstance"
},
"RouteTableId": {
"Ref": "RouteTabPrivate"
}
}
},
"SubnetPublic1RouteTable": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "RouteTabPublic"
},
"SubnetId": {
"Ref": "SubnetPublic1"
}
}
},
"SubnetPublic2RouteTable": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "RouteTabPublic"
},
"SubnetId": {
"Ref": "SubnetPublic2"
}
}
},
"SubnetPublic3RouteTable": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "RouteTabPublic"
},
"SubnetId": {
"Ref": "SubnetPublic3"
}
}
},
"SubnetPrivate1RouteTable": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "RouteTabPrivate"
},
"SubnetId": {
"Ref": "SubnetPrivate1"
}
}
},
"SubnetPrivate2RouteTable": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "RouteTabPrivate"
},
"SubnetId": {
"Ref": "SubnetPrivate2"
}
}
},
"SubnetPrivate3RouteTable": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "RouteTabPrivate"
},
"SubnetId": {
"Ref": "SubnetPrivate3"
}
}
},
"NATSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Security Group for the NAT Instance",
"VpcId": {
"Ref": "VPC"
},
"SecurityGroupIngress": [
{
"CidrIp": { "Fn::FindInMap": [ "CIDRs", "VPC", "Value" ] },
"IpProtocol": "-1",
"FromPort": "-1",
"ToPort": "-1"
}
],
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"NAT",
"SG"
]
]
}
},
{
"Key": "Role",
"Value": "NAT"
}
]
}
},
"IAMRoleNAT": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"nat",
"role"
]
]
},
"PolicyDocument": {
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeRouteTables",
"ec2:CreateRoute",
"ec2:ReplaceRoute",
"ec2:StartInstances",
"ec2:StopInstances"
],
"Resource": "*"
}
]
}
}
]
}
},
"IAMInstanceProfileNAT": {
"Type": "AWS::IAM::InstanceProfile",
"Properties": {
"Path": "/",
"Roles": [
{
"Ref": "IAMRoleNAT"
}
]
}
},
"NATInstance": {
"Type": "AWS::EC2::Instance",
"Properties": {
"InstanceType": {
"Ref": "NATInstanceType"
},
"SourceDestCheck": "false",
"Monitoring": "true",
"KeyName": {
"Ref": "NATInstanceKeyName"
},
"IamInstanceProfile": {
"Ref": "IAMInstanceProfileNAT"
},
"ImageId": {
"Fn::FindInMap": [
"NATInstanceAMI",
{
"Ref": "AWS::Region"
},
"AMI"
]
},
"SecurityGroupIds": [
{
"Ref": "NATSecurityGroup"
}
],
"SubnetId": {
"Ref": "SubnetPublic1"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"NAT"
]
]
}
}
]
}
},
"NATInstanceEIP": {
"Type": "AWS::EC2::EIP",
"Properties": {
"InstanceId": {
"Ref": "NATInstance"
},
"Domain": "vpc"
}
}
},
"Outputs": {
"VPC": {
"Description": "The VPC Id",
"Value": {
"Ref": "VPC"
}
},
"NATInstanceIP": {
"Description": "The NAT Instance EIP",
"Value": {
"Ref": "NATInstanceEIP"
}
}
}
}
@igorlg
Copy link
Author

igorlg commented Jun 10, 2015

PLEASE FEEL FREE TO SUGGEST CHANGES OR IMPROVEMENTS

Or, if you need any help, you can reach me on Twitter at @igorlgentil.

I've seen this before, more of the same?

Pretty much, yeah. The difference being I have a little bit of OCD and like things with organized names, tags, etc...

Please explain...

I've created these templates for a VPC with Public and Private Subnets and a NAT instance(s).

The first template assumes a single NAT instance, whereas the second assumes two with Failover capability.

These templates have been tested on the following AWS regions:

  • us-east-1
  • us-west-2
  • eu-west-1
  • sa-east-1

NAT Instance AMI

I used the latest (as of June 10th 2015) official NAT AMI provided by AWS: amzn-ami-vpc-nat-hvm-2015.03.0.x86_64-gp2. It uses EBS GP2 as the root volume (size ~8Gb).
The AMI ID on each region is:

  • us-east-1: ami-184dc970
  • us-west-2: ami-69ae8259
  • eu-west-1: ami-6975eb1e
  • sa-east-1: ami-fbfa41e6

Why is my region not supported?

Basically, I wanted a minimum of 3 AZs on the VPC. If you want to use these templates on a region with less than 3 AZs, feel free to edit it. It's pretty self-explanatory.

Further read

If you got this far, you probably don't need to read this, but anyways... http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_NAT_Instance.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment