{ config, lib, pkgs, ... }: with lib; let cfg = config.fudo.services.nexus; hostname = config.instance.hostname; domainName = config.fudo.hosts."${hostname}".domain; domain = config.fudo.domains."${domainName}"; siteName = config.fudo.hosts."${hostname}".site; site = config.fudo.sites."${siteName}"; hostNexusDomainList = host: let domainName = config.fudo.hosts."${host}".domain; domain = config.fudo.domains."${domainName}"; siteName = config.fudo.hosts."${host}".site; site = config.fudo.sites."${siteName}"; in unique (domain.nexus.domains ++ site.nexus.domains); isEmpty = lst: lst == [ ]; localNexusDomains = getAttrs (hostNexusDomainList hostname) (listKeys config.fudo.nexus.domains); isServer = let servers = concatMap (domainOpts: domainOpts.servers) (attrValues config.fudo.nexus.domains); in elem hostname servers; isDnsServer = let servers = concatMap (domainOpts: domainOpts.dns-servers) (attrValues config.fudo.nexus.domains); in elem hostname servers; isDatabase = hostname == domain.postgresql-server; enableClient = !isEmpty (hostNexusDomainList hostname); enable = isServer || isDnsServer || isDatabase || enableClient; servedDomains = filterAttrs (_: domainOpts: (elem hostname domainOpts.servers) || (elem hostname domainOpts.dns-servers)) config.fudo.nexus.domains; clientHosts = filter (hostname: !isEmpty (intersectLists (hostNexusDomainList hostname) (attrNames servedDomains))) (attrNames config.fudo.hosts); hostSecrets = config.fudo.secrets.host-secrets."${hostname}"; hostFqdn = hostname: "${hostname}.${domainName}"; databaseName = "nexus_dns"; serverUser = "nexus_server"; dnsServerUser = "nexus_dns"; concatMapAttrsToList = f: as: concatLists (mapAttrsToList f as); genServerRecords = name: domain: servers: imap0 (i: host: { inherit host domain; alias = "${name}${toString i}"; }) servers; serverList = concatMapAttrsToList (domain: domainOpts: genServerRecords "nexus-" domain domainOpts.servers) config.fudo.nexus.domains; dnsServerList = concatMapAttrsToList (domain: domainOpts: genServerRecords "ns" domain domainOpts.dns-servers) config.fudo.nexus.domains; genSshfp = path: pkgs.stdenv.mkDerivation { name = "sshfp-${baseNameOf path}"; buildInputs = with pkgs; [ openssh ]; phases = [ "installPhase" ]; installPhase = "ssh-keygen -r PLACEHOLDER -f ${path} | sed 's/PLACEHOLDER IN SSHFP //' > $out"; }; in { options.fudo.services.nexus.dns-server = with types; { listen-addresses = mkOption { type = nullOr (listOf str); description = "Listen addresses. Defaults to 0.0.0.0 (i.e. all addresses)."; default = null; }; }; config = mkIf enable { nexus = { database = { database = databaseName; host = pkgs.lib.getDomainPostgresqlServer domainName; }; domains = mapAttrs (domain: domainOpts: { admin = "admin@${domain}"; inherit (domainOpts) gssapi-realm; trusted-networks = domainOpts.trusted-networks ++ config.instance.local-networks; # aliases = let # mkAlias = { host, alias, ... }: # nameValuePair alias (pkgs.lib.getHostFqdn host); # domainRecords = filter (record: record.domain == domain) serverList; # in listToAttrs (map mkAlias domainRecords); nameservers = let domainNs = filter (record: record.domain == domain) dnsServerList; mkNsRecord = { alias, host, ... }: nameValuePair alias { ipv4-address = pkgs.lib.getHostIpv4 host; ipv6-address = pkgs.lib.getHostIpv6 host; }; in listToAttrs (map mkNsRecord domainNs); records = let domainServers = filter (record: record.domain == domain) serverList; mkHostRecords = { host, alias, ... }: let ipv4-address = pkgs.lib.getHostIpv4 host; ipv6-address = pkgs.lib.getHostIpv6 host; in (optional (ipv4-address != null) { name = "${alias}.${domain}"; type = "A"; content = ipv4-address; }) ++ (optional (ipv6-address != null) { name = "${alias}.${domain}"; type = "AAAA"; content = ipv6-address; }); in domainOpts.records ++ (concatMap mkHostRecords domainServers); }) servedDomains; client = { enable = enableClient; inherit hostname; verbose = true; domains = unique (domain.nexus.domains ++ site.nexus.domains); hmac-key-file = hostSecrets.nexus-key.target-file; servers = let localDomains = hostNexusDomainList hostname; in map ({ domain, alias, ... }: "${alias}.${domain}") (filter ({ domain, ... }: elem domain localDomains) serverList); ssh-key-files = map (key: key.path) config.services.openssh.hostKeys; }; server = { enable = isServer; verbose = true; client-keys-file = hostSecrets.nexus-client-keys.target-file; hostnames = let hostServerRecords = filter ({ host, ... }: host == hostname) serverList; in map ({ domain, alias, ... }: "${alias}.${domain}") hostServerRecords; database = { user = serverUser; password-file = hostSecrets.nexus-server-passwd.target-file; }; }; dns-server = { enable = isDnsServer; enable-dnssec = true; listen-addresses = mkIf (cfg.dns-server.listen-addresses != null) cfg.dns-server.listen-addresses; database = { user = dnsServerUser; password-file = hostSecrets.nexus-dns-server-passwd.target-file; }; }; }; fudo = { secrets.host-secrets."${hostname}" = { nexus-client-keys = mkIf isServer { source-file = let clientKeyFiles = filterAttrs (hostname: _: elem hostname clientHosts) config.fudo.secrets.files.nexus-hmacs; clientKeys = mapAttrs (_: filename: readFile filename) clientKeyFiles; in pkgs.writeText "nexus-client-keys.json" (builtins.toJSON clientKeys); target-file = "/run/nexus/client-keys.json"; }; nexus-key = mkIf enableClient { source-file = config.fudo.secrets.files.nexus-hmacs."${hostname}"; target-file = "/run/nexus/client.key"; }; nexus-server-passwd = mkIf isServer { source-file = pkgs.lib.passwd.stablerandom-passwd-file "nexus-server-passwd" "nexus-server-${config.instance.build-seed}"; target-file = "/run/nexus/server-db.passwd"; }; postgres-nexus-server-passwd = mkIf isDatabase { source-file = pkgs.lib.passwd.stablerandom-passwd-file "nexus-server-passwd" "nexus-server-${config.instance.build-seed}"; target-file = "/run/nexus/server-db.passwd"; user = "postgres"; }; nexus-dns-server-passwd = mkIf isDnsServer { source-file = pkgs.lib.passwd.stablerandom-passwd-file "nexus-dns-server-passwd" "nexus-dns-server-${config.instance.build-seed}"; target-file = "/run/nexus/dns-server-db.passwd"; }; postgres-nexus-dns-server-passwd = mkIf isDatabase { source-file = pkgs.lib.passwd.stablerandom-passwd-file "nexus-dns-server-passwd" "nexus-dns-server-${config.instance.build-seed}"; target-file = "/run/nexus-db/nexus-dns.passwd"; user = "postgres"; }; }; postgresql = mkIf isDatabase { required-services = [ "fudo-passwords.target" ]; databases."${databaseName}".users = config.instance.local-admins; users = { "${serverUser}" = { password-file = hostSecrets.postgres-nexus-server-passwd.target-file; databases."${databaseName}" = { access = "CONNECT"; entity-access = { "ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE"; "ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE"; }; }; }; "${dnsServerUser}" = { password-file = hostSecrets.postgres-nexus-dns-server-passwd.target-file; databases."${databaseName}" = { access = "CONNECT"; entity-access = { "ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE"; "ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE"; }; }; }; }; }; }; }; }