From 5356ba97c68a8da8bf35b714a52a5ae3208b73d4 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 7 Aug 2022 19:58:37 +0200 Subject: [PATCH] cluster/services/dns: init --- cluster/services/dns/admin.nix | 115 ++++++++++++++++++ cluster/services/dns/authoritative.nix | 41 +++++++ .../services/dns/coredns.nix | 59 ++++----- cluster/services/dns/default.nix | 32 +++++ .../services/dns/pdns-admin-oidc-secrets.age | Bin 0 -> 539 bytes cluster/services/dns/pdns-admin-salt.age | 11 ++ cluster/services/dns/pdns-admin-secret.age | 12 ++ cluster/services/dns/pdns-api-key.age | Bin 0 -> 841 bytes cluster/services/dns/pdns-db-credentials.age | 15 +++ hosts/VEGAS/services/dns/zones.nix | 65 ---------- hosts/VEGAS/system.nix | 1 - secrets.nix | 5 + 12 files changed, 258 insertions(+), 98 deletions(-) create mode 100644 cluster/services/dns/admin.nix create mode 100644 cluster/services/dns/authoritative.nix rename hosts/VEGAS/services/dns/default.nix => cluster/services/dns/coredns.nix (57%) create mode 100644 cluster/services/dns/default.nix create mode 100644 cluster/services/dns/pdns-admin-oidc-secrets.age create mode 100644 cluster/services/dns/pdns-admin-salt.age create mode 100644 cluster/services/dns/pdns-admin-secret.age create mode 100644 cluster/services/dns/pdns-api-key.age create mode 100644 cluster/services/dns/pdns-db-credentials.age delete mode 100644 hosts/VEGAS/services/dns/zones.nix diff --git a/cluster/services/dns/admin.nix b/cluster/services/dns/admin.nix new file mode 100644 index 0000000..2591b50 --- /dev/null +++ b/cluster/services/dns/admin.nix @@ -0,0 +1,115 @@ +{ cluster, config, hosts, inputs, lib, pkgs, tools, ... }: + +let + inherit (hosts.${config.networking.hostName}) interfaces; + inherit (tools.meta) domain; + inherit (config.links) pdnsAdmin; + inherit (cluster.config) vars; + + pdns-api = cluster.config.links.powerdns-api; + + dataDirUI = "/srv/storage/private/powerdns-admin"; + + translateConfig = withQuotes: cfg: let + pythonValue = val: if lib.isString val then "'${val}'" + else if lib.isAttrs val && val ? env then "__import__('os').getenv('${val.env}')" + else if lib.isBool val then (if val then "True" else "False") + else if lib.isInt val then toString val + else throw "translateConfig: unsupported value type"; + + quote = str: if withQuotes then pythonValue str else str; + + configList = lib.mapAttrsToList (n: v: "${n}=${quote v}") cfg; + in lib.concatStringsSep "\n" configList; + + login = x: "https://login.${domain}/auth/realms/master/protocol/openid-connect/${x}"; +in { + age.secrets = { + pdns-admin-oidc-secrets = { + file = ./pdns-admin-oidc-secrets.age; + mode = "0400"; + }; + pdns-admin-salt = { + file = ./pdns-admin-salt.age; + mode = "0400"; + owner = "powerdnsadmin"; + group = "powerdnsadmin"; + }; + pdns-admin-secret = { + file = ./pdns-admin-secret.age; + mode = "0400"; + owner = "powerdnsadmin"; + group = "powerdnsadmin"; + }; + pdns-api-key = { + file = ./pdns-api-key.age; + mode = "0400"; + }; + }; + + links.pdnsAdmin.protocol = "http"; + + networking.firewall = { + allowedTCPPorts = [ 53 ]; + allowedUDPPorts = [ 53 ]; + }; + + systemd.tmpfiles.rules = [ + "d '${dataDirUI}' 0700 powerdnsadmin powerdnsadmin - -" + ]; + + services.powerdns = { + enable = true; + extraConfig = translateConfig false { + api = "yes"; + webserver-allow-from = "127.0.0.1, ${vars.meshNet.cidr}"; + webserver-address = pdns-api.ipv4; + webserver-port = pdns-api.portStr; + api-key = "$scrypt$ln=14,p=1,r=8$ZRgztsniH1y+F7P/RkXq/w==$QTil5kbJPzygpeQRI2jgo5vK6fGol9YS/NVR95cmWRs="; + }; + }; + + services.powerdns-admin = { + enable = true; + secretKeyFile = config.age.secrets.pdns-admin-secret.path; + saltFile = config.age.secrets.pdns-admin-salt.path; + extraArgs = [ "-b" pdnsAdmin.tuple ]; + config = translateConfig true { + SQLALCHEMY_DATABASE_URI = "sqlite:///${dataDirUI}/pda.db"; + PDNS_VERSION = pkgs.pdns.version; + PDNS_API_URL = pdns-api.url; + PDNS_API_KEY.env = "PDNS_API_KEY"; + + SIGNUP_ENABLED = false; + OIDC_OAUTH_ENABLED = true; + OIDC_OAUTH_KEY = "net.privatevoid.dnsadmin1"; + OIDC_OAUTH_SECRET.env = "OIDC_OAUTH_SECRET"; + OIDC_OAUTH_SCOPE = "openid profile email roles"; + + OIDC_OAUTH_API_URL = login ""; + OIDC_OAUTH_TOKEN_URL = login "token"; + OIDC_OAUTH_AUTHORIZE_URL = login "auth"; + OIDC_OAUTH_LOGOUT_URL = login "logout"; + }; + }; + + systemd.services.powerdns-admin.serviceConfig = { + BindPaths = [ dataDirUI ]; + EnvironmentFile = [ + config.age.secrets.pdns-api-key.path + config.age.secrets.pdns-admin-oidc-secrets.path + ]; + }; + + services.nginx.virtualHosts."dnsadmin.${domain}" = lib.recursiveUpdate + (tools.nginx.vhosts.proxy pdnsAdmin.url) + # backend sends really big headers for some reason + # increase buffer size accordingly + { + locations."/".extraConfig = '' + proxy_busy_buffers_size 512k; + proxy_buffers 4 512k; + proxy_buffer_size 256k; + ''; + }; +} diff --git a/cluster/services/dns/authoritative.nix b/cluster/services/dns/authoritative.nix new file mode 100644 index 0000000..df117b3 --- /dev/null +++ b/cluster/services/dns/authoritative.nix @@ -0,0 +1,41 @@ +{ cluster, config, hosts, inputs, lib, pkgs, tools, ... }: + +let + inherit (hosts.${config.networking.hostName}) interfaces; + inherit (cluster.config) vars; + + patroni = cluster.config.links.patroni-pg-access; + pdns-api = cluster.config.links.powerdns-api; + + translateConfig = cfg: let + configList = lib.mapAttrsToList (n: v: "${n}=${v}") cfg; + in lib.concatStringsSep "\n" configList; +in { + age.secrets = { + pdns-db-credentials = { + file = ./pdns-db-credentials.age; + mode = "0400"; + owner = "pdns"; + group = "pdns"; + }; + }; + + networking.firewall = { + allowedTCPPorts = [ 53 ]; + allowedUDPPorts = [ 53 ]; + }; + + services.powerdns = { + enable = true; + extraConfig = translateConfig { + launch = "gpgsql"; + local-address = interfaces.primary.addr; + gpgsql-host = patroni.ipv4; + gpgsql-port = patroni.portStr; + gpgsql-dbname = "powerdns"; + gpgsql-user = "powerdns"; + gpgsql-extra-connection-parameters = "passfile=${config.age.secrets.pdns-db-credentials.path}"; + version-string = "Private Void DNS"; + }; + }; +} diff --git a/hosts/VEGAS/services/dns/default.nix b/cluster/services/dns/coredns.nix similarity index 57% rename from hosts/VEGAS/services/dns/default.nix rename to cluster/services/dns/coredns.nix index aade8b0..5037e6e 100644 --- a/hosts/VEGAS/services/dns/default.nix +++ b/cluster/services/dns/coredns.nix @@ -1,15 +1,19 @@ { config, hosts, inputs, pkgs, tools, ... }: -# TODO: is this secure? + let inherit (hosts.${config.networking.hostName}) interfaces; inherit (tools.meta) domain; + inherit (config.links) localRecursor; + inherit (inputs.self.packages.${pkgs.system}) stevenblack-hosts; dot = config.security.acme.certs."securedns.${domain}"; -in { - imports = [ ./zones.nix ]; +in + +{ + links.localRecursor = {}; networking.firewall = { - allowedTCPPorts = [ 53 853 ]; - allowedUDPPorts = [ 53 853 ]; + allowedTCPPorts = [ 853 ]; + allowedUDPPorts = [ 853 ]; }; systemd.services.coredns = { @@ -19,6 +23,7 @@ in { "dot-key.pem:${dot.directory}/key.pem" ]; }; + security.acme.certs."securedns.${domain}" = { group = "nginx"; webroot = "/var/lib/acme/acme-challenge"; @@ -28,52 +33,42 @@ in { "coredns.service" ]; }; + services.coredns = { enable = true; config = '' . { bind ${interfaces.vstub.addr} - hosts ${inputs.self.packages.${pkgs.system}.stevenblack-hosts} { + bind 127.0.0.1 + hosts ${stevenblack-hosts} { fallthrough } chaos "Private Void DNS" info@privatevoid.net - forward . 127.0.0.1 + forward . ${localRecursor.tuple} } tls://.:853 { bind ${interfaces.primary.addr} tls {$CREDENTIALS_DIRECTORY}/dot-cert.pem {$CREDENTIALS_DIRECTORY}/dot-key.pem - hosts ${inputs.self.packages.${pkgs.system}.stevenblack-hosts} { + hosts ${stevenblack-hosts} { fallthrough } chaos "Private Void DNS" info@privatevoid.net - forward . ${interfaces.primary.addr} + forward . ${localRecursor.tuple} } ''; }; - services.bind = { + services.pdns-recursor = { enable = true; - # TODO: un-hardcode all ip addresses - listenOn = [ interfaces.primary.addr "127.0.0.1" ]; - ipv4Only = true; - - cacheNetworks = [ "10.0.0.0/8" ]; - extraConfig = '' - acl "trusted" { - 127.0.0.0/8; - ::1/128; - ${interfaces.vstub.addr}/32; - 10.100.0.0/16; - 10.10.0.0/16; - }; - acl "publicservers" { - 116.202.226.86/32; - }; - ''; - extraOptions = '' - recursion yes; - allow-recursion { trusted; ${interfaces.primary.addr}/32; }; - dnssec-validation no; - ''; + dnssecValidation = "process"; + forwardZones = { + # optimize queries against our own domain + "${domain}" = interfaces.primary.addr; + }; + dns = { + inherit (localRecursor) port; + address = localRecursor.ipv4; + allowFrom = [ "127.0.0.1" ]; + }; }; } diff --git a/cluster/services/dns/default.nix b/cluster/services/dns/default.nix new file mode 100644 index 0000000..e68b22c --- /dev/null +++ b/cluster/services/dns/default.nix @@ -0,0 +1,32 @@ +{ config, ... }: + +let + inherit (config.vars) hosts; +in +{ + links = { + dnsResolver = { + ipv4 = hosts.VEGAS.interfaces.vstub.addr; + port = 53; + }; + powerdns-api = { + ipv4 = config.vars.mesh.VEGAS.meshIp; + protocol = "http"; + }; + }; + services.dns = { + nodes = { + master = [ "VEGAS" ]; + slave = [ "prophet" ]; + coredns = [ "VEGAS" ]; + }; + nixos = { + master = [ + ./authoritative.nix + ./admin.nix + ]; + slave = ./authoritative.nix; + coredns = ./coredns.nix; + }; + }; +} diff --git a/cluster/services/dns/pdns-admin-oidc-secrets.age b/cluster/services/dns/pdns-admin-oidc-secrets.age new file mode 100644 index 0000000000000000000000000000000000000000..185fe16465d79d2fda98016a4136aaa2bc1b6323 GIT binary patch literal 539 zcmZ9_J8RSc003a|(IK0UMG=f}iyUd*F>xp)X&!gUC6`>%%LyvEB$r3i-4k8FHin#Xs1D_iPP>^{=JFntAThEIS-bDdu11!r3 z3Ve(tQ3lj>lEPS!8N(E{V9b`c`&uPWJ+j3nc;M9*=~=#El3Xllj$L?04hZ0t@xoT?xdVi z>6VXloj~OzpKcpd?1}`SuM*vit8GLiSR}_0e9EOZ8xmUs#^k5IvnkZ0hU=Q?yga}8 z_*kl0FzNSDoXcy(by9J`PZJ-8AJPoE3YlcwM5ZJZ^CE`36Ql%2RH|4$O9&`D(%3DQ zlhg&{=m7jNxIQ#YZ(-ZFMZv}mEbn{>> i-v4lI?c&`_+UXDF&)@6s4_}|Y!=6z~d;R3bm7RYA2efnm literal 0 HcmV?d00001 diff --git a/cluster/services/dns/pdns-admin-salt.age b/cluster/services/dns/pdns-admin-salt.age new file mode 100644 index 0000000..1e4d774 --- /dev/null +++ b/cluster/services/dns/pdns-admin-salt.age @@ -0,0 +1,11 @@ +age-encryption.org/v1 +-> ssh-ed25519 NO562A d/YNanH/cHoFLPp8WcCXHh/LQLRwaUa95JiRLbgb8RI +UPEHpnHHTU6dGKi2MbApEspcpt1lFtFZ4XJjShL7OoE +-> ssh-ed25519 5/zT0w Rv9ZS5P2Eca3npPLR7yym/XTRSDfVmgRwH1pAGR79T8 +4A/KXc2wxxokfDAwWYf0ZTUEzQ8ldkC+zRNZY3KjBTs +-> ssh-ed25519 d3WGuA 2R0kaVjuhU3wT9pjj214zkEaHYNSlMxf9Z+MfBssHwY +EU5LWk6xfohWM/3sAqYtUvFmRgIPxOLXHnlqbsQ3+ok +-> -|(-grease W=cc~ O2q5 +FZzh/ZwDS2EqvVZ9NErmUwCMN72op1Qy +--- Ducan3ugRJC3dmWLr7+FKok+WmInOgOzW0ccYeqAFAQ +*Q.SCf*`5w"~xw*\"t '0L \ No newline at end of file diff --git a/cluster/services/dns/pdns-admin-secret.age b/cluster/services/dns/pdns-admin-secret.age new file mode 100644 index 0000000..03f5ab0 --- /dev/null +++ b/cluster/services/dns/pdns-admin-secret.age @@ -0,0 +1,12 @@ +age-encryption.org/v1 +-> ssh-ed25519 NO562A hUR+UdHnpazhANM8DKToI5Th3lv1aAuxZ1IQKvCOv34 +PvsiSym8YdleDULLnWuTs1x08KO3EmAg/AAjulgrgqE +-> ssh-ed25519 5/zT0w qMXS2xLOLv/+l6brG11i+3FwHdrhlmxZBNtBiU9hu2g +BlFYPvH4mFJRMHTlHwnBdJb6QcugylwZuT5bgSKcQa0 +-> ssh-ed25519 d3WGuA k2fRQ3+HyZP+bb/gkVKQqUmbITJLPm9tGp67DbRfiCs +RX9CACfYpYKvSqyfXjvEokTGsp4+ECQBD8i1ehD5xRg +-> IB@F$9G-grease +cXRgUVdIPGEjft1CJA +--- si16Det/GwF7GLHLt0ha8v4rFFeJXyhEylIiqzZVAK8 +ְpǺ#4^ ~u UuaQBj(N)q<"%,V95Zh#W["M&+%SQBޛy#ϫtwq, 3YyIq}ʓ>sgzs ƆFP|=~KQR,DZu+պZGHa=;C.uVSh$VA9= ? \ No newline at end of file diff --git a/cluster/services/dns/pdns-api-key.age b/cluster/services/dns/pdns-api-key.age new file mode 100644 index 0000000000000000000000000000000000000000..ab74c1ab7cb6959db0d8addeff6f3dd53cb0893a GIT binary patch literal 841 zcmZ9_>ucNu008iz4&f-cZk-e7BUV9NNb|Tyb0C%6D|eT>?{H|iq|OM}~J02%{qy9%ia77n9PfM&uGi~vZb9YZ8MUd|;O9#)G*Vw8`UC0Sv4 z9?!CS+{acCC@n?mK8xo=XfN*8107<`{wqk51k^of$O_TL09ZlCzJe^cR z3c@0fmtWU1rRxQ0a6emyhOKZ4+~Ik`O67bV^|;tr?tl zB+O4^gdh?aq7+QN2FHy$s%K3)zzTBF!jnZZ$f?t54OF-)DmiM(CQ?OelqQ9ef@&~p zWV8STL4as8Q&>C6sNEVl4M|&^d%W71};7K`q?x6A5U(0 zOWP;sOT(qvw+>AJH)o)s_w6^A|9I+`-E;iPOH198%H+4}uTV#v*Q)OQSC3_drH#aw zT?yShH2LEB7sTto4ea@TUO~jY`SY8-_5O}`@XtQ@d}kIO_-f#b%NIV`I@((6UWmBws62bzLvW3xGb%YWKLc8 zPJ0LYH*YO&^`GA*9Q^eS?PYrL-o*#jz8MRjdGf*c_B*p5nF}ku6G=3B;;1XHZfyNz z{BY{sJ023BK5O-l-*sam1zlbqUcUQ4P0{wZG@x`Rp_M)}f0JkM{U&{{f_XM{)oF literal 0 HcmV?d00001 diff --git a/cluster/services/dns/pdns-db-credentials.age b/cluster/services/dns/pdns-db-credentials.age new file mode 100644 index 0000000..3a28f99 --- /dev/null +++ b/cluster/services/dns/pdns-db-credentials.age @@ -0,0 +1,15 @@ +age-encryption.org/v1 +-> ssh-ed25519 NO562A /puQyDz+IepPqd8PTnD+YUp1obCh4gO1/7GGKaUAcRk +ydUvPiZyl9OZ3gVlhDxPkFf4PiPmQQtFoL9PK4pcA5Y +-> ssh-ed25519 5/zT0w MUEtkOeKzCBDBjoJjfkRnTmwl3pa0Qo07EKOpQp8RTQ +rUEyKc2BiQIxoPxTpoDPDfeJie2cfocwyT/VmIQcqL8 +-> ssh-ed25519 d3WGuA 0pGUj+2YukJEgbIZ++iUKwfCp8yGiU2iUuyk0NFlYSg +/O3DY0EO3odBXvQNM14PdkrRmCLHOIvOIdgTsq5jBsQ +-> ssh-ed25519 6YMlxg Us2lOVb1NCc8yTqT/pe8UEb6qNePw7onN7J2z0mkb0s +WWtatJOs1krHZxmFddhmDOEfMNvGKBPFdAUnekKaccE +-> H7;a-ODO-grease Ny!`X@)ݱ?n6(<|bGMBd3ڧ$i#qhgPj޼҅VT :Žv{?4&05O%D|u{*2B!'(.0֏KgѼ"&LKq<Dq[;xP]}kලXdfy_ +LC?hH(cIyZϿ|}#:w v5Azr: \ No newline at end of file diff --git a/hosts/VEGAS/services/dns/zones.nix b/hosts/VEGAS/services/dns/zones.nix deleted file mode 100644 index 956350d..0000000 --- a/hosts/VEGAS/services/dns/zones.nix +++ /dev/null @@ -1,65 +0,0 @@ -{ lib, tools, ... }: - -# upstream's zone generator is pretty bad, so... - -# TODO: make this prettier - -let - inherit (tools.meta) domain; - inherit (tools) nginx identity; - - externalSlave = { name, masters ? [ identity.dns.master.addr ], notify ? "no", alsoNotify ? [ "none" ] }: let - zoneName = "${name}"; - file = "/var/named/slaves/ext_${zoneName}.db"; - mastersFormatted = builtins.concatStringsSep "; " masters; - notifiersFormatted = builtins.concatStringsSep "; " alsoNotify; - in '' - zone "${zoneName}." IN { - type slave; - masters { ${mastersFormatted}; }; - file "${file}"; - allow-transfer { trusted; publicservers; }; - allow-query { any; }; - notify ${notify}; - also-notify { ${notifiersFormatted}; }; - }; - ''; - internalSlave' = domain: name: let - zoneName = "${name}${domain}"; - file = "/var/named/slaves/int_${zoneName}.db"; - in '' - zone "${zoneName}." IN { - type slave; - masters { ${identity.dns.master.addr}; }; - file "${file}"; - allow-transfer { trusted; }; - allow-query { trusted; }; - notify no; - }; - ''; - internalSlave = internalSlave' ".${domain}"; - revSlave = internalSlave' ".in-addr.arpa"; - toAttr = value: { inherit (value) name; inherit value; }; -in -{ - services.bind.extraConfig = builtins.concatStringsSep "\n" ([ - (externalSlave { name = domain; notify = "explicit"; alsoNotify = [ "116.202.226.86" ]; }) - (externalSlave { name = "imagine-using-oca.ml"; notify = "explicit"; alsoNotify = [ "116.202.226.86" ]; }) - (externalSlave { name = "animus.com"; masters = [ "116.202.226.86" ]; }) - ] ++ map internalSlave [ - "virtual-machines" - "core" - "services" - "ext" - "int" - "vpn" - "find" - ] ++ map revSlave [ - "0.10.10" - "1.10.10" - "2.10.10" - "100.10" - ] ++ map (internalSlave' "") [ - "void" - ]); -} diff --git a/hosts/VEGAS/system.nix b/hosts/VEGAS/system.nix index ccd57bd..b6cdaa6 100644 --- a/hosts/VEGAS/system.nix +++ b/hosts/VEGAS/system.nix @@ -19,7 +19,6 @@ ./services/api ./services/backbone-routing ./services/bitwarden - ./services/dns ./services/fbi ./services/gitlab ./services/hydra diff --git a/secrets.nix b/secrets.nix index c805655..f0b9d7a 100644 --- a/secrets.nix +++ b/secrets.nix @@ -4,6 +4,11 @@ let systemKeys = x: x.ssh.id.publicKey or null; in with hosts; { + "cluster/services/dns/pdns-admin-oidc-secrets.age".publicKeys = max ++ map systemKeys [ VEGAS ]; + "cluster/services/dns/pdns-admin-salt.age".publicKeys = max ++ map systemKeys [ VEGAS ]; + "cluster/services/dns/pdns-admin-secret.age".publicKeys = max ++ map systemKeys [ VEGAS ]; + "cluster/services/dns/pdns-api-key.age".publicKeys = max ++ map systemKeys [ VEGAS ]; + "cluster/services/dns/pdns-db-credentials.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ]; "cluster/services/patroni/passwords/replication.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ]; "cluster/services/patroni/passwords/rewind.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ]; "cluster/services/patroni/passwords/superuser.age".publicKeys = max ++ map systemKeys [ VEGAS prophet ];