Skip to content

Instantly share code, notes, and snippets.

@ralph-tice
Last active December 25, 2018 11:17
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ralph-tice/3d6e5b2076cbc2900aaa to your computer and use it in GitHub Desktop.
Save ralph-tice/3d6e5b2076cbc2900aaa to your computer and use it in GitHub Desktop.
terraform for 3 AZ VPC with NAT instance with autorecovery
###########
# Variables
###########
variable "aws_key_name" {
default = "mykeypair"
}
variable "region" {
default = "eu-west-1"
}
variable "vpc_name" {
default = "Development VPC"
}
# this template will use a /16 for the VPC and /24s for subnets
# starting at *.*.0.0/24 for private, counting up
# and *.*.255.0/24 for public, counting down
variable "cidr_prefix" {
default = "10.253"
}
#########
# Outputs
#########
output availability_zones {
value = "eu-west-1a,eu-west-1b,eu-west-1c"
}
output default_elb_sg {
value = "${aws_security_group.default_elb.id}"
}
output default_host_sg {
value = "${aws_security_group.default_host.id}"
}
output private_subnet_ids {
value = "${aws_subnet.a_private.id},${aws_subnet.b_private.id},${aws_subnet.c_private.id}"
}
output private_subnet_ids_elb {
value = "${aws_subnet.a_private.id},${aws_subnet.b_private.id},${aws_subnet.c_private.id}"
}
output public_subnet_ids {
value = "${aws_subnet.a_public.id},${aws_subnet.b_public.id},${aws_subnet.c_public.id}"
}
output region {
value = "${var.region}"
}
output vpc_id {
value = "${aws_vpc.this_vpc.id}"
}
output vpc_cidr_block {
value = "${aws_vpc.this_vpc.cidr_block}"
}
# Subnets
output "production_1a_private_id" { value = "${aws_subnet.a_private.id}" }
output "production_1b_private_id" { value = "${aws_subnet.b_private.id}" }
output "production_1c_private_id" { value = "${aws_subnet.c_private.id}" }
output "production_1a_public_id" { value = "${aws_subnet.a_public.id}" }
output "production_1b_public_id" { value = "${aws_subnet.b_public.id}" }
output "production_1c_public_id" { value = "${aws_subnet.c_public.id}" }
###########
# Resources
###########
provider aws {
region = "${var.region}"
}
# Vpc
resource aws_vpc "this_vpc" {
cidr_block = "${var.cidr_prefix}.0.0/16"
tags {
Name = "${var.vpc_name}"
}
}
resource "aws_internet_gateway" "default" {
vpc_id = "${aws_vpc.this_vpc.id}"
}
# Subnets
resource aws_subnet "a_private" {
availability_zone = "${var.region}a"
cidr_block = "${var.cidr_prefix}.0.0/24"
vpc_id = "${aws_vpc.this_vpc.id}"
tags {
Name = "${var.vpc_name}_a_private"
}
}
resource aws_subnet "b_private" {
availability_zone = "${var.region}b"
cidr_block = "${var.cidr_prefix}.1.0/24"
vpc_id = "${aws_vpc.this_vpc.id}"
tags {
Name = "${var.vpc_name}_b_private"
}
}
resource aws_subnet "c_private" {
availability_zone = "${var.region}c"
cidr_block = "${var.cidr_prefix}.2.0/24"
vpc_id = "${aws_vpc.this_vpc.id}"
tags {
Name = "${var.vpc_name}_c_private"
}
}
resource aws_subnet "a_public" {
availability_zone = "${var.region}a"
cidr_block = "${var.cidr_prefix}.255.0/24"
map_public_ip_on_launch = true
vpc_id = "${aws_vpc.this_vpc.id}"
tags {
Name = "${var.vpc_name}_a_public"
}
}
resource aws_subnet "b_public" {
availability_zone = "${var.region}b"
cidr_block = "${var.cidr_prefix}.254.0/24"
map_public_ip_on_launch = true
vpc_id = "${aws_vpc.this_vpc.id}"
tags {
Name = "${var.vpc_name}_b_public"
}
}
resource aws_subnet "c_public" {
availability_zone = "${var.region}c"
cidr_block = "${var.cidr_prefix}.253.0/24"
map_public_ip_on_launch = true
vpc_id = "${aws_vpc.this_vpc.id}"
tags {
Name = "${var.vpc_name}_c_public"
}
}
# Security Groups
resource aws_security_group "default_elb" {
name = "Prod Security Group for internal Service ELBs"
description = "Prod Security Group for internal Service ELBs"
vpc_id = "${aws_vpc.this_vpc.id}"
ingress = {
cidr_blocks = ["${var.cidr_prefix}.0.0/16"]
from_port = "0"
to_port = "0"
protocol = "-1"
}
egress = {
cidr_blocks = ["0.0.0.0/0"]
from_port = "0"
to_port = "0"
protocol = "-1"
}
}
resource aws_security_group "default_host" {
name = "Prod Security Group for Service Apps"
description = "Prod Security Group for Service Apps"
vpc_id = "${aws_vpc.this_vpc.id}"
# Allow access from the elb security group
ingress = {
security_groups = [ "${aws_security_group.default_elb.id}" ]
from_port = "0"
to_port = "0"
protocol = "-1"
}
# Allow SSH on all svc app instances
ingress = {
cidr_blocks = ["0.0.0.0/0"]
from_port = "22"
to_port = "22"
protocol = "tcp"
}
# Allow consul gossip
ingress = {
cidr_blocks = ["${var.cidr_prefix}.0.0/16"]
from_port = "8300"
to_port = "8302"
protocol = "tcp"
}
ingress = {
cidr_blocks = ["${var.cidr_prefix}.0.0/16"]
from_port = "8300"
to_port = "8302"
protocol = "udp"
}
egress = {
cidr_blocks = ["0.0.0.0/0"]
from_port = "0"
to_port = "0"
protocol = "-1"
}
}
resource "aws_security_group" "nat" {
name = "nat"
description = "Allow services from the private subnet through NAT"
ingress {
from_port = 0
to_port = 65535
protocol = "tcp"
cidr_blocks = ["${aws_subnet.a_private.cidr_block}"]
}
ingress {
from_port = 0
to_port = 65535
protocol = "tcp"
cidr_blocks = ["${aws_subnet.b_private.cidr_block}"]
}
ingress {
from_port = 0
to_port = 65535
protocol = "tcp"
cidr_blocks = ["${aws_subnet.c_private.cidr_block}"]
}
vpc_id = "${aws_vpc.this_vpc.id}"
}
# NAT instances
resource "aws_instance" "nat-1a" {
ami = "ami-6975eb1e" # amzn-ami-vpc-nat-hvm-2015.03.0.x86_64-gp2
availability_zone = "eu-west-1a"
instance_type = "m4.xlarge"
key_name = "${var.aws_key_name}"
security_groups = ["${aws_security_group.nat.id}"]
subnet_id = "${aws_subnet.a_public.id}"
associate_public_ip_address = true
source_dest_check = false
}
resource "aws_eip" "nat-1a" {
instance = "${aws_instance.nat-1a.id}"
vpc = true
depends_on = ["aws_instance.nat-1a"]
}
resource "aws_cloudwatch_metric_alarm" "nat-1a_recover" {
alarm_name = "${var.region}-${var.vpc_name}-nat-1a-recover"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "1"
metric_name = "StatusCheckFailed_System"
namespace = "AWS/EC2"
period = "60"
statistic = "Minimum"
threshold = "0"
alarm_actions = [ "arn:aws:automate:${var.region}:ec2:recover" ]
dimensions = {
InstanceId = "${aws_instance.nat-1a.id}"
}
depends_on = ["aws_instance.nat-1a"]
}
resource "aws_instance" "nat-1b" {
ami = "ami-6975eb1e" # amzn-ami-vpc-nat-hvm-2015.03.0.x86_64-gp2
availability_zone = "eu-west-1b"
instance_type = "m4.xlarge"
key_name = "${var.aws_key_name}"
security_groups = ["${aws_security_group.nat.id}"]
subnet_id = "${aws_subnet.b_public.id}"
associate_public_ip_address = true
source_dest_check = false
}
resource "aws_eip" "nat-1b" {
instance = "${aws_instance.nat-1b.id}"
vpc = true
depends_on = ["aws_instance.nat-1b"]
}
resource "aws_cloudwatch_metric_alarm" "nat-1b_recover" {
alarm_name = "${var.region}-${var.vpc_name}-nat-1b-recover"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "1"
metric_name = "StatusCheckFailed_System"
namespace = "AWS/EC2"
period = "60"
statistic = "Minimum"
threshold = "0"
alarm_actions = [ "arn:aws:automate:${var.region}:ec2:recover" ]
dimensions = {
InstanceId = "${aws_instance.nat-1b.id}"
}
depends_on = ["aws_instance.nat-1b"]
}
resource "aws_instance" "nat-1c" {
ami = "ami-6975eb1e" # amzn-ami-vpc-nat-hvm-2015.03.0.x86_64-gp2
availability_zone = "eu-west-1c"
instance_type = "m4.xlarge"
key_name = "${var.aws_key_name}"
security_groups = ["${aws_security_group.nat.id}"]
subnet_id = "${aws_subnet.c_public.id}"
associate_public_ip_address = true
source_dest_check = false
}
resource "aws_eip" "nat-1c" {
instance = "${aws_instance.nat-1a.id}"
vpc = true
depends_on = ["aws_instance.nat-1c"]
}
resource "aws_cloudwatch_metric_alarm" "nat-1c_recover" {
alarm_name = "${var.region}-${var.vpc_name}-nat-1c-recover"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "1"
metric_name = "StatusCheckFailed_System"
namespace = "AWS/EC2"
period = "60"
statistic = "Minimum"
threshold = "0"
alarm_actions = [ "arn:aws:automate:${var.region}:ec2:recover" ]
dimensions = {
InstanceId = "${aws_instance.nat-1c.id}"
}
depends_on = ["aws_instance.nat-1c"]
}
###################################
# Routing tables for public subnets
###################################
resource "aws_route_table" "a_public" {
vpc_id = "${aws_vpc.this_vpc.id}"
route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.default.id}"
}
}
resource "aws_route_table" "b_public" {
vpc_id = "${aws_vpc.this_vpc.id}"
route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.default.id}"
}
}
resource "aws_route_table" "c_public" {
vpc_id = "${aws_vpc.this_vpc.id}"
route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.default.id}"
}
}
resource "aws_route_table_association" "a_public" {
subnet_id = "${aws_subnet.a_public.id}"
route_table_id = "${aws_route_table.a_public.id}"
}
resource "aws_route_table_association" "b_public" {
subnet_id = "${aws_subnet.b_public.id}"
route_table_id = "${aws_route_table.b_public.id}"
}
resource "aws_route_table_association" "c_public" {
subnet_id = "${aws_subnet.c_public.id}"
route_table_id = "${aws_route_table.c_public.id}"
}
####################################
# Routing tables for private subnets
####################################
resource "aws_route_table" "a_private" {
vpc_id = "${aws_vpc.this_vpc.id}"
route {
cidr_block = "0.0.0.0/0"
network_interface_id = "${aws_eip.nat-1a.network_interface}"
}
depends_on = ["aws_instance.nat-1a", "aws_eip.nat-1a"]
}
resource "aws_route_table" "b_private" {
vpc_id = "${aws_vpc.this_vpc.id}"
route {
cidr_block = "0.0.0.0/0"
network_interface_id = "${aws_eip.nat-1b.network_interface}"
}
depends_on = ["aws_instance.nat-1b", "aws_eip.nat-1b"]
}
resource "aws_route_table" "c_private" {
vpc_id = "${aws_vpc.this_vpc.id}"
route {
cidr_block = "0.0.0.0/0"
network_interface_id = "${aws_eip.nat-1c.network_interface}"
}
depends_on = ["aws_instance.nat-1c", "aws_eip.nat-1c"]
}
resource "aws_route_table_association" "a_private" {
subnet_id = "${aws_subnet.a_private.id}"
route_table_id = "${aws_route_table.a_private.id}"
}
resource "aws_route_table_association" "b_private" {
subnet_id = "${aws_subnet.b_private.id}"
route_table_id = "${aws_route_table.b_private.id}"
}
resource "aws_route_table_association" "c_private" {
subnet_id = "${aws_subnet.c_private.id}"
route_table_id = "${aws_route_table.c_private.id}"
}
@pll
Copy link

pll commented Oct 29, 2015

resource "aws_eip" "nat-1-eip" {
   instance   = "${aws_instance.nat-1.id}"
   vpc        = true
   depends_on = ["aws_instance.nat-1"]
}

@ralph-tice
Copy link
Author

note the update (just now) for the correct Dimension for autorecovery alarms

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