Files
terraform-binarylane/modules/binarylane/main.tf
T
unkin-agent 975ff15b6b
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
Bootstrap gateways via a retrying wg handshake unit and guard servers against rebuilds
2026-10-12 21:57:40 +11:00

149 lines
4.8 KiB
Terraform

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
# only these destinations route over wg0; everything else (incl. SMTP) stays public
wg_allowed_ips = [
"10.10.13.1/32", # prodnxsr0020 tunnel address
"10.10.12.200/32", # management ssh client (wireguard workstation)
"198.18.200.2/32", # puppetca.k8s.syd1.au.unkin.net
"198.18.200.3/32", # puppet.k8s.syd1.au.unkin.net
"198.18.200.4/32", # artifactapi.k8s.syd1.au.unkin.net (package repos)
"198.18.200.7/32", # bind-internal resolvers
"198.18.200.17/32", # rspamd milter :11332
"198.18.25.78/32", # vault.service.consul
"198.18.26.197/32", # vault.service.consul
"198.18.27.116/32", # vault.service.consul
"198.18.28.248/32", # vault.service.consul
"198.18.29.92/32", # vault.service.consul
]
vpcs = {
syd = "10.10.14.0/24"
mel = "10.10.15.0/24"
}
gateways = {
mta1 = { region = "syd", wg_address = "10.10.13.11" }
mta2 = { region = "mel", wg_address = "10.10.13.12" }
}
}
resource "binarylane_vpc" "dmz" {
for_each = local.vpcs
name = "dmz-${each.key}"
ip_range = each.value
}
resource "wireguard_asymmetric_key" "hub" {}
resource "wireguard_asymmetric_key" "gateway" {
for_each = local.gateways
}
resource "vault_kv_secret_v2" "hub" {
mount = "kv"
name = "service/wireguard/binarylane/prodnxsr0020"
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
})
}
resource "vault_kv_secret_v2" "gateway" {
for_each = local.gateways
mount = "kv"
name = "service/wireguard/binarylane/${each.key}"
data_json = jsonencode({
private_key = wireguard_asymmetric_key.gateway[each.key].private_key
public_key = wireguard_asymmetric_key.gateway[each.key].public_key
address = "${each.value.wg_address}/24"
listen_port = local.wg_port
})
}
resource "binarylane_server" "gateway" {
for_each = local.gateways
name = "${each.key}.edge.unkin.net"
region = each.value.region
image = "alma-9"
size = "std-min"
public_ipv4_count = 1
vpc_id = binarylane_vpc.dmz[each.value.region].id
port_blocking = false
backups = false
ipv6 = false
user_data = templatefile("${path.module}/cloud-init.yaml.tftpl", {
hostname = each.key
fqdn = "${each.key}.edge.unkin.net"
wg_address = each.value.wg_address
wg_port = local.wg_port
wg_private_key = wireguard_asymmetric_key.gateway[each.key].private_key
hub_public_key = wireguard_asymmetric_key.hub.public_key
hub_endpoint = "${local.hub_endpoint}:${local.hub_port}"
allowed_ips = join(", ", local.wg_allowed_ips)
})
# 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" "gateway" {
for_each = local.gateways
server_id = binarylane_server.gateway[each.key].id
ipv4_address = binarylane_server.gateway[each.key].public_ipv4_addresses[0]
reverse_name = "${each.key}.edge.unkin.net"
}
# SSH has no public rule: management reaches sshd through wg0, which this firewall never sees.
resource "binarylane_server_firewall_rules" "gateway" {
for_each = local.gateways
server_id = binarylane_server.gateway[each.key].id
firewall_rules = [
{
description = "mail and https"
protocol = "tcp"
source_addresses = ["0.0.0.0/0"]
destination_addresses = [binarylane_server.gateway[each.key].public_ipv4_addresses[0]]
destination_ports = ["25", "465", "587", "993", "443"]
action = "accept"
},
{
description = "wireguard from home gateway"
protocol = "udp"
source_addresses = ["${local.hub_endpoint}/32"]
destination_addresses = [binarylane_server.gateway[each.key].public_ipv4_addresses[0]]
destination_ports = [tostring(local.wg_port)]
action = "accept"
},
{
description = "icmp"
protocol = "icmp"
source_addresses = ["0.0.0.0/0"]
destination_addresses = [binarylane_server.gateway[each.key].public_ipv4_addresses[0]]
action = "accept"
},
{
description = "default deny"
protocol = "all"
source_addresses = ["0.0.0.0/0"]
destination_addresses = [binarylane_server.gateway[each.key].public_ipv4_addresses[0]]
action = "drop"
},
]
}