Reflect web01 in the machines table and monitoring scrape list, note Grafana is now also published publicly via web01's reverse proxy, add the CNX Uptime dashboard, and document the dedicated acme_mx1/acme_web01 DNS-01 keys.
3.8 KiB
DNS
Authoritative DNS for three zones, served by Knot:
cnx.networkbuildfor.lifecnx.email
Add a zone in modules/dns/domains.nix and drop a matching <domain>.zone
file in modules/dns/zones/.
Primary / secondary
ns1= primary (master). Loads each zone from its file, signs it, and notifiesns2. Config inmachines/ns1/configuration.nix.ns2= secondary (slave). Pulls every zone fromns1(AXFR/IXFR) and accepts its NOTIFY. Config inmachines/ns2/configuration.nix.
Zone transfers run over the ZeroTier mesh, authenticated with a shared TSIG
key (dns-tsig, a clan var copied to both machines).
Serial handling
ns1 uses zonefile-load = difference-no-serial with serial-policy = unixtime:
edit records without touching the SOA serial — Knot diffs the file, assigns a
strictly-monotonic unixtime serial, signs, and transfers. journal-content = all
holds the live signed zone (required by difference-no-serial).
DNSSEC
Automatic signing on ns1 only, policy cnx: ECDSA P-256/SHA-256. The ZSK
auto-rolls; the KSK is kept stable, so the DS at the registrar only changes on a
manual KSK rollover.
Registrar DS records
Knot manages all key material itself on ns1 (the only signer); the KSK/ZSK
private keys live in the KASP keystore under /var/lib/knot (backed up nightly —
see Backups). You never touch the private keys directly.
What a registrar needs is the DS record for a zone's KSK, which anchors the
zone into the parent's chain of trust. Generate it on ns1 — the keymgr wrapper
is already pointed at Knot's config, and it runs as the knot user that owns the
keystore:
sudo -u knot keymgr <zone> ds
e.g. sudo -u knot keymgr cnx.email ds. Paste the printed DS record (key tag,
algorithm 13, digest type, digest) into the registrar's DNSSEC form for that
domain. Repeat per signed zone (cnx.network, buildfor.life, cnx.email) at
whichever registrar holds each delegation. After submitting, confirm the parent
publishes it with dig +short DS <zone>.
The ZSK rolls automatically and needs no registrar action; only a KSK rollover requires re-submitting the DS.
Pending (manual): submit DS records for
buildfor.lifeandcnx.emailonce they're at a DNSSEC-capable registrar.
ACME DNS-01
Certificates are issued by _acme-challenge TXT updates that ns1 accepts over
TSIG, signs, and transfers to ns2 (which never needs these keys). Each consumer
gets its own key, scoped by an ACL to exactly the owner names it needs and
attached only to the zone it lives in — so a leaked key can write nothing but its
own challenges.
acme_ddns(acl_acme) — the general key, scoped toTXTat or under_acme-challenge.<zone>and attached to every zone. Client config:clan vars get ns1 dns-acme-tsig/acme.confacme_mx1(acl_acme_mx1) — held only bymx1, scoped to_acme-challenge.{mx1,mta-sts,mail}and attached only tocnx.email(the mail cert plus its MTA-STS and client-alias SANs). Secret shared via thedns-acme-mx1-secretgenerator.acme_web01(acl_acme_web01) — held only byweb01, scoped to_acme-challengeand attached only tocnx.network(where the wildcard*.cnx.networkchallenge lands, at the apex). Secret shared via thedns-acme-web01-secretgenerator.
Runbook: stale secondary
If ns2 serves stale records while SOA serials match (e.g. after a manual zone
edit that didn't bump the serial as expected), force a fresh transfer on ns2:
knotc zone-retransfer <zone>
Watch the CNX DNS Grafana dashboard: the per-nameserver SOA serial table
should agree across ns1/ns2, and "seconds until zone expiry" on the secondary
should reset on each successful transfer rather than counting toward zero.