{ self, pkgs, lib, config, dns, ... }: let secondary = "185.181.104.96"; domain = config.networking.domain; # fetches all VgetVirtualHosts from the caddy config getVirtualHosts = hostname: map (name: builtins.substring 0 (builtins.stringLength name - (builtins.stringLength domain + 1)) name) (builtins.attrNames self.nixosConfigurations."${hostname}".config.services.caddy.virtualHosts); # generate CNAMES from caddy service to host genCNAMEs = hostname: lib.attrsets.genAttrs (getVirtualHosts hostname) (_label: { CNAME = [ "${hostname}.${domain}." ]; }); # generate Bind config to allow dynamic updates genKeyGrants = hostname: builtins.foldl' (x: y: x + "grant caddy name _acme-challenge." + y + ".${domain} txt;\n") "" (lib.lists.remove ":2018" (getVirtualHosts hostname)); zonefile = with dns.lib.combinators; pkgs.writeText "rfive.de.zone.txt" (dns.lib.toString domain { TTL = 3600; SOA = let modulo = number: mod: (number - ((number / mod) * mod)); in { nameServer = "ns.rfive.de."; adminEmail = "hostmaster@rfive.de"; serial = lib.strings.toInt (builtins.substring 0 8 self.sourceInfo.lastModifiedDate + toString ((modulo self.sourceInfo.lastModified 86400) / 864)); # serial = 2025051143; refresh = 10800; retry = 3600; expire = 604800; minimum = 3600; }; NS = [ "ns.inwx.de." "ns2.inwx.de." "ns3.inxw.eu." ]; A = [ "23.88.121.184" ]; AAAA = [ "2a01:4f8:c012:49de::1" ]; CAA = letsEncrypt "ca@rfive.de"; MX = [{ preference = 1; exchange = "mail.rfive.de."; }]; TXT = [ (spf.soft [ "mx" ]) ]; subdomains = let # generate ACME challenge recorsd for every VirtualHost genACMECNAMEs = hostname: lib.attrsets.genAttrs (getVirtualHosts hostname) (_label: { subdomains._acme-challenge.CNAME = [ "challenge.acme.${domain}." ]; }); # fuckery to merge the generated attribute lists mergeRecords = recordList: lib.attrsets.mapAttrs (_host: records: lib.attrsets.mergeAttrsList records) (lib.attrsets.zipAttrs recordList); in lib.attrsets.mergeAttrsList [ rec { nuc = { A = [ "141.30.227.6" ]; }; avm = { A = [ "141.30.30.20" ]; }; falkenstein = { A = [ "23.88.121.184" ]; AAAA = [ "2a01:4f8:c012:49de::1" ]; }; ns = falkenstein; mail = falkenstein; _dmarc.TXT = [ "v=DMARC1; p=none; adkim=s; fo=1; rua=mailto:dmarc@rfive.de; ruf=mailto:dmarc@rfive.de" ]; _domainkey.subdomains.rspamd.TXT = [ "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDoirUMubro4nlmY6a8JMwK9QB2agAXiJzexDU/7ba6KCggONfoSTfUHlrM/XeM1GG/9oKpngApxDPP97adJuxc8/EELyo4HjTyYD8GBFZhg0AN7V8IPaJ1o5k6dGDk8ZLh41ZCnlAVWkhVSKs5pYtzkrlJIfUSzyuoe8nuFsVe3QIDAQAB" ]; } (builtins.removeAttrs (genCNAMEs "nuc") ([ ":2018" ] ++ (builtins.filter (host: lib.strings.hasInfix "vpn" host) (getVirtualHosts "nuc")))) (builtins.removeAttrs (genCNAMEs "falkenstein") ([ ":2018" "mail" ])) # (mergeRecords [ # (builtins.removeAttrs (genCNAMEs "nuc") ([ ":2018" ] ++ (builtins.filter (host: lib.strings.hasInfix "vpn" host) (getVirtualHosts "nuc")))) # (builtins.removeAttrs (genACMECNAMEs "nuc") ([ ":2018" ])) # ]) # (mergeRecords [ # (builtins.removeAttrs (genCNAMEs "falkenstein") ([ ":2018" "mail" ])) # (builtins.removeAttrs (genACMECNAMEs "falkenstein") ([ ":2018" "mail" ])) # ]) # (builtins.removeAttrs (genACMECNAMEs "fujitsu") ([ ":2018" ])) ]; }); in { age.secrets.acme-dns = { file = ../../../../secrets/falkenstein/acme-dns.age; owner = "named"; }; services.bind = rec { enable = true; directory = "/var/lib/bind"; extraConfig = '' dnssec-policy "split-keys" { keys { ksk lifetime unlimited algorithm ecdsap256sha256; zsk lifetime 60d algorithm ecdsap256sha256; }; publish-safety 1d; retire-safety 1d; }; include "${config.age.secrets.acme-dns.path}"; ''; zones = { "rfive.de" = { master = true; slaves = [ secondary ]; extraConfig = '' also-notify {${secondary};}; dnssec-policy split-keys; inline-signing yes; serial-update-method date; update-policy { grant caddy name _acme-challenge.cinema.vpn.rfive.de. txt; ${genKeyGrants "nuc"} ${genKeyGrants "falkenstein"} ${genKeyGrants "fujitsu"} }; ''; file = "${directory}/rfive.de.zone.txt"; }; }; }; systemd.services.bind-zonefile = { script = '' # copy the file manually to its destination since signing requires a writable directory ${pkgs.coreutils}/bin/cp ${zonefile} ${config.services.bind.directory}/rfive.de.zone.txt ${pkgs.coreutils}/bin/chown named:named ${config.services.bind.directory}/rfive.de.zone.txt ''; }; systemd.services.bind = { after = [ "bind-zonefile.service" ]; requires = [ "bind-zonefile.service" ]; }; networking.firewall.extraInputRules = '' ip saddr ${secondary}/32 tcp dport 53 accept comment "Allow DNS AXFR access from INWX Servers" ip saddr ${secondary}/32 udp dport 53 accept comment "Allow DNS access from INWX Servers" ''; environment.systemPackages = with pkgs; [ dig.out ]; }