diff --git a/machines/compute01/_configuration.nix b/machines/compute01/_configuration.nix index ffc7f5f..8ab7753 100644 --- a/machines/compute01/_configuration.nix +++ b/machines/compute01/_configuration.nix @@ -1,5 +1,7 @@ { ... }: { + dgn-dns.enable = true; + system.stateVersion = "23.05"; # Did you read the comment? } diff --git a/meta/network.nix b/meta/network.nix index 4a4f4d3..8072f8b 100644 --- a/meta/network.nix +++ b/meta/network.nix @@ -5,6 +5,9 @@ let getAddresses = version: interface: builtins.map (builtins.getAttr "address") interface.${version}; + filterIPv4 = ip: builtins.substring 0 7 ip != "192.168"; + filterIPv6 = _: true; + mkNet = _: value: let base = mkBase value; in base // { @@ -18,10 +21,10 @@ let { ipv4 = [ ]; ipv6 = [ ]; } (builtins.attrValues base.interfaces); in - _addresses // { - public = (builtins.filter - (ip: builtins.substring 0 7 ip != "192.168") - _addresses.ipv4) ++ _addresses.ipv6; + _addresses // rec { + publicV4 = builtins.filter filterIPv4 _addresses.ipv4; + publicV6 = builtins.filter filterIPv6 _addresses.ipv6; + public = publicV4 ++ publicV6; }; }; in diff --git a/meta/nodes.nix b/meta/nodes.nix index e48571d..8a698c6 100644 --- a/meta/nodes.nix +++ b/meta/nodes.nix @@ -35,6 +35,8 @@ builtins.mapAttrs mkNode { compute01 = { adminGroups = [ "bureau" ]; + deployment.tags = [ "dns" ]; + stateVersion = "23.05"; }; diff --git a/modules/default.nix b/modules/default.nix index fca9132..bdeaa13 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -38,6 +38,7 @@ "dgn-access-control" "dgn-acme" "dgn-console" + "dgn-dns" "dgn-hardware" "dgn-network" "dgn-secrets" diff --git a/modules/dgn-dns/default.nix b/modules/dgn-dns/default.nix new file mode 100644 index 0000000..ee46589 --- /dev/null +++ b/modules/dgn-dns/default.nix @@ -0,0 +1,33 @@ +args@{ config, lib, meta, name, sources, ... }: + +let + inherit (lib) + mkEnableOption + mkIf; + + dns = import sources."dns.nix"; + + cfg = config.dgn-dns; +in + +{ + options.dgn-dns = { + enable = mkEnableOption "an authoritative dns service on this server."; + }; + + + config = mkIf cfg.enable { + services.nsd = { + enable = true; + + interfaces = meta.network.${name}.addresses.public; + + zones = import ./zones (args // { inherit dns; }); + }; + + networking.firewall = { + allowedTCPPorts = [ 53 ]; + allowedUDPPorts = [ 53 ]; + }; + }; +} diff --git a/modules/dgn-dns/serial.nix b/modules/dgn-dns/serial.nix new file mode 100644 index 0000000..40caa4c --- /dev/null +++ b/modules/dgn-dns/serial.nix @@ -0,0 +1 @@ +2023072002 \ No newline at end of file diff --git a/modules/dgn-dns/zones/_dgnum.eu.nix b/modules/dgn-dns/zones/_dgnum.eu.nix new file mode 100644 index 0000000..fde6788 --- /dev/null +++ b/modules/dgn-dns/zones/_dgnum.eu.nix @@ -0,0 +1,96 @@ +{ dgn-lib, meta, dns, ... }: + +let + inherit (dgn-lib) + fuseAttrs + mapSingleFuse; + + inherit (dns.lib.combinators) + mx + spf + ttl; + + mkCNAME = host: { CNAME = [ host ]; }; + + mkRecord = host: + let net = meta.network.${host}; in + { + A = net.addresses.publicV4; + AAAA = net.addresses.publicV6; + }; + + mkNS = { A, AAAA, ... }: { inherit A AAAA; }; + + mkHosted = server: mapSingleFuse (_: mkCNAME "${server}.${meta.nodes.${server}.zone}.infra"); + + hosted = fuseAttrs (builtins.attrValues + (builtins.mapAttrs mkHosted { + compute01 = [ + "social" + ]; + + storage01 = [ + "cloud" + "git" + "s3" + "video" + ]; + + web01 = [ + "analytics" + ]; + }) + ); + + infra.subdomains = builtins.mapAttrs + (_: nodes: { subdomains = mapSingleFuse mkRecord nodes; }) + meta.infra; + + kurisuDKIM = [{ + selector = "kurisu"; + k = "rsa"; + s = [ "email" ]; + p = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDa5KuK6ry+Ss2VsKL0FsDpoBlc7dcXZyp62fGqFJFJv4/GEivPWiwbr2o5oLKjQVI4kIYjIZsyQJFtI/Xcu4BrtDdBknb5WvCN8V9EvIMh3pfXOBLVx4oqw4BR7wF8Rw1J9xyfgsfK+m2n0M39XlMHH0Nuy6kU48jH9vYpZs17ZQIDAQAB"; + }]; +in + +{ + # Primary DNS servers + NS = [ + "ns01.dgnum.eu." + ]; + + # dgnum.codeberg.pages + # ALIAS = [ "codeberg.page" ]; + A = [ "217.197.91.145" ]; + AAAA = [ "2001:67c:1401:20f0::1" ]; + + MX = map (ttl 3600) [ + (mx.mx 10 "kurisu.lahfa.xyz.") + ]; + + TXT = [ + "dgnum.codeberg.page" + (spf.strict [ "a:kurisu.lahfa.xyz" ]) + ]; + DMARC = [{ p = "none"; }]; + DKIM = kurisuDKIM; + + subdomains = hosted // { + ns01 = mkNS infra.subdomains.par01.subdomains.compute01; + } // { + infra = infra // { + MX = map (ttl 3600) [ + (mx.mx 10 "kurisu.lahfa.xyz.") + ]; + + TXT = [ (spf.strict [ "a:kurisu.lahfa.xyz" ]) ]; + DMARC = [{ p = "none"; }]; + DKIM = kurisuDKIM; + }; + + dev.CNAME = [ "dev.pages.codeberg.page." ]; + irc.CNAME = [ "public.p.lahfa.xyz." ]; + webmail.CNAME = [ "kurisu.dual.lahfa.xyz." ]; + }; +} diff --git a/modules/dgn-dns/zones/default.nix b/modules/dgn-dns/zones/default.nix new file mode 100644 index 0000000..972f918 --- /dev/null +++ b/modules/dgn-dns/zones/default.nix @@ -0,0 +1,52 @@ +args@{ dgn-lib, dns, ... }: + +let + inherit (dgn-lib) + mapSingleFuse + mkRel + recursiveFuse; + + delegations = { + "dgnum.eu" = { + "ns-01.hubrecht.ovh." = [ "51.15.174.50" ]; + "ns-03.hubrecht.ovh." = [ "51.178.27.125" ]; + "kurisu.dual.lahfa.xyz." = [ ]; + }; + }; + + servedZones = [ + "dgnum.eu" + + # For reverse DNS + # "ip6.arpa" + ]; + + SOA = { + nameServer = "ns01.dgnum.eu."; + adminEmail = "dns.dgnum.eu"; + serial = import ../serial.nix; + retry = 3600; + minimum = 300; + }; + + mkZone = zone: + let + secondaryDNS = builtins.map + (ip: "${ip} NOKEY") + (builtins.concatLists (builtins.attrValues (delegations.${zone} or { }))); + in + { + data = + let attrs = import (mkRel ./. "_${zone}.nix") args; in + dns.lib.toString zone (recursiveFuse [ + { inherit SOA; } + attrs + { NS = attrs.NS ++ (builtins.attrNames (delegations.${zone} or { })); } + ]); + + provideXFR = secondaryDNS; + notify = secondaryDNS; + }; +in + +mapSingleFuse mkZone servedZones diff --git a/npins/sources.json b/npins/sources.json index a62650a..0194d75 100644 --- a/npins/sources.json +++ b/npins/sources.json @@ -28,6 +28,19 @@ "url": "https://api.github.com/repos/nix-community/disko/tarball/v1.0.0", "hash": "153cm29hjgklsi1aw85srvcd3h3afm7j77llk4fj3slf5gcwnmx9" }, + "dns.nix": { + "type": "GitRelease", + "repository": { + "type": "Git", + "url": "https://git.hubrecht.ovh/hubrecht/dns.nix" + }, + "pre_releases": false, + "version_upper_bound": null, + "version": "v1.2.1", + "revision": "66979725afe2164491be38ffff78460cc9b0ffd7", + "url": null, + "hash": "1bashjbh71dqs32yld7ihw2vz0vrad73pc35crf3qck8ssgpzv7d" + }, "nixos-23.05": { "type": "Channel", "name": "nixos-23.05", diff --git a/scripts/default.nix b/scripts/default.nix new file mode 100644 index 0000000..9e2e4c6 --- /dev/null +++ b/scripts/default.nix @@ -0,0 +1,30 @@ +{ pkgs, ... }: + +let + substitutions = { + inherit (pkgs) + bash + colmena + coreutils + git; + }; + + mkShellScript = name: (pkgs.substituteAll ({ + inherit name; + src = ./. + "/${name}.sh"; + dir = "/bin/"; + isExecutable = true; + + checkPhase = '' + ${pkgs.stdenv.shellDryRun} "$target" + ''; + } // substitutions)); + + scripts = [ + "ns-update" + # "mk-backup-key" + # "wg-setup" + ]; +in + +builtins.map mkShellScript scripts diff --git a/scripts/ns-update.sh b/scripts/ns-update.sh new file mode 100644 index 0000000..d909afa --- /dev/null +++ b/scripts/ns-update.sh @@ -0,0 +1,13 @@ +#!@bash@/bin/bash + +cd "$(@git@/bin/git rev-parse --show-toplevel)" + +SERIAL=$(@coreutils@/bin/cat modules/dgn-dns/serial.nix) +T_SERIAL="$(@coreutils@/bin/date +'%Y%m%d')00" + +N_SERIAL=$(( ( SERIAL >= T_SERIAL ? SERIAL : T_SERIAL ) + 1 )) + +echo "New SOA serial: $N_SERIAL" +echo -n "$N_SERIAL" > modules/dgn-dns/serial.nix + +@colmena@/bin/colmena apply --on @dns diff --git a/shell.nix b/shell.nix index bcef228..9b9e252 100644 --- a/shell.nix +++ b/shell.nix @@ -40,13 +40,13 @@ let in pkgs.mkShell { - packages = with pkgs; [ + packages = (with pkgs; [ npins colmena nixos-generators ] ++ (builtins.map (p: callPackage p { }) [ (sources.disko + "/package.nix") - ]); + ])) ++ (import ./scripts { inherit pkgs; }); allowSubstitutes = false; }