feat: Unbound DNS-Resolver — vollständig (Renderer + Handler + UI)

Stub raus, vollständig implementiert:

* Migration 0014: dns_settings (single-row) + dns_zones.forward_to.
  Default-Settings sind sinnvoll für die typische LAN-Resolver-Rolle
  (1.1.1.1 + 9.9.9.9 upstream, localnet allow, DNSSEC + qname-min on).
* internal/services/dns: CRUD-Repo für zones, records, settings.
* internal/handlers/dns.go: REST /api/v1/dns/zones, /records, /settings
  mit Auto-Reload nach jeder Mutation.
* internal/unbound/unbound.cfg.tpl + unbound.go: Renderer schreibt
  /etc/unbound/unbound.conf.d/edgeguard.conf direkt (kein Symlink-
  Dance, weil AppArmor unbound nur /etc/unbound erlaubt). Local-zones
  authoritativ aus dns_records; forward-zones per stub-zone; default-
  forwarders catchen alles sonst.
* main.go: dnsRepo + unbound-Reloader injiziert.
* render.go: unbound.New() bekommt Pool.
* postinst:
  - Conf-Datei /etc/unbound/unbound.conf.d/edgeguard.conf wird als
    edgeguard:edgeguard 0644 angelegt damit Renderer schreiben kann.
  - /etc/edgeguard + Service-Subdirs auf 0755 (Squid + Unbound laufen
    NICHT als edgeguard, brauchen Read-Traversal).
  - Sudoers: systemctl reload unbound.service whitelisted.
* Template: chroot:"" (Conf liegt außerhalb /var/lib/unbound default-
  chroot), DNSSEC-Trust-Anchor NICHT setzen (Distro hat schon
  root-auto-trust-anchor-file.conf — sonst doppelter Anchor → start
  failure).
* Frontend /dns: PageHeader + zwei Tabs (Zones + Resolver-Settings).
  Zones-Tab mit Drawer für Records (CRUD pro Zone, A/AAAA/CNAME/TXT/
  MX/SRV/NS/PTR/CAA). Sidebar-Eintrag unter Network.
* i18n DE/EN für dns.* Block.

Verified end-to-end: render → unbound restart → dig @127.0.0.1
example.com → 104.20.23.154 / 172.66.147.243.

Version 1.0.34 (mehrere Iterationen wegen AppArmor + chroot + perms).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Debian
2026-05-11 06:24:51 +02:00
parent 72269f5b7c
commit e537d70e04
19 changed files with 1416 additions and 23 deletions

View File

@@ -20,10 +20,17 @@ case "$1" in
fi
# ── Directories ──────────────────────────────────────────────
for d in /etc/edgeguard /var/lib/edgeguard /var/log/edgeguard \
/etc/edgeguard/haproxy /etc/edgeguard/squid \
# /etc/edgeguard und Service-Subdirs müssen für die Service-User
# (squid, unbound, haproxy laufen NICHT als edgeguard) traversier-
# bzw lesbar sein. 0755 statt 0750 — kein Geheimnis ist hier
# gespeichert, alles sind Renderer-Outputs.
for d in /etc/edgeguard /etc/edgeguard/haproxy /etc/edgeguard/squid \
/etc/edgeguard/wireguard /etc/edgeguard/unbound \
/etc/edgeguard/nftables.d /etc/edgeguard/tls \
/etc/edgeguard/nftables.d; do
install -d -m 0755 -o "$EG_USER" -g "$EG_USER" "$d"
done
# Sensitive Verzeichnisse bleiben 0750 (TLS-Keys, ACME-State).
for d in /etc/edgeguard/tls /var/lib/edgeguard /var/log/edgeguard \
/var/lib/edgeguard/acme; do
install -d -m 0750 -o "$EG_USER" -g "$EG_USER" "$d"
done
@@ -49,7 +56,38 @@ edgeguard ALL=(root) NOPASSWD: /usr/bin/wg show all dump
edgeguard ALL=(root) NOPASSWD: /usr/bin/wg show *
edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl reload squid.service
edgeguard ALL=(root) NOPASSWD: /bin/systemctl reload squid.service
edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl reload unbound.service
edgeguard ALL=(root) NOPASSWD: /bin/systemctl reload unbound.service
SUDOERS
# ── Distro-Conf-Includes für die per-Service Renderer ─────────
# Squid + Unbound lesen ihre Distro-Default-Conf, die wir per
# Symlink/Drop-in auf unsere managed conf zeigen lassen müssen.
# Renderer können das nicht selbst (kein Schreibrecht in /etc/squid
# bzw. /etc/unbound/unbound.conf.d/), daher hier einmalig.
# Plus: Squid + Unbound laufen als eigene User (squid/unbound),
# nicht edgeguard. Damit sie unsere Conf lesen können, müssen
# die Conf-Dirs world-readable sein (Configs ohne Secrets).
install -d -m 0755 -o "$EG_USER" -g "$EG_USER" /etc/edgeguard/squid /etc/edgeguard/unbound
# Squid: ersetzt die Distro-Datei durch Symlink (Backup .distro-bak)
if [ -f /etc/squid/squid.conf ] && [ ! -L /etc/squid/squid.conf ]; then
mv /etc/squid/squid.conf /etc/squid/squid.conf.distro-bak
fi
ln -sfn /etc/edgeguard/squid/squid.conf /etc/squid/squid.conf
# Unbound: Drop-in im conf.d-Verzeichnis. Wir schreiben direkt
# rein (statt /etc/edgeguard/unbound/...) weil das AppArmor-
# Profil unbound nur /etc/unbound erlaubt. Datei gehört dem
# edgeguard-User damit der Renderer sie überschreiben kann.
install -d /etc/unbound/unbound.conf.d
# Vorgänger-Symlink (aus früheren Versionen) wegräumen.
if [ -L /etc/unbound/unbound.conf.d/edgeguard.conf ]; then
rm /etc/unbound/unbound.conf.d/edgeguard.conf
fi
if [ ! -f /etc/unbound/unbound.conf.d/edgeguard.conf ]; then
: > /etc/unbound/unbound.conf.d/edgeguard.conf
fi
chown "$EG_USER":"$EG_USER" /etc/unbound/unbound.conf.d/edgeguard.conf
chmod 0644 /etc/unbound/unbound.conf.d/edgeguard.conf
chmod 0440 /etc/sudoers.d/edgeguard
# ── Sysctl-Profil für Edge-Gateway (NAT + HAProxy + Forwarding) ──