From 29f3a531438dd1f1bbdc20c440a6c3b37c960e58 Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Mon, 12 Oct 2026 22:32:03 +1100 Subject: [PATCH] Give each vpn host its own p2p wg link to prodnxsr0020 --- README.md | 12 ++++--- modules/binarylane/cloud-init.yaml.tftpl | 6 ++-- modules/binarylane/main.tf | 46 ++++++++++++------------ modules/binarylane/outputs.tf | 15 ++++++-- 4 files changed, 46 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index f77953c..f84709c 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,10 @@ role in terraform-vault. ## Mail edge Each DMZ VPC (`syd`, `mel`) holds a postfix edge host and a vpn host. The vpn -host runs wg0 to prodnxsr0020 and forwards the lab routes for its VPC; the edge -host reaches the lab through it and has no WireGuard. wg0 is bootstrapped from -a key in `user_data` (readable via the BinaryLane API); Puppet then manages it -from Vault, so rotate by replacing `wireguard_asymmetric_key.vpn` here and -letting Puppet roll it out. +host runs wg0 as a /31 point-to-point link to its own prodnxsr0020 interface +(`wg-syd` on 51821, `wg-mel` on 51822; `router_links` output) and forwards the +lab routes for its VPC; the edge host reaches the lab through it and has no +WireGuard. Router keys live at `kv/service/wireguard/binarylane/prodnxsr0020-`. +wg0 is bootstrapped from a key in `user_data` (readable via the BinaryLane +API); Puppet then manages it from Vault, so rotate by replacing +`wireguard_asymmetric_key.vpn` here and letting Puppet roll it out. diff --git a/modules/binarylane/cloud-init.yaml.tftpl b/modules/binarylane/cloud-init.yaml.tftpl index 15cac91..e86da2b 100644 --- a/modules/binarylane/cloud-init.yaml.tftpl +++ b/modules/binarylane/cloud-init.yaml.tftpl @@ -9,13 +9,13 @@ write_files: permissions: "0600" content: | [Interface] - Address = ${vpn.address}/24 + Address = ${vpn.address} ListenPort = ${vpn.port} PrivateKey = ${vpn.private_key} [Peer] - PublicKey = ${vpn.hub_key} - Endpoint = ${vpn.hub} + PublicKey = ${vpn.router_key} + Endpoint = ${vpn.router} AllowedIPs = ${vpn.allowed_ips} PersistentKeepalive = 25 - path: /etc/sysctl.d/90-ip-forward.conf diff --git a/modules/binarylane/main.tf b/modules/binarylane/main.tf index 36ab260..0f9ef76 100644 --- a/modules/binarylane/main.tf +++ b/modules/binarylane/main.tf @@ -1,10 +1,8 @@ locals { - # home gateway (prodnxsr0020) end of the mail DMZ tunnel - hub_endpoint = "103.216.191.185" - hub_port = 51821 - hub_address = "10.10.13.1" - wg_port = 51820 - domain = "main.unkin.net" + # 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 = [ @@ -18,8 +16,8 @@ locals { } vpns = { - ausyd2nxvm2131 = { region = "syd", vpc_ip = "10.10.14.11", wg_address = "10.10.13.11" } - aumel1nxvm2133 = { region = "mel", vpc_ip = "10.10.15.11", wg_address = "10.10.13.12" } + ausyd2nxvm2131 = { region = "syd", vpc_ip = "10.10.14.11", router_port = 51821, router_address = "10.10.13.0", wg_address = "10.10.13.1" } + aumel1nxvm2133 = { region = "mel", vpc_ip = "10.10.15.11", router_port = 51822, router_address = "10.10.13.2", wg_address = "10.10.13.3" } } edges = { @@ -46,20 +44,24 @@ resource "binarylane_vpc_route_entries" "dmz" { }] } -resource "wireguard_asymmetric_key" "hub" {} +resource "wireguard_asymmetric_key" "router" { + for_each = local.vpns +} resource "wireguard_asymmetric_key" "vpn" { for_each = local.vpns } -resource "vault_kv_secret_v2" "hub" { +resource "vault_kv_secret_v2" "router" { + for_each = local.vpns + mount = "kv" - name = "service/wireguard/binarylane/prodnxsr0020" + name = "service/wireguard/binarylane/prodnxsr0020-${each.value.region}" data_json = jsonencode({ - private_key = wireguard_asymmetric_key.hub.private_key - public_key = wireguard_asymmetric_key.hub.public_key - address = "${local.hub_address}/24" - listen_port = local.hub_port + 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 }) } @@ -71,7 +73,7 @@ resource "vault_kv_secret_v2" "vpn" { 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}/24" + address = "${each.value.wg_address}/31" listen_port = local.wg_port }) } @@ -94,12 +96,12 @@ resource "binarylane_server" "vpn" { hostname = each.key fqdn = "${each.key}.${local.domain}" vpn = { - address = each.value.wg_address + address = "${each.value.wg_address}/31" port = local.wg_port private_key = wireguard_asymmetric_key.vpn[each.key].private_key - hub_key = wireguard_asymmetric_key.hub.public_key - hub = "${local.hub_endpoint}:${local.hub_port}" - allowed_ips = join(", ", concat(["${local.hub_address}/32"], local.lab_routes)) + 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, ["${each.value.router_address}/32"])) } routes = null }) @@ -197,9 +199,9 @@ resource "binarylane_server_firewall_rules" "vpn" { server_id = binarylane_server.vpn[each.key].id firewall_rules = [ { - description = "wireguard from home gateway" + description = "wireguard from prodnxsr0020" protocol = "udp" - source_addresses = ["${local.hub_endpoint}/32"] + 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" diff --git a/modules/binarylane/outputs.tf b/modules/binarylane/outputs.tf index a45f9ea..e04854e 100644 --- a/modules/binarylane/outputs.tf +++ b/modules/binarylane/outputs.tf @@ -16,7 +16,16 @@ output "hosts" { ) } -output "hub" { - description = "prodnxsr0020 end of the tunnels." - value = { address = local.hub_address, public_key = wireguard_asymmetric_key.hub.public_key, listen_port = local.hub_port } +output "router_links" { + description = "Per-region p2p wg link as prodnxsr0020 sees it; consumed by its Puppet config." + value = { for k, v in local.vpns : v.region => { + interface = "wg-${v.region}" + listen_port = v.router_port + router_address = "${v.router_address}/31" + peer_address = v.wg_address + peer_public_key = wireguard_asymmetric_key.vpn[k].public_key + peer_endpoint = "${binarylane_server.vpn[k].public_ipv4_addresses[0]}:${local.wg_port}" + vpc_cidr = local.vpcs[v.region] + private_key_vault_path = "kv/${vault_kv_secret_v2.router[k].name}" + } } }