locals { # home WAN address of prodnxsr0020, which terminates one wg link per vpn host router_endpoint = "103.216.191.185" wg_port = 51820 domain = "main.unkin.net" # lab destinations reached through each region's vpn host; SMTP stays on the public internet lab_routes = [ "198.18.0.0/16", "10.10.12.200/32", # management ssh host ] # ospf hellos over the p2p links; wg has one peer per interface so this routes to it ospf_allspf = "224.0.0.5/32" vpcs = { syd = "172.18.30.0/24" mel = "172.18.31.0/24" bne = "172.18.32.0/24" } vpns = { ausyd2nxvm2131 = { region = "syd", vpc_ip = "172.18.30.11", router_port = 51821, router_address = "198.18.2.176", wg_address = "198.18.2.177", loopback = "198.18.2.161" } aumel1nxvm2133 = { region = "mel", vpc_ip = "172.18.31.11", router_port = 51823, router_address = "198.18.2.180", wg_address = "198.18.2.181", loopback = "198.18.2.163" } aubne1nxvm2133 = { region = "bne", vpc_ip = "172.18.32.11", router_port = 51822, router_address = "198.18.2.178", wg_address = "198.18.2.179", loopback = "198.18.2.162" } } edges = { ausyd2nxvm2130 = { region = "syd", vpc_ip = "172.18.30.10", vpn = "ausyd2nxvm2131", ptr = "mta1.edge.unkin.net" } aumel1nxvm2132 = { region = "mel", vpc_ip = "172.18.31.10", vpn = "aumel1nxvm2133", ptr = "mta2.edge.unkin.net" } aubne1nxvm2132 = { region = "bne", vpc_ip = "172.18.32.10", vpn = "aubne1nxvm2133", ptr = "mta2.edge.unkin.net" } } # regions whose servers are built; mel is out of stock at BinaryLane enabled_regions = ["syd", "bne"] enabled_vpns = { for k, v in local.vpns : k => v if contains(local.enabled_regions, v.region) } enabled_edges = { for k, v in local.edges : k => v if contains(local.enabled_regions, v.region) } } resource "binarylane_vpc" "dmz" { for_each = local.vpcs name = "dmz-${each.key}" ip_range = each.value } resource "binarylane_vpc_route_entries" "dmz" { for_each = local.enabled_vpns vpc_id = binarylane_vpc.dmz[each.value.region].id route_entries = [for dst in local.lab_routes : { description = "lab via ${each.key}" destination = dst router = binarylane_server.vpn[each.key].private_ipv4_addresses[0] }] } resource "wireguard_asymmetric_key" "router" { for_each = local.vpns } resource "wireguard_asymmetric_key" "vpn" { for_each = local.vpns } resource "vault_kv_secret_v2" "router" { for_each = local.vpns mount = "kv" name = "service/wireguard/binarylane/prodnxsr0020-${each.value.region}" data_json = jsonencode({ private_key = wireguard_asymmetric_key.router[each.key].private_key public_key = wireguard_asymmetric_key.router[each.key].public_key address = "${each.value.router_address}/31" listen_port = each.value.router_port }) } resource "vault_kv_secret_v2" "vpn" { for_each = local.vpns mount = "kv" name = "service/wireguard/binarylane/${each.key}" data_json = jsonencode({ private_key = wireguard_asymmetric_key.vpn[each.key].private_key public_key = wireguard_asymmetric_key.vpn[each.key].public_key address = "${each.value.wg_address}/31" listen_port = local.wg_port }) } resource "binarylane_server" "vpn" { for_each = local.enabled_vpns name = "${each.key}.${local.domain}" region = each.value.region image = "alma-9" size = "std-min" public_ipv4_count = 1 vpc_id = binarylane_vpc.dmz[each.value.region].id vpc_ipv4_address = each.value.vpc_ip source_and_destination_check = false backups = false ipv6 = false user_data = templatefile("${path.module}/cloud-init.yaml.tftpl", { hostname = each.key fqdn = "${each.key}.${local.domain}" vpn = { address = "${each.value.wg_address}/31" loopback = "${each.value.loopback}/32" routes = local.lab_routes src = each.value.wg_address port = local.wg_port private_key = wireguard_asymmetric_key.vpn[each.key].private_key router_key = wireguard_asymmetric_key.router[each.key].public_key router = "${local.router_endpoint}:${each.value.router_port}" allowed_ips = join(", ", concat(local.lab_routes, [local.ospf_allspf])) } routes = null }) # user_data/image changes reinstall the server in place, wiping its disk lifecycle { ignore_changes = [user_data, image] prevent_destroy = true } } resource "binarylane_server" "edge" { for_each = local.enabled_edges name = "${each.key}.${local.domain}" region = each.value.region image = "alma-9" size = "std-min" public_ipv4_count = 1 vpc_id = binarylane_vpc.dmz[each.value.region].id vpc_ipv4_address = each.value.vpc_ip port_blocking = false backups = false ipv6 = false user_data = templatefile("${path.module}/cloud-init.yaml.tftpl", { hostname = each.key fqdn = "${each.key}.${local.domain}" vpn = null routes = { vpc = local.vpcs[each.value.region] list = join(", ", [ for dst in local.lab_routes : "${dst} ${local.vpns[each.value.vpn].vpc_ip} src=${each.value.vpc_ip}" ]) } }) # user_data/image changes reinstall the server in place, wiping its disk lifecycle { ignore_changes = [user_data, image] prevent_destroy = true } } resource "binarylane_server_reverse_name" "edge" { for_each = local.enabled_edges server_id = binarylane_server.edge[each.key].id ipv4_address = binarylane_server.edge[each.key].public_ipv4_addresses[0] reverse_name = each.value.ptr } resource "binarylane_server_firewall_rules" "edge" { for_each = local.enabled_edges server_id = binarylane_server.edge[each.key].id firewall_rules = [ { description = "smtp" protocol = "tcp" source_addresses = ["0.0.0.0/0"] destination_addresses = [binarylane_server.edge[each.key].public_ipv4_addresses[0], each.value.vpc_ip] destination_ports = ["25"] action = "accept" }, { description = "ssh from the lab via ${each.value.vpn}" protocol = "tcp" source_addresses = ["${local.vpns[each.value.vpn].vpc_ip}/32", "10.10.12.200/32"] destination_addresses = [each.value.vpc_ip] destination_ports = ["22"] action = "accept" }, { description = "icmp" protocol = "icmp" source_addresses = ["0.0.0.0/0"] destination_addresses = [binarylane_server.edge[each.key].public_ipv4_addresses[0], each.value.vpc_ip] action = "accept" }, { description = "default deny" protocol = "all" source_addresses = ["0.0.0.0/0"] destination_addresses = [binarylane_server.edge[each.key].public_ipv4_addresses[0], each.value.vpc_ip] action = "drop" }, ] } # SSH has no rule: management reaches sshd through wg0, which this firewall never sees. resource "binarylane_server_firewall_rules" "vpn" { for_each = local.enabled_vpns server_id = binarylane_server.vpn[each.key].id firewall_rules = [ { description = "wireguard from prodnxsr0020" protocol = "udp" source_addresses = ["${local.router_endpoint}/32"] destination_addresses = [binarylane_server.vpn[each.key].public_ipv4_addresses[0], each.value.vpc_ip] destination_ports = [tostring(local.wg_port)] action = "accept" }, { description = "forward dmz to lab" protocol = "all" source_addresses = [local.vpcs[each.value.region]] destination_addresses = local.lab_routes action = "accept" }, { description = "icmp" protocol = "icmp" source_addresses = ["0.0.0.0/0"] destination_addresses = [binarylane_server.vpn[each.key].public_ipv4_addresses[0], each.value.vpc_ip] action = "accept" }, { description = "default deny" protocol = "all" source_addresses = ["0.0.0.0/0"] destination_addresses = [binarylane_server.vpn[each.key].public_ipv4_addresses[0], each.value.vpc_ip] action = "drop" }, ] }