So I’ve spent some time to build out a Stratum 2 NTP server module in Terraform. It’s good to and be deployed. Now I just need a network to attach it to. Given my experience of trying to get hosts within our protected VPC to access NTP sources, instances of this module will be accessible to our systems over the public internet to a Stratum 3 edge for each cluster. Therefore most of our systems will be a Stratum 4 for sync with a low latency connection to their upstreams. I was originally on the fence regarding building a Stratum 2 cluster, however after throwing some conservative figures around I quickly realized we met the 200 client suggested minimum for attaching yet another Stratum 2 service.

Taking a quick look at prior art already out there: a majority of the modules are concerned with both public and private subnets hwere I’m strictly concerned with only having a public network. Having additional private subnets is a bit overkill for this particular use case. In the future more will probably be useful.

Overview of design

Each VPC is regional scoped with a 0.0.0.0/16 network mask for IPv4. I generally use 4 bits ot the left of the divide to represent the region the network is running in. Just in case we ever need to peer VPC_s across regions. This if the first instance of an IPv6 network I’ll be setting up through _Terraform however AWS assigns IPv6 prefixes automagically, which is a bit unfortunate for dealing with VPC peering rules, but meh. But to make matters worse these are allocated out of AWS’s IPv6 blocks using a ::/56 prefix. This leaves 8 network bits for each VPC. This restriction should not really impact this VPC but a bit annoying as I usually use a sparse IPv4 address space to reserve for future expansion.

Anyway, really we only need one subnet with an internet gateway. This subnet should have an internet gateway and boom, we should be done.

Public VPC construction

To construct the public portions of a VPC you need three elements. First an internet gateway which will provide IPv4 and IPv6 transport to the general internet. Second the routing tables need to set the default route (0.0.0.0/0 for IPv4 and ::/0 for IPv6) to target the internet gateway. Last each subnet to be exposed must additionally set the auto-assign flags for the correct protocols. A minimal implementation for Terraform may look like the following:

resource "aws_vpc" "vpc_public" {
  cidr_block = "192.168.0.0/16"
  assign_generated_ipv6_cidr_block = true
  
  tags {
    Name = "example-network"
  }
}

resource "aws_internet_gateway" "public_access" {
  vpc_id = "${aws_vpc.public_vpc.id}"
  tags {
    Name = "example-gateway"
  }
}

resource "aws_route" "internet_route_ipv4" {
  route_table_id = "${aws_vpc.public_vpc.default_route_table_id}"
  destination_cidr_block = "0.0.0.0/0"
  gateway_id = "${aws_internet_gateway.public_access.id}"
}

resource "aws_route" "internet_route_ipv6" {
  route_table_id = "${aws_vpc.public_vpc.default_route_table_id}"
  destination_ipv6_cidr_block = "::/0"
  gateway_id = "${aws_internet_gateway.public_access.id}"
}


resource "aws_subnet" "az-subnet" {
  vpc_id = "${aws_vpc.public_vpc.id}"
  map_public_ip_on_launch = true
  assign_ipv6_address_on_creation = true

  cidr_block = "${cidrsubnet(aws_vpc.public_vpc.cidr_block, 8, 1)}"
  ipv6_cidr_block = "${cidrsubnet(aws_vpc.public_vpc.ipv6_cidr_block, 8, 1)}"

  tags {
    Name = "example-subnet-${count.index}"
  }
}