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.
This commit is contained in:
Berwn
2026-06-14 15:49:00 +07:00
parent 344f432640
commit 5864054b00
2 changed files with 38 additions and 34 deletions
+3 -34
View File
@@ -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 = [ imports = [
../../modules/hetzner-firewall.nix ../../modules/hetzner-firewall.nix
@@ -31,16 +6,10 @@ in
time.timeZone = "Etc/GMT-3"; # UTC+3 (fixed offset, no DST) time.timeZone = "Etc/GMT-3"; # UTC+3 (fixed offset, no DST)
services.timesyncd.enable = true; services.timesyncd.enable = true;
# Public Hetzner Cloud firewalls, kept in sync from this config on every # Public Hetzner Cloud firewalls, synced from this config on every deploy.
# deploy. Admin SSH is intentionally not exposed publicly: it rides the # Rules live in their own data file; see that file for the no-public-SSH note.
# ZeroTier mesh (inside UDP 9993), with emergency-access as the console
# fallback if the mesh is ever unreachable.
cnx.hetznerFirewall = { cnx.hetznerFirewall = {
enable = true; enable = true;
firewalls = { firewalls = import ../../modules/hetzner-firewall-rules.nix;
"clan-control" = [ zerotier ping ];
"clan-ns1" = dnsRules;
"clan-ns2" = dnsRules;
};
}; };
} }
+35
View File
@@ -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;
}