Skip to content

Instantly share code, notes, and snippets.

@dstufft
Created February 16, 2017 23:46
Show Gist options
  • Save dstufft/84c20ad994d9597fa45a74622aaf8917 to your computer and use it in GitHub Desktop.
Save dstufft/84c20ad994d9597fa45a74622aaf8917 to your computer and use it in GitHub Desktop.
# US-East-1 Has 5 availability zones, and we want to split our network over all
# of them. So we will do a /19 per AZ which will give us the ability to expand
# up to 8 total AZs or to add more capacity in 3/5 of the other AZs if need be.
# If for some reason this is being run in a region with less AZs, we will just
# have more left over capacity being reserved as a spare. In addition, we will
# split our allocation within each AZ up into a /20 for all of our private
# instances, a /21 for all of our public instances, and a /21 left over for
# spare capacity. This will give us the largest block of IP addresses for our
# private tier, where most of our instances will reside, while still leaving
# spare allocation for the future.
#
# The VPC design will look like:
#
# 172.20.0.0 / 16 – VPC – 65536 IPs (172.20.0.0 – 172.20.255.255)
# 172.20.0.0/19 – Availability Zone A – 8190 IPs (172.20.0.0 – 172.20.31.255)
# 172.20.0.0/20 - Private Subnet - 4096 IPs (172.20.0.0 - 172.20.15.255)
# 172.20.16.0/21 - Public Subnet - 2046 IPs (172.20.16.0 - 172.20.23.255)
# 172.20.24.0/21 - Spare - 2046 IPs (172.20.24.0 - 172.20.31.255)
#
# 172.20.32.0/19 – Availability Zone B – 8190 IPs (172.20.32.0 – 172.20.63.255)
# 172.20.32.0/20 - Private Subnet - 4096 IPs (172.20.32.0 - 172.20.47.255)
# 172.20.48.0/21 - Public Subnet - 2046 IPs (172.20.48.0 - 172.20.55.255)
# 172.20.56.0/21 - Spare - 2046 IPs (172.20.56.0 - 172.20.63.255)
#
# 172.20.64.0/19 – Availability Zone C – 8190 IPs (172.20.64.0 – 172.20.95.255)
# 172.20.64.0/20 - Private Subnet - 4096 IPs (172.20.64.0 - 172.20.79.255)
# 172.20.80.0/21 - Public Subnet - 2046 IPs (172.20.80.0 - 172.20.87.255)
# 172.20.88.0/21 - Spare - 2046 IPs (172.20.88.0 - 172.20.95.255)
#
# 172.20.96.0/19 – Availability Zone D – 8190 IPs (172.20.96.0 – 172.20.127.255)
# 172.20.96.0/20 - Private Subnet - 4096 IPs (172.20.96.0 - 172.20.111.255)
# 172.20.112.0/21 - Public Subnet - 2046 IPs (172.20.112.0 - 172.20.119.255)
# 172.20.120.0/21 - Spare - 2046 IPs (172.20.120.0 - 172.20.127.255)
#
# 172.20.128.0/19 – Availability Zone E – 8190 IPs (172.20.128.0 – 172.20.159.255)
# 172.20.128.0/20 - Private Subnet - 4096 IPs (172.20.128.0 - 172.20.143.255)
# 172.20.144.0/21 - Public Subnet - 2046 IPs (172.20.144.0 - 172.20.151.255)
# 172.20.152.0/21 - Spare - 2046 IPs (172.20.152.0 - 172.20.159.255)
#
# 172.20.160.0/19 - Spare - 8190 IPs (172.20.160.0 - 172.20.191.255)
# 172.20.192.0/19 - Spare - 8190 IPs (172.20.192.0 - 172.20.223.255)
# 172.20.224.0/19 - Spare - 8190 IPs (172.20.224.0 - 172.20.255.255)
variable "name" { default = "cleese" }
variable "cidr" { default = "172.20.0.0/16" }
variable "vpn" { default = "172.16.0.0/24" }
data "aws_availability_zones" "available" {}
resource "aws_vpc" "main" {
cidr_block = "${var.cidr}"
tags { Name = "${var.name}" }
}
resource "aws_subnet" "public" {
vpc_id = "${aws_vpc.main.id}"
availability_zone = "${data.aws_availability_zones.available.names[count.index]}"
cidr_block = "${cidrsubnet(cidrsubnet(var.cidr, 3, count.index), 2, 2)}"
map_public_ip_on_launch = true
tags { Name = "Public Network" }
# count = "${length(data.aws_availability_zones.available.names)}"
count = 5 # When Terraform 0.9 is out, we can remove this line and uncomment the above.
}
resource "aws_subnet" "private" {
vpc_id = "${aws_vpc.main.id}"
availability_zone = "${data.aws_availability_zones.available.names[count.index]}"
cidr_block = "${cidrsubnet(cidrsubnet(var.cidr, 3, count.index), 1, 0)}"
tags { Name = "Private Network" }
# count = "${length(data.aws_availability_zones.available.names)}"
count = 5 # When Terraform 0.9 is out, we can remove this line and uncomment the above.
}
resource "aws_internet_gateway" "main" { vpc_id = "${aws_vpc.main.id}" }
resource "aws_eip" "nat" {
vpc = true
# count = "${length(data.aws_availability_zones.available.names)}"
count = 5 # When Terraform 0.9 is out, we can remove this line and uncomment the above.
}
resource "aws_nat_gateway" "nat" {
allocation_id = "${element(aws_eip.nat.*.id, count.index)}"
subnet_id = "${element(aws_subnet.public.*.id, count.index)}"
# count = "${length(data.aws_availability_zones.available.names)}"
count = 5 # When Terraform 0.9 is out, we can remove this line and uncomment the above.
}
resource "aws_route_table" "public" {
vpc_id = "${aws_vpc.main.id}"
tags { Name = "Public" }
route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.main.id}"
}
route {
cidr_block = "${var.vpn}"
instance_id = "${aws_instance.vpn.id}"
}
}
resource "aws_route_table_association" "public" {
subnet_id = "${element(aws_subnet.public.*.id, count.index)}"
route_table_id = "${aws_route_table.public.id}"
# count = "${length(data.aws_availability_zones.available.names)}"
count = 5 # When Terraform 0.9 is out, we can remove this line and uncomment the above.
}
resource "aws_route_table" "private" {
vpc_id = "${aws_vpc.main.id}"
tags { Name = "Private" }
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = "${element(aws_nat_gateway.nat.*.id, count.index)}"
}
route {
cidr_block = "${var.vpn}"
instance_id = "${aws_instance.vpn.id}"
}
# count = "${length(data.aws_availability_zones.available.names)}"
count = 5 # When Terraform 0.9 is out, we can remove this line and uncomment the above.
}
resource "aws_route_table_association" "private" {
subnet_id = "${element(aws_subnet.private.*.id, count.index)}"
route_table_id = "${element(aws_route_table.private.*.id, count.index)}"
# count = "${length(data.aws_availability_zones.available.names)}"
count = 5 # When Terraform 0.9 is out, we can remove this line and uncomment the above.
}
resource "aws_default_security_group" "default" {
vpc_id = "${aws_vpc.main.id}"
ingress {
from_port = 0
to_port = 0
protocol = -1
self = true
}
ingress {
from_port = 0
to_port = 0
protocol = -1
cidr_blocks = ["${var.vpn}"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
data "aws_ami" "vpn" {
most_recent = true
owners = ["self"]
filter {
name = "tag:image"
values = ["vpn"]
}
}
resource "aws_security_group" "vpn" {
name = "VPN"
description = "Allow VPN traffic"
vpc_id = "${aws_vpc.main.id}"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 1194
to_port = 1194
protocol = "udp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "vpn" {
ami = "${data.aws_ami.vpn.id}"
instance_type = "t2.micro"
subnet_id = "${element(aws_subnet.public.*.id, count.index)}"
vpc_security_group_ids = ["${aws_security_group.vpn.id}"]
source_dest_check = false
tags {
Name = "vpn.${count.index}"
}
root_block_device {
volume_type = "gp2"
delete_on_termination = true
}
}
# This is normally deployed by building an AMI with packer and ansible,
# but this is really the only important bit besides installing openvpn
# and dropping TLS keys and such.
user nobody
group nobody
port 1194
proto udp
dev tun
persist-key
persist-tun
server 172.16.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "route 172.20.0.0 255.255.0.0"
client-to-client
keepalive 10 120
# TLS Configuration
tls-version-min 1.2
tls-cipher TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256
tls-auth /etc/openvpn/tls-auth.key 0
ca /etc/pki/ca-trust/source/anchors/PSF_CA.pem
cert /etc/pki/tls/certs/vpn.crt
key /etc/pki/tls/private/vpn.key
dh /etc/openvpn/dh.pem
remote-cert-eku "TLS Web Client Authentication"
# HMAC
auth SHA256
# Cipher
cipher AES-256-CBC
status openvpn-status.log
verb 3
# TODO: Once OpenVPN is out, uncomment this.
# explicit-exit-notify 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment