Files
terraform-binarylane/modules/binarylane/main.tf
T
unkin-agent cc72e6c8d2
ci/woodpecker/pr/plan Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Route 198.18.0.0/16 and the management host through the vpn hosts
2026-10-12 22:13:01 +11:00

230 lines
7.3 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
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
]
vpcs = {
syd = "10.10.14.0/24"
mel = "10.10.15.0/24"
}
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" }
}
edges = {
ausyd2nxvm2130 = { region = "syd", vpc_ip = "10.10.14.10", vpn = "ausyd2nxvm2131", ptr = "mta1.edge.unkin.net" }
aumel1nxvm2132 = { region = "mel", vpc_ip = "10.10.15.10", vpn = "aumel1nxvm2133", ptr = "mta2.edge.unkin.net" }
}
}
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.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" "hub" {}
resource "wireguard_asymmetric_key" "vpn" {
for_each = local.vpns
}
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" "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}/24"
listen_port = local.wg_port
})
}
resource "binarylane_server" "vpn" {
for_each = local.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
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))
}
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.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.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.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.vpns
server_id = binarylane_server.vpn[each.key].id
firewall_rules = [
{
description = "wireguard from home gateway"
protocol = "udp"
source_addresses = ["${local.hub_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"
},
]
}