mirror of
https://github.com/foo-dogsquared/nixos-config.git
synced 2025-01-31 22:57:55 +00:00
Gabriel Arazas
eb1003f7e6
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.
171 lines
5.1 KiB
Nix
171 lines
5.1 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) privateIPv6Prefix interfaces clientNetworks serverNetworks secondaryNameServers wireguardPeers;
|
|
|
|
domainZoneFile = pkgs.substituteAll {
|
|
ploverPublicIPv4 = interfaces.main'.IPv4.address;
|
|
ploverPublicIPv6 = interfaces.main'.IPv6.address;
|
|
src = ../../config/dns/${domain}.zone;
|
|
};
|
|
|
|
# The final location of the thing.
|
|
domainZoneFile' = "/etc/coredns/zones/${domain}.zone";
|
|
|
|
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 local network segments.
|
|
allowedIPs = secondaryNameServersIPv4 ++ [
|
|
# Loopback address
|
|
"127.0.0.0/8"
|
|
|
|
# Private uses
|
|
"10.0.0.0/8"
|
|
"172.16.0.0/12"
|
|
"192.168.0.0/16"
|
|
];
|
|
allowedIPv6s = secondaryNameServersIPv6 ++ [
|
|
"::1" # Loopback
|
|
"${privateIPv6Prefix}::/48" # Private uses
|
|
];
|
|
|
|
mainIP = with interfaces.main'; [
|
|
IPv4.address
|
|
IPv6.address
|
|
];
|
|
|
|
internalIP = with interfaces.internal; [
|
|
IPv4.address
|
|
IPv6.address
|
|
];
|
|
|
|
wireguardIP = with wireguardPeers.server; [
|
|
IPv4 IPv6
|
|
];
|
|
|
|
dnsListenInterfaces = (with interfaces; [
|
|
"127.0.0.1"
|
|
"::1"
|
|
]) ++ mainIP ++ internalIP ++ wireguardPeers;
|
|
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" = { };
|
|
};
|
|
|
|
# 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 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"
|
|
'';
|
|
|
|
# For more information how the server is set up, you could take a look at the
|
|
# hardware networking configuration.
|
|
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 = ''
|
|
# The LAN.
|
|
${fqdn} {
|
|
bind ${interfaces.internal.ifname}
|
|
acl {
|
|
# Hetzner doesn't support DNSSEC yet though.
|
|
block type DS SIG RRSIG TA TSIG PTR DLV DNSKEY KEY NSEC NSEC3
|
|
|
|
allow net ${lib.concatStringsSep " " (clientNetworks ++ serverNetworks)}
|
|
allow net 127.0.0.0/8 ::1
|
|
block
|
|
}
|
|
|
|
template IN A {
|
|
answer "{{ .Name }} IN 60 A ${interfaces.internal.IPv4.address}"
|
|
}
|
|
|
|
template IN AAAA {
|
|
answer "{{ .Name }} IN 60 AAAA ${interfaces.internal.IPv6.address}"
|
|
}
|
|
}
|
|
|
|
# The WAN.
|
|
${domain} {
|
|
bind ${interfaces.main'.ifname}
|
|
|
|
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}
|
|
|
|
# This will allow internal clients connect to the subdomains that
|
|
# have internal resources.
|
|
allow net ${lib.concatStringsSep " " (clientNetworks ++ serverNetworks)}
|
|
allow net 127.0.0.0/8 ::1
|
|
|
|
# Otherwise, it's just really a primary server that is hidden
|
|
# somewhere (or just very shy, whichever of the two).
|
|
block
|
|
}
|
|
|
|
file ${domainZoneFile'} {
|
|
reload 30s
|
|
}
|
|
|
|
transfer {
|
|
to ${lib.concatStringsSep " " secondaryNameServersIPs}
|
|
}
|
|
}
|
|
|
|
# The NAN.
|
|
. {
|
|
cache
|
|
forward . /etc/resolv.conf
|
|
|
|
log ${domain} {
|
|
class success error
|
|
}
|
|
|
|
errors {
|
|
consolidate 1m "^.* no next plugin found$"
|
|
}
|
|
}
|
|
'';
|
|
};
|
|
}
|