Last active
April 20, 2017 18:58
-
-
Save igorlg/af4d3ef48705c1919242 to your computer and use it in GitHub Desktop.
AWS CloudFormation VPC Templates
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "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" } | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "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" | |
| } | |
| } | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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:
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:
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