From 5864054b008496ff90ecbbec7626c303d8d85100 Mon Sep 17 00:00:00 2001 From: Berwn Date: Sun, 14 Jun 2026 15:49:00 +0700 Subject: [PATCH] Move Hetzner firewall rules into a separate data file Extract the per-firewall rule data out of control's configuration into modules/hetzner-firewall-rules.nix, imported like the DNS domains list. The evaluated rules are unchanged. --- machines/control/configuration.nix | 37 +++--------------------------- modules/hetzner-firewall-rules.nix | 35 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 34 deletions(-) create mode 100644 modules/hetzner-firewall-rules.nix diff --git a/machines/control/configuration.nix b/machines/control/configuration.nix index 88455cc..8b53331 100644 --- a/machines/control/configuration.nix +++ b/machines/control/configuration.nix @@ -1,28 +1,3 @@ -let - world = [ "0.0.0.0/0" "::/0" ]; - - zerotier = { - direction = "in"; - protocol = "udp"; - port = "9993"; - source_ips = world; - description = "ZeroTier"; - }; - - ping = { - direction = "in"; - protocol = "icmp"; - source_ips = world; - description = "ICMP (ping / PMTUD)"; - }; - - dnsRules = [ - { direction = "in"; protocol = "udp"; port = "53"; source_ips = world; description = "DNS (UDP)"; } - { direction = "in"; protocol = "tcp"; port = "53"; source_ips = world; description = "DNS (TCP)"; } - zerotier - ping - ]; -in { imports = [ ../../modules/hetzner-firewall.nix @@ -31,16 +6,10 @@ in time.timeZone = "Etc/GMT-3"; # UTC+3 (fixed offset, no DST) services.timesyncd.enable = true; - # Public Hetzner Cloud firewalls, kept in sync from this config on every - # deploy. Admin SSH is intentionally not exposed publicly: it rides the - # ZeroTier mesh (inside UDP 9993), with emergency-access as the console - # fallback if the mesh is ever unreachable. + # Public Hetzner Cloud firewalls, synced from this config on every deploy. + # Rules live in their own data file; see that file for the no-public-SSH note. cnx.hetznerFirewall = { enable = true; - firewalls = { - "clan-control" = [ zerotier ping ]; - "clan-ns1" = dnsRules; - "clan-ns2" = dnsRules; - }; + firewalls = import ../../modules/hetzner-firewall-rules.nix; }; } diff --git a/modules/hetzner-firewall-rules.nix b/modules/hetzner-firewall-rules.nix new file mode 100644 index 0000000..b157881 --- /dev/null +++ b/modules/hetzner-firewall-rules.nix @@ -0,0 +1,35 @@ +# Hetzner Cloud firewall rules, keyed by firewall name. Imported by +# machines/control/configuration.nix and fed to cnx.hetznerFirewall.firewalls. +# +# Public SSH (22) is intentionally absent: admin access rides the ZeroTier mesh +# (inside UDP 9993), with emergency-access as the console fallback. +let + world = [ "0.0.0.0/0" "::/0" ]; + + zerotier = { + direction = "in"; + protocol = "udp"; + port = "9993"; + source_ips = world; + description = "ZeroTier"; + }; + + ping = { + direction = "in"; + protocol = "icmp"; + source_ips = world; + description = "ICMP (ping / PMTUD)"; + }; + + dnsRules = [ + { direction = "in"; protocol = "udp"; port = "53"; source_ips = world; description = "DNS (UDP)"; } + { direction = "in"; protocol = "tcp"; port = "53"; source_ips = world; description = "DNS (TCP)"; } + zerotier + ping + ]; +in +{ + "clan-control" = [ zerotier ping ]; + "clan-ns1" = dnsRules; + "clan-ns2" = dnsRules; +}