From eb1003f7e6abe54850db2a2dc46186c3a49babef Mon Sep 17 00:00:00 2001 From: Gabriel Arazas Date: Thu, 22 Jun 2023 17:56:47 +0800 Subject: [PATCH] hosts/plover: change DNS server to Bind9 CoreDNS doesn't have dynamic updates available yet (though there are PRs and discussions for it) so we'll have to go with something that has it. Also, it provides an opportunity for me to use the de-facto software for this. --- .../{coredns => dns}/foodogsquared.one.zone | 9 +- .../config/dns/plover.foodogsquared.one.zone | 19 +++ hosts/plover/default.nix | 7 +- hosts/plover/modules/services/bind.nix | 148 ++++++++++++++++++ hosts/plover/modules/services/coredns.nix | 2 +- hosts/plover/modules/services/gitea.nix | 1 + hosts/plover/modules/services/keycloak.nix | 1 + hosts/plover/modules/services/vaultwarden.nix | 1 + hosts/plover/secrets/secrets.yaml | 6 +- 9 files changed, 184 insertions(+), 10 deletions(-) rename hosts/plover/config/{coredns => dns}/foodogsquared.one.zone (94%) create mode 100644 hosts/plover/config/dns/plover.foodogsquared.one.zone create mode 100644 hosts/plover/modules/services/bind.nix diff --git a/hosts/plover/config/coredns/foodogsquared.one.zone b/hosts/plover/config/dns/foodogsquared.one.zone similarity index 94% rename from hosts/plover/config/coredns/foodogsquared.one.zone rename to hosts/plover/config/dns/foodogsquared.one.zone index eb4f9540..57b11a12 100644 --- a/hosts/plover/config/coredns/foodogsquared.one.zone +++ b/hosts/plover/config/dns/foodogsquared.one.zone @@ -1,9 +1,10 @@ ; This is trying to be discrete with certain information. This should be copied ; and replaced with more confidential information somewhere. $TTL 12h +$ORIGIN foodogsquared.one. @ 3600 IN SOA ns1.first-ns.de. hostmaster.foodogsquared.one. ( - 2023061201 ; serial number + 2023062201 ; serial number 1h ; refresh 15m ; update retry 3w ; expiry @@ -48,14 +49,16 @@ wiki IN CNAME foodogsquared-wiki.netlify.app. ; Public-facing services from this server. Just remember to increment the ; serial number once the public IPs changes. PLEEEEEEEEEEEAAAAAAAAASE! -plover IN A @ploverPublicIPv4@ -plover IN AAAA @ploverPublicIPv6@ +plover IN A @ploverWANIPv4@ +plover IN AAAA @ploverWANIPv6@ auth IN CNAME plover pass IN CNAME plover code IN CNAME plover vpn IN CNAME plover +postgres IN CNAME plover + ; Other things. _github-pages-challenge-foo-dogsquared IN TXT 673febae1ea0095e76d1e02a7a1709 diff --git a/hosts/plover/config/dns/plover.foodogsquared.one.zone b/hosts/plover/config/dns/plover.foodogsquared.one.zone new file mode 100644 index 00000000..a99b8479 --- /dev/null +++ b/hosts/plover/config/dns/plover.foodogsquared.one.zone @@ -0,0 +1,19 @@ +$TTL 12h +$ORIGIN plover.foodogsquared.one. + +@ 3600 IN SOA ns hostmaster.foodogsquared.one. ( + 2023062201 ; serial number + 1h ; refresh + 15m ; update retry + 3w ; expiry + 2h ; nx = nxdomain ttl + ) + 3600 IN NS ns + +ns 3600 IN A @ploverLANIPv4@ + 3600 IN AAAA @ploverLANIPv6@ + +* 3600 IN A @ploverLANIPv4@ + 3600 IN AAAA @ploverLANIPv6@ + +; vim: expandtab! tabstop=8 shiftwidth=8 filetype=dns diff --git a/hosts/plover/default.nix b/hosts/plover/default.nix index 57cb2404..35b468d6 100644 --- a/hosts/plover/default.nix +++ b/hosts/plover/default.nix @@ -23,7 +23,7 @@ in "${modulesPath}/profiles/hardened.nix" # The primary DNS server that is completely hidden. - ./modules/services/coredns.nix + ./modules/services/bind.nix # The reverse proxy of choice. ./modules/services/nginx.nix @@ -145,11 +145,12 @@ in }; # DNS-related settings. We're settling by configuring the ACME setup with a - # DNS provider. + # self-hosted DNS server. security.acme.defaults = { email = "admin@foodogsquared.one"; - dnsProvider = "porkbun"; + dnsProvider = "rfc2136"; credentialsFile = config.sops.secrets."plover/lego/env".path; + dnsPropagationCheck = false; }; services.openssh.hostKeys = [{ diff --git a/hosts/plover/modules/services/bind.nix b/hosts/plover/modules/services/bind.nix new file mode 100644 index 00000000..8be65cdd --- /dev/null +++ b/hosts/plover/modules/services/bind.nix @@ -0,0 +1,148 @@ +{ config, lib, pkgs, ... }: + +let + inherit (config.networking) domain fqdn; + inherit (import ../hardware/networks.nix) privateIPv6Prefix interfaces clientNetworks serverNetworks secondaryNameServers wireguardPeers; + secondaryNameserverDomains = lib.attrNames secondaryNameServers; + secondaryNameServersIPv4 = lib.foldl' + (total: addresses: total ++ addresses.IPv4) + [ ] + (lib.attrValues secondaryNameServers); + secondaryNameServersIPv6 = lib.foldl' + (total: addresses: total ++ addresses.IPv6) + [ ] + (lib.attrValues secondaryNameServers); + secondaryNameServersIPs = secondaryNameServersIPv4 ++ secondaryNameServersIPv6; + + domainZone = pkgs.substituteAll { + src = ../../config/dns/${domain}.zone; + ploverWANIPv4 = interfaces.wan.IPv4.address; + ploverWANIPv6 = interfaces.wan.IPv6.address; + }; + + fqdnZone = pkgs.substituteAll { + src = ../../config/dns/${fqdn}.zone; + ploverLANIPv4 = interfaces.lan.IPv4.address; + ploverLANIPv6 = interfaces.lan.IPv6.address; + }; + + zonesDir = "/var/db/dns"; + zoneFile = domain: "${zonesDir}/${domain}.zone"; + + localhostIP = [ + "127.0.0.1" + "::1" + ]; + + allowedLANIPs = [ + # Loopback address + "127.0.0.0/8" + + # Private uses + "10.48.0.0/12" + "172.27.0.0/16" # The private subnet for our internal network. + "172.28.0.0/16" # The Wireguard subnet. + ]; + + allowedLANIPv6s = [ + "::1" # Loopback + "${privateIPv6Prefix}::/48" # Private uses + ]; +in +{ + sops.secrets = + let + getKey = key: { + inherit key; + sopsFile = ../../secrets/secrets.yaml; + }; + getSecrets = secrets: + lib.mapAttrs' + (secret: config: + lib.nameValuePair + "plover/${secret}" + ((getKey secret) // config)) + secrets; + in + getSecrets { + "dns/${domain}/mailbox-security-key" = { }; + "dns/${domain}/mailbox-security-key-record" = { }; + }; + + networking.nameservers = localhostIP; + + environment.etc."bind/named.conf".source = config.services.bind.configFile; + + services.bind = { + enable = true; + forward = "first"; + forwarders = [ "127.0.0.53 port 53" ]; + + listenOn = [ + "127.0.0.1" + interfaces.lan.IPv4.address + interfaces.wan.IPv4.address + ]; + + listenOnIpv6 = [ + "::1" + interfaces.lan.IPv6.address + interfaces.wan.IPv6.address + ]; + + extraConfig = '' + acl internals { ${lib.concatStringsSep "; " (clientNetworks ++ serverNetworks ++ [ "127.0.0.0/8" "::1" ])}; }; + ''; + + extraOptions = '' + allow-recursion { internals; }; + empty-zones-enable yes; + ''; + + zones = { + "${config.networking.domain}" = { + file = zoneFile domain; + allowQuery = allowedLANIPs ++ allowedLANIPv6s; + master = true; + slaves = secondaryNameServersIPs; + extraConfig = '' + forwarders { }; + update-policy local; + ''; + }; + + "${config.networking.fqdn}" = { + file = zoneFile fqdn; + master = true; + allowQuery = allowedLANIPs ++ allowedLANIPv6s; + slaves = [ "none" ]; + }; + }; + }; + + networking.firewall.extraInputRules = + let + allowedIPs = secondaryNameServersIPv4 ++ allowedLANIPs; + allowedIPv6s = secondaryNameServersIPv6 ++ allowedLANIPv6s; + in + '' + meta l4proto {tcp, udp} th dport domain ip saddr { ${lib.concatStringsSep ", " allowedIPs} } accept comment "Accept DNS queries from secondary nameservers and private networks" + meta l4proto {tcp, udp} th dport domain ip6 saddr { ${lib.concatStringsSep ", " allowedIPv6s} } accept comment "Accept DNS queries from secondary nameservers and private networks" + meta l4proto {tcp, udp} th dport domain-s ip saddr { ${lib.concatStringsSep ", " allowedIPs} } accept comment "Accept DNS queries from secondary nameservers and private networks" + meta l4proto {tcp, udp} th dport domain-s ip6 saddr { ${lib.concatStringsSep ", " allowedIPv6s} } accept comment "Accept DNS queries from secondary nameservers and private networks" + ''; + + systemd.services.bind = { + preStart = let + secretsPath = path: config.sops.secrets."plover/${path}".path; + replaceSecretBin = "${lib.getBin pkgs.replace-secret}/bin/replace-secret"; + in + lib.mkBefore '' + install -Dm0644 ${domainZone} ${zoneFile domain} + install -Dm0644 ${fqdnZone} ${zoneFile fqdn} + + ${replaceSecretBin} '#mailboxSecurityKey#' '${secretsPath "dns/${domain}/mailbox-security-key"}' '${zoneFile domain}' + ${replaceSecretBin} '#mailboxSecurityKeyRecord#' '${secretsPath "dns/${domain}/mailbox-security-key-record"}' '${zoneFile domain}' + ''; + }; +} diff --git a/hosts/plover/modules/services/coredns.nix b/hosts/plover/modules/services/coredns.nix index 9feb753d..2871483a 100644 --- a/hosts/plover/modules/services/coredns.nix +++ b/hosts/plover/modules/services/coredns.nix @@ -9,9 +9,9 @@ let inherit (import ../hardware/networks.nix) privateIPv6Prefix interfaces clientNetworks serverNetworks secondaryNameServers wireguardPeers; domainZoneFile = pkgs.substituteAll { - src = ../../config/coredns/${domain}.zone; ploverPublicIPv4 = interfaces.main'.IPv4.address; ploverPublicIPv6 = interfaces.main'.IPv6.address; + src = ../../config/dns/${domain}.zone; }; # The final location of the thing. diff --git a/hosts/plover/modules/services/gitea.nix b/hosts/plover/modules/services/gitea.nix index 9f19bcdc..7b95a075 100644 --- a/hosts/plover/modules/services/gitea.nix +++ b/hosts/plover/modules/services/gitea.nix @@ -163,6 +163,7 @@ in services.nginx.virtualHosts."${codeForgeDomain}" = { forceSSL = true; enableACME = true; + acmeRoot = null; locations."/" = { proxyPass = "http://localhost:${toString config.services.gitea.settings.server.HTTP_PORT}"; }; diff --git a/hosts/plover/modules/services/keycloak.nix b/hosts/plover/modules/services/keycloak.nix index 2fc2941f..68112912 100644 --- a/hosts/plover/modules/services/keycloak.nix +++ b/hosts/plover/modules/services/keycloak.nix @@ -78,6 +78,7 @@ in "${authDomain}" = { forceSSL = true; enableACME = true; + acmeRoot = null; # This is based from the reverse proxy guide from the official # documentation at https://www.keycloak.org/server/reverseproxy. diff --git a/hosts/plover/modules/services/vaultwarden.nix b/hosts/plover/modules/services/vaultwarden.nix index c470fdd6..714eb5c2 100644 --- a/hosts/plover/modules/services/vaultwarden.nix +++ b/hosts/plover/modules/services/vaultwarden.nix @@ -81,6 +81,7 @@ in services.nginx.virtualHosts."${passwordManagerDomain}" = { forceSSL = true; enableACME = true; + acmeRoot = null; locations = let address = config.services.vaultwarden.config.ROCKET_ADDRESS; diff --git a/hosts/plover/secrets/secrets.yaml b/hosts/plover/secrets/secrets.yaml index 9575805e..fb3ad4bd 100644 --- a/hosts/plover/secrets/secrets.yaml +++ b/hosts/plover/secrets/secrets.yaml @@ -1,6 +1,6 @@ ssh-key: ENC[AES256_GCM,data:UgJB9WiLs1nt8e95sYeBr9XJRw16CldxBFYazppwHD0Tx0rkv9YDsqJMdrMFQJJ15UgOx61yQ2rg56KoaR4cJIqQM/7foKY3+LgdI4ePtfnbGRebIMyeqCiEVWq+a5ppwsG6B9w9liRqaOG7LpD90JpXcLKVG6Lo/YwTmwDbOBGJHhyJk2DindJ7qWly1gcys5Mm9GTZmtuz8lKG7hNVQar5lmuq1fhyOolnxlFKCLG3zfumttVnT3U1ELd3TzZIaWnNIL7SuhfZDBko3ZO4bbDj/JdX1uNKlEh2FeS7Mp/DvylFlVleoQOMI9FTes/tQHmztVaA7DllYP6gKHzvLsKX577fXeoZihrGvQiNj11qDXxcj3qhUx/8iXdyVzvy/UTGWW5/QeDGNDsrT7wlwuVmqVHb7s+9Ep6Oq9tFbDQHkRMRv/Nl3C/xxtH23RuShJ1IjxXTPu9t+AiD/qPvecXyD0iZ9OX1YJn5AM9WyPLisEFasaFbgfhF6uDS2l61oCS3LPwjdbXA8UyB7vUi,iv:1OGfGUojkL0/DS+HMbyAK0GeVKa6AuQkyRwO5txiD54=,tag:TmD3ljgWGv0SNPq8GxI/kw==,type:str] lego: - env: ENC[AES256_GCM,data:CAklP0yjTBABPZq/0SANoi+6tNTXrbX7dgY34V+l5w65osPFJkC3GwDk037NzQKr9LgizhuzXqd6FP1YcHv8GZa5c7hrXU32brqNlGsW/xBL2e2DjvILgmwcndi3Bk7opzoXASyRuv3J/bTkPMdEEie+G041ushO+bPcR6Vw2xL8TJKujZrBJJ+Pd8KJHOqck3/x2pFynYHTflwOb3SgHhIBY+/H72G0I8pKYK4A1vR7,iv:KIHu2dWaOY8crEC+2LQu5WNTcgFhSV1+mwhGe3ViblY=,tag:EHz9LV9iiGCdtHa/vXbCWA==,type:str] + env: ENC[AES256_GCM,data:pJPaYAuFEj8f0Rm+Quhf4T2FKmvJ5cxGPAW7TCZkl++0yMaYx7e94WKYjLmWp+OWfUQss6byZ4WiARHY0XuF7w/S41isJdObSGgeUXnoLAu9oqt9JLsVOlQABtrY45ZF,iv:J6vBXY1gi12Zy6wXM1NyGZNxuVApKWy7eJUs8WapDoE=,tag:nEoAiY7Uy92/JjJDaSJZzw==,type:str] sourcehut: network-key: ENC[AES256_GCM,data:e28WJt1POxWnCgjYG+6HdSOwhHiIArGPrGb/3pQ5o2P2R4gIuxm8YxRPg4E=,iv:44VlT5ID8KXDquDOZMIEPBWl7r+JwbamRdqhBsFO4Rw=,tag:JRTs4FRT8bBpPyetDbt6zg==,type:str] service-key: ENC[AES256_GCM,data:glZuT+e9c2UOXieP313ny6Dl15HRXpeHtGr4XPWjhNSAvFgcwp/1AgFYrHDWZBf771MkN0pgVE/d/fx0oBOgSg==,iv:S4BzMYPZtVFhXV0g5qBxjItqCyEQ25Ct6swBut7FefQ=,tag:w3t59DqroYuAmgHlu/BhEQ==,type:str] @@ -55,8 +55,8 @@ sops: ZCtNbnFqdzNkVlBtNjVCdE4yNHMrRjQKfFV4GaReO0UO81xsTB0EuN5ibVsafXJY miBgZAZWbJjSBcM4X+Fym/DlxHRoB1a6iFEFN9yg+Z9WI8PfjKnbsA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2023-04-29T14:57:00Z" - mac: ENC[AES256_GCM,data:Fkf+0g4FweOxhHgJbAvq4GBqYSr2K7U4uDN/9A5t/LN80oJGX2G/Xj0/Al2+rr0TOOgWJpDkQqVhoZNG27Hl0xzo95n/vc+jcp7y3oeCk+P02+dn3tiEPOnKmCGnAYC5xiuDpPKTIPStKQAX/p89MvL/rliQ4FhPV4P+BfkNgp8=,iv:xyWKf0PIk0BiGJj9w+1rurOZAJMOukMBQzgTSX5YGys=,tag:cej29myo5y69TRbrBIb/4Q==,type:str] + lastmodified: "2023-06-22T08:57:24Z" + mac: ENC[AES256_GCM,data:Ltx4nr5Llq3txLTcK1mO1/BoOKm6O0FaQd60FMPpFtpIUhFQhPaPrDmnAB7/j1rMMCc4fg9hv2AYAx/rCCoaMy2aQmgRnjsuX8S7UfwqOYqvCVl6CJz3HeCfficDe5P2Un0BeblK1SeSJ689VXO0kAa2z8/uB5tis5cULfAIkBs=,iv:HKEN2YLM83mu4JjNWdBQGI+RX03nssZPwIdaP9iMW1I=,tag:VMHrarG2H/NPuymojxntUQ==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.7.3