mirror of
https://github.com/foo-dogsquared/nixos-config.git
synced 2025-01-31 16:57:55 +00:00
190 lines
6.0 KiB
Nix
190 lines
6.0 KiB
Nix
{ config, options, lib, pkgs, ... }:
|
|
|
|
# Take note we're also running with systemd-resolved which shouldn't really
|
|
# conflict much with established DNS servers default configuration considering
|
|
# it lives in 127.0.0.53 (not 127.0.0.1). So if you found some errors, that's
|
|
# on you. Either that or we can easily move the resolver somewhere else.
|
|
let
|
|
inherit (config.networking) domain fqdn;
|
|
inherit (import ../hardware/networks.nix) interfaces clientNetworks serverNetworks secondaryNameServers;
|
|
|
|
dnsSubdomain = "ns1";
|
|
dnsDomainName = "${dnsSubdomain}.${domain}";
|
|
certs = config.security.acme.certs;
|
|
dnsEmail = "hostmaster.${domain}";
|
|
|
|
# This is the part of the SOA record. You'll have to modify it here instead
|
|
# of modifying a zone file since it does not play well with a dynamically
|
|
# configured server it seems.
|
|
dnsSerialNumber = "2023020800";
|
|
dnsRefresh = "3h";
|
|
dnsUpdateRetry = "15m";
|
|
dnsExpiry = "3w";
|
|
dnsNxTTL = "3h";
|
|
|
|
corednsServiceName = "coredns";
|
|
|
|
domainZoneFile = pkgs.substituteAll {
|
|
src = ../../config/coredns/${domain}.zone;
|
|
inherit domain dnsSubdomain;
|
|
email = dnsEmail;
|
|
publicIPv4 = interfaces.main'.IPv4.address;
|
|
publicIPv6 = interfaces.main'.IPv6.address;
|
|
};
|
|
|
|
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;
|
|
|
|
# The final location of the thing.
|
|
domainZoneFile' = "/etc/coredns/zones/${domain}.zone";
|
|
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/mailbox-security-key" = { };
|
|
"dns/mailbox-security-key-record" = { };
|
|
};
|
|
|
|
# Generating a certificate for the DNS-over-TLS feature.
|
|
security.acme.certs."${dnsDomainName}".postRun = ''
|
|
systemctl restart ${corednsServiceName}.service
|
|
'';
|
|
|
|
# Setting up the firewall to make less things to screw up in case anything is
|
|
# screwed up.
|
|
networking.firewall.extraInputRules = ''
|
|
meta l4proto {tcp, udp} th dport 53 ip saddr { ${lib.concatStringsSep ", " secondaryNameServersIPv4} } accept comment "Accept DNS queries from secondary nameservers"
|
|
meta l4proto {tcp, udp} th dport 53 ip6 saddr { ${lib.concatStringsSep ", " secondaryNameServersIPv6} } accept comment "Accept DNS queries from secondary nameservers"
|
|
'';
|
|
|
|
# The main DNS server.
|
|
services.coredns = {
|
|
enable = true;
|
|
|
|
# NOTE: Currently, Hetzner DNS servers does not support DNSSEC. Will need
|
|
# to visit the following document periodically to see if they support but
|
|
# it is doubtful since they are doubting the benefits of supporting it. :(
|
|
#
|
|
# From what I can tell, it seems like DNSSEC is not much embraced by the
|
|
# major organizations yet so I'll wait with them on this one.
|
|
#
|
|
# https://docs.hetzner.com/dns-console/dns/general/dnssec
|
|
config = ''
|
|
(common) {
|
|
forward . /etc/resolv.conf
|
|
log
|
|
cache
|
|
errors
|
|
}
|
|
|
|
${fqdn} {
|
|
import common
|
|
|
|
bind ${interfaces.internal.IPv4.address} ${interfaces.internal.IPv6.address}
|
|
|
|
local
|
|
|
|
acl {
|
|
allow net ${lib.concatStringsSep " " (clientNetworks ++ serverNetworks)}
|
|
block
|
|
}
|
|
|
|
template ANY ANY {
|
|
authority "{{ .Zone }} IN SOA {{ .Zone }} ${dnsEmail} (1 60 60 60 60)"
|
|
fallthrough
|
|
}
|
|
|
|
template IN A {
|
|
answer "{{ .Zone }} IN 60 A ${interfaces.internal.IPv4.address}"
|
|
answer "{{ .Zone }} IN 60 A ${interfaces.internal.IPv4.address}"
|
|
}
|
|
|
|
template IN AAAA {
|
|
answer "{{ .Zone }} IN 60 AAAA ${interfaces.internal.IPv6.address}"
|
|
answer "{{ .Zone }} IN 60 AAAA ${interfaces.internal.IPv6.address}"
|
|
}
|
|
}
|
|
|
|
${domain} {
|
|
import common
|
|
|
|
bind lo {
|
|
# These are already taken from systemd-resolved.
|
|
except 127.0.0.53 127.0.0.54
|
|
}
|
|
|
|
acl {
|
|
# We're setting this up as a "hidden" primary server.
|
|
allow type AXFR net ${lib.concatStringsSep " " secondaryNameServersIPs}
|
|
allow type IXFR net ${lib.concatStringsSep " " secondaryNameServersIPs}
|
|
block type AXFR
|
|
block type IXFR
|
|
}
|
|
|
|
template IN NS {
|
|
${lib.concatStringsSep "\n "
|
|
(lib.lists.map
|
|
(ns: ''answer "{{ .Zone }} IN NS ${ns}"'')
|
|
secondaryNameserverDomains)}
|
|
}
|
|
|
|
file ${domainZoneFile'}
|
|
|
|
transfer {
|
|
to *
|
|
}
|
|
}
|
|
|
|
tls://${domain} {
|
|
import common
|
|
|
|
tls {$CREDENTIALS_DIRECTORY}/cert.pem {$CREDENTIALS_DIRECTORY}/key.pem {$CREDENTIALS_DIRECTORY}/fullchain.pem
|
|
}
|
|
'';
|
|
};
|
|
|
|
# This is based from the Gitea pre-start script.
|
|
systemd.services.${corednsServiceName} = {
|
|
requires = [ "acme-finished-${dnsDomainName}.target" ];
|
|
preStart =
|
|
let
|
|
secretsPath = path: config.sops.secrets."plover/${path}".path;
|
|
replaceSecretBin = "${lib.getBin pkgs.replace-secret}/bin/replace-secret";
|
|
in
|
|
lib.mkBefore ''
|
|
install -Dm0644 ${domainZoneFile} ${domainZoneFile'}
|
|
|
|
${replaceSecretBin} '#mailboxSecurityKey#' '${secretsPath "dns/mailbox-security-key"}' '${domainZoneFile'}'
|
|
${replaceSecretBin} '#mailboxSecurityKeyRecord#' '${secretsPath "dns/mailbox-security-key-record"}' '${domainZoneFile'}'
|
|
'';
|
|
serviceConfig.LoadCredential = let
|
|
certDirectory = certs."${dnsDomainName}".directory;
|
|
in
|
|
[
|
|
"cert.pem:${certDirectory}/cert.pem"
|
|
"key.pem:${certDirectory}/key.pem"
|
|
"fullchain.pem:${certDirectory}/fullchain.pem"
|
|
];
|
|
};
|
|
}
|