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