Skip to content

Instantly share code, notes, and snippets.

@jwieringa
Forked from ralph-tice/gist:3d6e5b2076cbc2900aaa
Created October 30, 2015 00:39
Show Gist options
  • Save jwieringa/4c35a4fe9676df78afcd to your computer and use it in GitHub Desktop.
Save jwieringa/4c35a4fe9676df78afcd 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 = {
Name = "InstanceId"
Value = "${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 = {
Name = "InstanceId"
Value = "${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 = {
Name = "InstanceId"
Value = "${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}"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment