commit 60be52f877c7e3ded9f2faada3f74a07e3028f08
parent 8fe84450b8325bc43be2a64b520d35ca1150ee55
Author: Katja (ctucx) <git@ctu.cx>
Date: Fri, 28 Feb 2025 00:52:18 +0100
parent 8fe84450b8325bc43be2a64b520d35ca1150ee55
Author: Katja (ctucx) <git@ctu.cx>
Date: Fri, 28 Feb 2025 00:52:18 +0100
modules/linux/dns: replace `bind` with `knot`, support zone-transfer to slaves
3 files changed, 152 insertions(+), 83 deletions(-)
M
|
106
++++++++++++++++++++++++++++++++++++-------------------------------------------
M
|
128
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
diff --git a/configurations/linux/services/default.nix b/configurations/linux/services/default.nix @@ -22,7 +22,6 @@ ]; ctucxConfig.monitoring.exporters.enable = (lib.mkDefault (if (config.networking.primaryIP != "") || (config.networking.primaryIP4 != "") then true else false)); - ctucxConfig.services.dnsServer.enable = (lib.mkDefault (builtins.elem "dnsServer" config.deployment.tags)); ctucxConfig.services.resticServer.enable = (lib.mkDefault (builtins.elem "resticServer" config.deployment.tags)); } \ No newline at end of file
diff --git a/configurations/linux/services/dns.nix b/configurations/linux/services/dns.nix @@ -1,78 +1,68 @@ { nodes, config, lib, pkgs, ...}: -let - cfg = config.ctucxConfig.services.dnsServer; - -in { - - options = { - ctucxConfig.services.dnsServer = { - enable = lib.mkEnableOption "dns"; - }; - }; - - config = lib.mkIf cfg.enable { - dns = { - enable = true; - allZones = with pkgs.dns.lib.combinators; let - CAA = [ { issuerCritical = false; tag = "issue"; value = "letsencrypt.org"; } ]; - NS = [ "ns1.ctu.cx." "ns2.ctu.cx." ]; - SOA = { - nameServer = "ns1.ctu.cx."; - adminEmail = "dns@ctu.cx"; # Email address with a real `@`! - serial = lib.toInt ("2023" + "03" + "04" + "1"); - }; - - in { +{ + + dns = { + enable = lib.mkDefault (builtins.elem "dnsServer" config.deployment.tags); + primary = lib.mkDefault (config.networking.hostName == "hector"); + allZones = with pkgs.dns.lib.combinators; let + CAA = [ { issuerCritical = false; tag = "issue"; value = "letsencrypt.org"; } ]; + NS = [ "ns1.ctu.cx." "ns2.ctu.cx." ]; + SOA = { + nameServer = "ns1.ctu.cx."; + adminEmail = "dns@ctu.cx"; # Email address with a real `@`! + serial = lib.toInt ("2023" + "03" + "04" + "1"); + }; - "ctu.cx" = { - inherit SOA NS CAA; + in { + "ctu.cx" = { + inherit SOA NS CAA; - subdomains = { - ns1 = (host nodes.hector.config.networking.primaryIP4 nodes.hector.config.networking.primaryIP); - ns2 = (host nodes.wanderduene.config.networking.primaryIP4 nodes.wanderduene.config.networking.primaryIP); + subdomains = { + ns1 = (host nodes.hector.config.networking.primaryIP4 nodes.hector.config.networking.primaryIP); + ns2 = (host nodes.wanderduene.config.networking.primaryIP4 nodes.wanderduene.config.networking.primaryIP); - _atproto.TXT = [ "did=did:plc:zaeuok3fmh2pcp4cjiicku4i" ]; - }; + _atproto.TXT = [ "did=did:plc:zaeuok3fmh2pcp4cjiicku4i" ]; + test.TXT = [ "test uwu"]; }; + }; - "wifionic.de" = { - inherit SOA NS CAA; - }; + "wifionic.de" = { + inherit SOA NS CAA; + }; - "trans-agenda.de" = { - inherit SOA NS CAA; - }; + "trans-agenda.de" = { + inherit SOA NS CAA; + }; - "katja.wtf" = { - inherit SOA NS CAA; - }; + "katja.wtf" = { + inherit SOA NS CAA; + }; - "ctucx.de" = { - inherit SOA NS CAA; - }; + "ctucx.de" = { + inherit SOA NS CAA; + }; - "zuggeschmack.de" = { - inherit SOA NS CAA; - }; + "zuggeschmack.de" = { + inherit SOA NS CAA; + }; - "thein.ovh" = { - inherit SOA NS CAA; - }; + "thein.ovh" = { + inherit SOA NS CAA; + }; - "flauschehorn.sexy" = { - inherit SOA NS CAA; + "flauschehorn.sexy" = { + inherit SOA NS CAA; - MX = with mx; [ (mx 10 "rx300.kunbox.net.") ]; - TXT = [ "v=spf1 mx ~all" ]; + MX = with mx; [ (mx 10 "rx300.kunbox.net.") ]; + TXT = [ "v=spf1 mx ~all" ]; - subdomains = { - _dmarc.TXT = [ "v=DMARC1; p=quarantine; rua=mailto:hostmaster@kunbox.net; ruf=mailto:postmaster@kunsmann.eu; fo=0:d:s; adkim=r; aspf=r" ]; - "mail._domainkey".TXT = [ "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnh5Ym9PO7r+wdOIKfopvHzn3KU3qT6IlCG/gvvbmIqoeFQfRbAe3gQmcG6RcLue55cJQGhI6y2r0lm59ZeoHR40aM+VabAOlplekM7xWmoXb/9vG2OZLIqAyF4I+7GQmTN6B9keBHp9SWtDUkI0B0G9neZ5MkXJP705M0duxritqQlb4YvCZwteHiyckKcg9aE9j+GF2EEawBoVDpoveoB3+wgde3lWEUjjwKFtXNXxuN354o6jgXgPNWtIEdPMLfK/o0CaCjZNlzaLTsTegY/+67hdHFqDmm8zXO9s+Xiyfq7CVq21t7wDhQ2W1agj+up6lH82FMh5rZNxJ6XB0yQIDAQAB" ]; - }; + subdomains = { + _dmarc.TXT = [ "v=DMARC1; p=quarantine; rua=mailto:hostmaster@kunbox.net; ruf=mailto:postmaster@kunsmann.eu; fo=0:d:s; adkim=r; aspf=r" ]; + "mail._domainkey".TXT = [ "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnh5Ym9PO7r+wdOIKfopvHzn3KU3qT6IlCG/gvvbmIqoeFQfRbAe3gQmcG6RcLue55cJQGhI6y2r0lm59ZeoHR40aM+VabAOlplekM7xWmoXb/9vG2OZLIqAyF4I+7GQmTN6B9keBHp9SWtDUkI0B0G9neZ5MkXJP705M0duxritqQlb4YvCZwteHiyckKcg9aE9j+GF2EEawBoVDpoveoB3+wgde3lWEUjjwKFtXNXxuN354o6jgXgPNWtIEdPMLfK/o0CaCjZNlzaLTsTegY/+67hdHFqDmm8zXO9s+Xiyfq7CVq21t7wDhQ2W1agj+up6lH82FMh5rZNxJ6XB0yQIDAQAB" ]; }; - }; + }; };
diff --git a/modules/linux/dns.nix b/modules/linux/dns.nix @@ -10,6 +10,21 @@ in { options.dns = { enable = mkEnableOption "nix-powered DNS"; + primary = lib.mkOption { + type = lib.types.bool; + default = true; + }; + + zonesDir = lib.mkOption { + type = lib.types.str; + default = "zones"; + }; + + dataDir = lib.mkOption { + type = lib.types.str; + default = "/var/lib/knot"; + }; + # contains dns entries defined on the local host zones = mkOption { type = lib.types.attrsOf pkgs.dns.lib.types.subzone; @@ -21,12 +36,6 @@ in { type = lib.types.attrsOf pkgs.dns.lib.types.zone; default = {}; }; - - # zones not generated by nix-dns, for example secondaries - extraZones = mkOption { - type = lib.types.listOf lib.types.attrs; - default = []; - }; }; config = mkIf cfg.enable { @@ -40,24 +49,95 @@ in { ) nodes ); - systemd.services.bind.preStart = '' - mkdir -p /var/lib/bind - chown named /var/lib/bind - ''; - - services.bind = { - enable = true; - zones = ( - mapAttrsToList ( - name: zone: { - inherit name; - master = true; - slaves = [ "any" ]; - file = pkgs.dns.util."${currentSystem}".writeZone name zone; - } - ) cfg.allZones - ) ++ cfg.extraZones; - }; + environment.etc = (lib.mapAttrs' (name: zone: { + name = "${cfg.zonesDir}/${name}.zone"; + value = { source = pkgs.dns.util."${currentSystem}".writeZone name zone; }; + }) cfg.allZones); + + services.knot = { + enable = true; + keyFiles = []; + settings = { + log.syslog.any = "info"; + + server = { + automatic-acl = true; + listen = [ + (lib.mkIf (config.networking.primaryIP != "") "${config.networking.primaryIP}@53") + (lib.mkIf (config.networking.primaryIP4 != "") "${config.networking.primaryIP4}@53") + ]; + }; + + remote = [ + { + id = "primary"; + address = lib.concatLists ( + lib.mapAttrsToList ( + name: node: [ + (lib.mkIf (node.config.networking.primaryIP != "") node.config.networking.primaryIP) + (lib.mkIf (node.config.networking.primaryIP4 != "") node.config.networking.primaryIP4) + ] + ) (lib.filterAttrs (name: node: node.config.dns.enable && node.config.dns.primary) nodes) + ); + } + { + id = "secondary"; + address = lib.concatLists ( + lib.mapAttrsToList ( + name: node: [ + (lib.mkIf (node.config.networking.primaryIP != "") node.config.networking.primaryIP) + (lib.mkIf (node.config.networking.primaryIP4 != "") node.config.networking.primaryIP4) + ] + ) (lib.filterAttrs (name: node: node.config.dns.enable && !node.config.dns.primary) nodes) + ); + } + ]; + + template.default = { + storage = "${cfg.dataDir}/zones"; + zonefile-sync = -1; + zonefile-load = "difference-no-serial"; + journal-content = "all"; + notify = lib.mkIf cfg.primary "secondary"; + master = lib.mkIf (!cfg.primary) "primary"; + }; + + zone = lib.mapAttrs (name: zone: {}) cfg.allZones; + }; + }; + + systemd.tmpfiles.settings = { + dataDir."${cfg.dataDir}".d = { + group = "knot"; + user = "knot"; + mode = "770"; + age = "-"; + }; + + zones."${cfg.dataDir}/zones".d = { + group = "knot"; + user = "knot"; + mode = "770"; + age = "-"; + }; + }; + + systemd.services.knot = lib.mkIf cfg.primary { + reloadTriggers = lib.mapAttrsToList (name: zone: pkgs.dns.util."${currentSystem}".writeZone name zone) cfg.allZones; + + preStart = '' + set -euo pipefail + cp --dereference /etc/${cfg.zonesDir}/* ${cfg.dataDir}/zones + chmod -R 770 ${cfg.dataDir}/zones + ''; + + serviceConfig.ExecReload = lib.mkForce (pkgs.writeShellScript "knot-reload" '' + set -eou pipefail + cp --dereference /etc/${cfg.zonesDir}/* ${cfg.dataDir}/zones + chmod -R 770 ${cfg.dataDir}/zones + ${config.services.knot.package}/bin/knotc reload + ''); + }; }; }