hosts/plover: replace dnsmasq with CoreDNS as DNS server

This commit is contained in:
Gabriel Arazas 2023-02-08 18:00:35 +08:00
parent 3787bf2e68
commit f75c04eaa9
No known key found for this signature in database
GPG Key ID: ADE0C41DAB221FCC
9 changed files with 289 additions and 23 deletions

View File

@ -0,0 +1,58 @@
; This is trying to be discrete with certain information. This should be copied
; and replaced with more confidential information somewhere.
; Take note we're not making the
$TTL 2h
$ORIGIN @domain@
@ IN SOA @dnsSubdomain@.@domain@ @email@ (
2023020800 ; serial number
3h ; refresh
15m ; update retry
3w ; expiry
3h ; nx = nxdomain ttl
)
; Setting up the mail-related DNS entries.
; For future references, please the see the following document at
; https://kb.mailbox.org/en/private/e-mail-article/using-e-mail-addresses-of-your-domain
@ IN MX 10 mxext1.mailbox.org
IN MX 10 mxext2.mailbox.org
IN MX 20 mxext3.mailbox.org
IN TXT v=spf1 include:mailbox.org ~all
_dmarc IN TXT v=DMARC1;p=none;rua=mailto:postmaster@foodogsquared.one
mbo0001._domainkey IN CNAME mbo0001._domainkey.mailbox.org.
mbo0002._domainkey IN CNAME mbo0002._domainkey.mailbox.org.
mbo0003._domainkey IN CNAME mbo0003._domainkey.mailbox.org.
mbo0004._domainkey IN CNAME mbo0004._domainkey.mailbox.org.
#mailboxSecurityKey# IN TXT #mailboxSecurityKeyRecord#
; My websites that are deployed by somewhere else.
@ IN ALIAS apex-loadbalancer.netlify.com.
www IN CNAME foodogsquared.netlify.app.
wiki IN CNAME foodogsquared-wiki.netlify.app.
; Public-facing services from this server.
auth IN A @publicIPv4@
auth IN AAAA @publicIPv6@
pass IN A @publicIPv4@
pass IN AAAA @publicIPv6@
code IN A @publicIPv4@
code IN AAAA @publicIPv6@
; Other things.
_github-pages-challenge-foo-dogsquared IN TXT 673febae1ea0095e76d1e02a7a1709
; Setting up SendGrid.
; This is for rewriting tracking links to my domain.
url2871 IN CNAME sendgrid.net
30339354 IN CNAME sendgrid.net
; This is for SendGrid sender authentication.
em1172 IN CNAME u30339354.wl105.sendgrid.net
s1._domainkey IN CNAME s1.domainkey.u30339354.wl105.sendgrid.net
s2._domainkey IN CNAME s2.domainkey.u30339354.wl105.sendgrid.net
; vim: expandtab! tabstop=8 shiftwidth=8 filetype=dns

View File

@ -22,6 +22,9 @@ in
# Hardened profile from nixpkgs.
"${modulesPath}/profiles/hardened.nix"
# The primary DNS server that is completely hidden.
./modules/services/coredns.nix
./modules/services/nginx.nix
# The database of choice which is used by most self-managed services on

View File

@ -50,15 +50,6 @@ in
dhcpcd.enable = false;
};
# The internal DNS server of choice.
services.dnsmasq = {
enable = true;
settings = {
listen-address = with interfaces.internal; [ IPv4.address IPv6.address ];
port = 3908;
};
};
# The main DNS server (not exactly by choice).
services.resolved = {
enable = true;
@ -103,6 +94,11 @@ in
IPv4.gateway
IPv6.gateway
];
networkConfig.DNS = [
"127.0.0.1"
"::1"
];
};
};
};

View File

@ -6,6 +6,16 @@ let
in
rec {
privateIPv6Prefix = "fdee:b0de:5685";
clientNetworks = [
"172.24.0.0/13"
"10.128.0.0/9"
];
serverNetworks = [
"172.16.0.0/13"
"10.0.0.0/9"
];
interfaces = let
ploverInternalNetworkGateway = "172.16.0.1";
widdeerLan = "10.0.0.1";
@ -79,4 +89,19 @@ rec {
IPv6 = "${wireguardIPv6Prefix}3";
};
};
secondaryNameServers = {
"ns1.first-ns.de." = {
IPv4 = [ "213.239.242.238" ];
IPv6 = [ "2a01:4f8:0:a101::a:1" ];
};
"robotns2.second-ns.de." = {
IPv4 = [ "213.133.105.6" ];
IPv6 = [ "2a01:4f8:d0a:2004::2" ];
};
"robotns3.second-ns.com." = {
IPv4 = [ "193.47.99.3" ];
IPv6 = [ "2001:67c:192c::add:a3" ];
};
};
}

View File

@ -30,9 +30,6 @@ in
'';
};
# Attaching the domain name to the DNS server.
services.dnsmasq.settings.address = [ "/${atuinInternalDomain}/${host}" ];
# Putting it altogether in the reverse proxy of choice.
services.nginx.virtualHosts."${atuinInternalDomain}" = {
locations."/" = {

View File

@ -0,0 +1,189 @@
{ 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"
];
};
}

View File

@ -12,7 +12,7 @@ let
keycloakDbName = if config.services.keycloak.database.createLocally then keycloakUser else config.services.keycloak.database.username;
certs = config.security.acme.certs;
host = interfaces.internal.IPv4.address;
host = "127.0.0.1";
in
{
# Hey, the hub for your application sign-in.
@ -69,9 +69,6 @@ in
'';
};
# Attach an domain name to the DNS server.
services.dnsmasq.settings.address = [ "/${authInternalDomain}/${host}" ];
# Attaching it to the reverse proxy of choice.
services.nginx.virtualHosts = {
"${authDomain}" = {

View File

@ -58,11 +58,9 @@ in
matchConfig.Name = wireguardIFName;
networkConfig = {
DNS = with interfaces.internal; let
internalDNSPort = config.services.dnsmasq.settings.port;
in [
"${IPv4.address}:${toString internalDNSPort}"
"${IPv6.address}:${toString internalDNSPort}"
DNS = with interfaces.internal; [
"127.0.0.1"
"::1"
];
Domains = lib.concatStringsSep " " internalDomains;
DNSDefaultRoute = false;

View File

@ -36,6 +36,9 @@ wireguard:
preshared-keys:
ni: ENC[AES256_GCM,data:NAgNnVtPKCaaSagWCIet5pd5ZehymJPmhQShoO/ktqa1pl6MtzJsygbTktk=,iv:2/sOdNN6QX1Rou5xnq87t/m/kguPTthOXD8oXJfvM90=,tag:F/I2CYR9O1LAlLs/9LaXGg==,type:str]
phone: ENC[AES256_GCM,data:3wIv8mE7eYhvSjwcE9fwsUZhh2Svmzg+RFjJzvjvMyB9V3uvBYG8vmB751w=,iv:iSm4dXNVqFa52eq0Hhct1MGSoq4x7FFzWdjXHlkGTW8=,tag:Lr463ee5r/ZhEC78uYyzfQ==,type:str]
dns:
mailbox-security-key: ENC[AES256_GCM,data:e1/y+JNNUxdf5D0OVhTD8hsoPlvV2Jpp3/+nHBktZH02/ZOfa9W5oA==,iv:tR9aVFHuMekr2uz4MaGAddlRsAh9XctS25EO+yMyvhE=,tag:BImSGpx4ltuU1qPTrmioKg==,type:str]
mailbox-security-key-record: ENC[AES256_GCM,data:bP1kKQczfjOQyokOa+cScNs7jKLaXamUHYqzW7k0QRXnin5Nsj7G9w==,iv:l8NtJcYll8rdQJLsuxPIj3Ch3Tc/ESs1wUwPrGRTI7Y=,tag:RWD9mvinKW0xv6GDw/4jkQ==,type:str]
sops:
kms: []
gcp_kms: []
@ -51,8 +54,8 @@ sops:
ZCtNbnFqdzNkVlBtNjVCdE4yNHMrRjQKfFV4GaReO0UO81xsTB0EuN5ibVsafXJY
miBgZAZWbJjSBcM4X+Fym/DlxHRoB1a6iFEFN9yg+Z9WI8PfjKnbsA==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2023-01-17T09:10:51Z"
mac: ENC[AES256_GCM,data:wzxOoyd+Zq6Fna1GxCZ6Uha6rdW3xVRx3uJniyuJ6TpGCpMoCzv9O0F7JgYyK7je2GR1RomynECEGu84re46yK9AkwV9KKWXVAs8jaI9QeZ6usEbFdr7KmyLFZbO/OMP72OIV03wxJ7Hguz2snF5ONjjhbAfZ2n+xXTofFJqBZY=,iv:cMZdVJQ4Vpf1FB70De3Rf/iMqp2Uv1QARp6897bew1A=,tag:rRx+ufoCVqqOGWhURxo6aQ==,type:str]
lastmodified: "2023-02-08T09:58:04Z"
mac: ENC[AES256_GCM,data:VJiZJclfId8pwfKNKyRWtMVX3e6yAjrQmEmQPbW/0nQCxfSe6ixapmoEheMEaF1WbJe0sOiKV8i3GZbxW+aLX9RN6+fOB/lKqSUigQOLgFjs9fgDG9WN4HCzeWPWm+vkfsL3+A5T3ucKHyqjEFJ91BpcA1x+fa5qNAnnaXCifJM=,iv:/oPeVaLbu+yWXF86b8Dc16JuuhCDlJKluK+GrQl0VMU=,tag:0ox7Qf8FdPtOY9GXkqAhkQ==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.7.3