Dynamische DNS-Zonen und DNSSEC schließen sich nicht aus. Mit BIND 9.20 lässt sich eine bestehende, per DHCP/DDNS gepflegte Zone nachträglich auf DNSSEC mit automatischer Schlüsselverwaltung und Inline-Signing umstellen.
In diesem Projekt ging es darum, mehrere bereits produktiv verwendete dynamische Zonen eines internen DNS-Servers nachträglich mit DNSSEC abzusichern. Dabei zeigte sich allerdings ein interessanter Fehlerzustand: Nach der Aktivierung von Inline-Signing wurden DDNS-Änderungen zwar in der unsignierten Zone angenommen, aber nicht mehr in der signierten Zone sichtbar.
Die anschließende Reparatur war ein kleines, aber lehrreiches BIND-Recovery-Projekt.
Die Umgebung bestand aus zwei BIND-DNS-Servern:
Die internen DNS-Namen und Netzwerke sind in diesem Artikel anonymisiert.
Die DHCP-Infrastruktur aktualisierte unter anderem:
example.internal.
168.192.in-addr.arpa.
16.172.in-addr.arpa.
Die Forward-Zone und die beiden Reverse-Zonen wurden bereits dynamisch per DDNS gepflegt.
Zusätzlich gab es eine wichtige Anforderung:
Die Zonen müssen weiterhin gelegentlich manuell bearbeitet werden können.
Das bedeutet, dass eine reine Dynamic-DNS-Konfiguration ohne Inline-Signing keine Option war. Die manuelle Bearbeitung erfolgt weiterhin über:
rndc freeze <zone>
Datei bearbeiten, anschließend:
rndc thaw <zone>
Dabei muss bei manuellen Änderungen selbstverständlich auch die SOA-Serial erhöht werden.
BIND kann DNSSEC auf unterschiedliche Arten mit dynamischen Zonen kombinieren.
Bei einer dynamischen DNSSEC-Zone ohne Inline-Signing werden die DNSSEC-Daten direkt in der dynamischen Zone beziehungsweise deren Journal verwaltet.
Bei Inline-Signing existieren dagegen zwei Zustände:
+-------------------+
DDNS ----------> | unsigned zone |
| example.zone |
+---------+---------+
|
| Inline-Signing
v
+-------------------+
| signed zone |
| example.zone.signed|
+-------------------+
Das hat für diesen Anwendungsfall einen entscheidenden Vorteil:
Die ursprüngliche Zone bleibt die Quelle der administrativen Änderungen, während BIND daraus automatisch die signierte Version erzeugt.
Das passt gut zu einer Umgebung, in der sowohl DDNS-Updates als auch gelegentliche manuelle Änderungen stattfinden.
Vor der Migration wurde zunächst geprüft, ob die vorhandenen Zonen überhaupt mit der konfigurierten maximalen TTL kompatibel waren.
In der BIND-Konfiguration war beispielsweise eine maximale TTL von:
86400
gesetzt.
Die vorhandenen Zonen enthielten teilweise noch Einträge wie:
$TTL 259200 ; 3 days
Das verhinderte die Aktivierung der DNSSEC-Konfiguration.
Die betroffenen TTLs wurden daher zunächst auf einen zulässigen Wert reduziert, beispielsweise:
$TTL 1200 ; 20 minutes
Anschließend wurde die Zone mit:
named-checkzone example.internal. /var/named/example.hosts
geprüft.
Erst wenn named-checkzone die Zone mit OK bestätigte, wurde die Konfiguration weiter geändert.
Für eine Zone sah die Konfiguration anschließend beispielsweise so aus:
zone "example.internal." {
type master;
file "example.hosts";
dnssec-policy default;
inline-signing yes;
allow-update { key DHCP_UPDATER; };
allow-transfer { 192.0.2.66; };
also-notify { 192.0.2.66; };
notify yes;
};
Bei den Reverse-Zonen war die Konfiguration entsprechend:
zone "16.172.in-addr.arpa." {
type master;
file "172.16.rev";
dnssec-policy default;
inline-signing yes;
allow-update { key DHCP_UPDATER; };
allow-transfer { 192.0.2.66; };
also-notify { 192.0.2.66; };
notify yes;
};
Danach:
named-checkconf
und anschließend:
rndc reconfig
Der Zustand der Zone lässt sich mit:
rndc zonestatus 16.172.in-addr.arpa.
prüfen.
Ein erfolgreicher Zustand sieht beispielsweise so aus:
name: 16.172.in-addr.arpa.
type: primary
files: 172.16.rev
serial: 2026092919
signed serial: 2026092929
nodes: 28
secure: yes
inline signing: yes
key maintenance: automatic
dynamic: yes
frozen: no
Besonders interessant sind:
secure: yes
inline signing: yes
dynamic: yes
Damit ist zunächst bestätigt, dass BIND die Zone als DNSSEC-geschützte dynamische Inline-Signing-Zone verwaltet.
Als nächstes wurde ein bereits existierender PTR-Eintrag geprüft:
dig @127.0.0.1 -x 172.16.0.147 +dnssec
Die Antwort enthielt neben dem PTR-Eintrag eine RRSIG:
ANSWER SECTION:
147.0.16.172.in-addr.arpa. 1200 IN PTR one-device.example.internal.
147.0.16.172.in-addr.arpa. 1200 IN RRSIG PTR ...
Damit war klar:
Die vorhandenen Daten werden korrekt signiert.
Anschließend wurde derselbe Eintrag auf dem Secondary geprüft:
dig @192.0.2.66 -x 172.16.0.147 +dnssec
Auch dort erschienen PTR und RRSIG.
Nun wurde ein temporärer PTR-Eintrag per DDNS erzeugt:
server 127.0.0.1
zone 16.172.in-addr.arpa.
update add 251.1.16.172.in-addr.arpa. 1200 PTR dnssec-test.example.internal.
send
Der DNS-Update wurde mit:
status: NOERROR
akzeptiert.
Das sah zunächst gut aus.
Eine anschließende Abfrage ergab jedoch:
status: NXDOMAIN
Der neue PTR war nicht sichtbar.
Noch interessanter wurde es mit:
rndc zonestatus 16.172.in-addr.arpa.
Die Ausgabe zeigte:
serial: 2026092918
signed serial: 2026092927
nodes: 28
Die unsignierte Zone hatte sich also verändert.
Die signierte Zone war dagegen nicht nachgezogen worden.
Troubleshooting: DDNS-Update mit
NOERROR, aber Datensatz nicht sichtbarWenn
nsupdatemitNOERRORendet, der neue Datensatz anschließend aber weder in der DNS-Abfrage noch in der signierten Zone erscheint, lohnt sich zunächst:rndc zonestatus <zone>Achte insbesondere darauf, ob sich
serialder unsignierten Zone erhöht, währendsigned serialunverändert bleibt.Im Log können in diesem Fall Meldungen wie
dns_diff_apply: ... del not exact receive_secure_serial: not exactauftauchen. Das deutet darauf hin, dass die unsignierte und die signierte Version der Inline-Signing-Zone nicht mehr konsistent sind.
Wichtig: Nicht sofort die Zone neu erstellen oder
inline-signingabschalten. Zuerst ein vollständiges Backup von Zone und Journals erstellen. Anschließend kann die signierte Arbeitskopie kontrolliert neu aufgebaut werden.
Ein Blick in das Journal zeigte:
dns_diff_apply: 16.0.16.172.in-addr.arpa/PTR/IN: del not exact
zone 16.172.in-addr.arpa/IN (signed): receive_secure_serial: not exact
Diese beiden Meldungen waren der entscheidende Hinweis.
Die unsignierte Zone funktionierte weiterhin.
Das DDNS-Update wurde angenommen und in das Journal der unsignierten Zone geschrieben.
Der Inline-Signer konnte die Änderung jedoch nicht auf die bereits vorhandene signierte Zone anwenden.
Der Zustand war damit vereinfacht:
DDNS
|
v
+---------------+
| unsigned zone |
| OK |
+-------+-------+
|
X
Synchronisation
|
v
+---------------+
| signed zone |
| veraltet |
+---------------+
Bevor irgendeine Recovery-Maßnahme durchgeführt wurde, wurden alle relevanten Dateien gesichert.
Bei der Reverse-Zone:
mkdir -p /root/bind-recovery-YYYYMMDD/172.16-before-repair
cp -a /var/named/172.16.rev \
/var/named/172.16.rev.jnl \
/root/bind-recovery-YYYYMMDD/172.16-before-repair/
cp -a /var/named/172.16.rev.signed \
/var/named/172.16.rev.signed.jnl \
/root/bind-recovery-YYYYMMDD/172.16-before-repair/
Damit konnte jederzeit auf den ursprünglichen Zustand zurückgegriffen werden.
Das ist bei einer DNSSEC-Recovery besonders wichtig: Die Journals enthalten unter Umständen Änderungen, die noch nicht in der eigentlichen Zonendatei stehen.
Als nächstes wurde:
rndc sync -clean 16.172.in-addr.arpa.
ausgeführt.
Damit wurden die noch offenen Änderungen des unsignierten Journals in die Zonendatei übernommen.
Danach zeigte zonestatus weiterhin:
serial: 2026092918
signed serial: 2026092927
Die signierte Zone war also weiterhin veraltet.
Nun wurde BIND kontrolliert gestoppt:
systemctl stop named
Anschließend wurde geprüft:
systemctl is-active named
Erwartet:
inactive
Die vorhandene signierte Zone wurde nicht gelöscht, sondern zunächst nur umbenannt:
mv /var/named/172.16.rev.signed \
/var/named/172.16.rev.signed.recovery-old
Interessanterweise war das signierte Journal zu diesem Zeitpunkt bereits nicht mehr vorhanden. Das war kein Problem.
Die ursprüngliche Zonendatei blieb unangetastet.
Anschließend wurde BIND wieder gestartet:
systemctl start named
BIND erzeugte die signierte Zone daraufhin aus dem aktuellen Stand der unsignierten Zone neu.
rndc zonestatus zeigte nun:
serial: 2026092918
signed serial: 2026092928
nodes: 28
secure: yes
inline signing: yes
dynamic: yes
Die signierte Serial hatte sich erhöht.
Der zuvor fehlende DDNS-Eintrag war nun ebenfalls wieder sichtbar:
dig @127.0.0.1 251.1.16.172.in-addr.arpa. PTR +dnssec
Antwort:
status: NOERROR
ANSWER SECTION:
251.1.16.172.in-addr.arpa. 1200 IN PTR dnssec-test-172.example.internal.
251.1.16.172.in-addr.arpa. 1200 IN RRSIG PTR ...
Damit war bewiesen:
Der Inline-Signer arbeitet wieder korrekt mit der dynamischen Zone zusammen.
Anschließend wurde derselbe Datensatz auf dem Secondary geprüft:
dig @192.0.2.66 251.1.16.172.in-addr.arpa. PTR +dnssec
Auch dort erschienen:
PTR
RRSIG
und zwar mit derselben Signatur.
Damit war auch die Replikation des reparierten Zustands erfolgreich.
Zum Abschluss wurde der temporäre PTR wieder über DDNS gelöscht:
server 127.0.0.1
zone 16.172.in-addr.arpa.
update delete 251.1.16.172.in-addr.arpa. PTR
send
Auch dieser Update wurde mit:
status: NOERROR
bestätigt.
Eine anschließende Abfrage:
dig @127.0.0.1 251.1.16.172.in-addr.arpa. PTR +dnssec
ergab:
status: NXDOMAIN
und enthielt zusätzlich:
SOA
RRSIG SOA
NSEC
RRSIG NSEC
Das ist ein wichtiger Test, denn damit wurde nicht nur die positive DNSSEC-Antwort geprüft, sondern auch die korrekte Signierung negativer Antworten.
Die Gegenprobe auf dem Secondary ergab dasselbe Ergebnis.
Bei der Migration der Forward-Zone wurde zusätzlich eine manuelle Änderung getestet.
Dafür wurde die Zone zunächst eingefroren:
rndc freeze example.internal.
Nach der Änderung der Zonendatei wurde die SOA-Serial erhöht und die Zone geprüft:
named-checkzone example.internal. /var/named/example.hosts
Danach:
rndc thaw example.internal.
Die Änderung wurde anschließend sowohl auf dem Primary als auch auf dem Secondary mit RRSIG ausgeliefert.
Ein wichtiger Punkt dabei:
Bei manuellen Änderungen muss die SOA-Serial erhöht werden.
Nur eine Änderung der Zonendatei ohne Erhöhung der Serial reicht bei diesem Setup nicht zuverlässig aus, damit die Änderung in die signierte Zone übernommen und repliziert wird.
Das Projekt hat einige interessante Punkte gezeigt.
Kea DHCP-DDNS kann weiterhin ganz normal DNS-Updates durchführen.
DNSSEC ist dabei für die DHCP-Infrastruktur transparent.
Der Ablauf lautet:
Kea DHCP
|
| authenticated DNS UPDATE
v
BIND unsigned zone
|
| inline signing
v
BIND signed zone
|
+----> Secondary
dnssec-policy default vereinfacht die SchlüsselverwaltungBIND übernimmt bei Verwendung einer DNSSEC Policy die automatische Schlüsselverwaltung und die regelmäßige Erneuerung beziehungsweise Pflege der Schlüssel.
Dadurch muss nicht für jede Zone manuell eine komplette DNSSEC-Key-Infrastruktur aufgebaut werden.
inline-signing ist für diesen Anwendungsfall sinnvollDie Zone bleibt dynamisch und kann weiterhin über DDNS aktualisiert werden.
Gleichzeitig bleibt die Möglichkeit erhalten, die Zone kontrolliert mit:
rndc freeze
und:
rndc thaw
manuell zu bearbeiten.
receive_secure_serial: not exact ist ernst zu nehmenDiese Meldung sollte nicht einfach ignoriert werden.
In unserem Fall bedeutete sie:
Die signierte und die unsignierte Zone waren intern nicht mehr synchron.
Die unsignierte Zone konnte weiterhin Updates annehmen, während die signierte Zone diese Änderungen nicht mehr korrekt übernahm.
Das kann besonders gefährlich sein, wenn der Fehler unbemerkt bleibt: DNS-Updates scheinen erfolgreich zu sein, werden aber von DNSSEC-signierten Abfragen nicht sichtbar.
Bei einer dynamischen Zone darf man nicht einfach nur die Zonendatei betrachten.
Relevant sind unter anderem:
zone
zone.jnl
zone.signed
zone.signed.jnl
Deshalb sollte vor einer Reparatur immer eine Sicherung des kompletten relevanten Zustands erstellt werden.
Für einen vergleichbaren Fehler würde ich heute folgenden Ablauf verwenden:
1. Fehler reproduzieren bzw. eindeutig feststellen
|
v
2. zonestatus prüfen
|
v
3. Logs prüfen
receive_secure_serial: not exact
|
v
4. alle Zone-/Journal-Dateien sichern
|
v
5. rndc sync -clean
|
v
6. named kontrolliert stoppen
|
v
7. signed + signed.jnl sichern/verschieben
|
v
8. named starten
|
v
9. zonestatus prüfen
|
v
10. DDNS-Test
|
v
11. Primary + Secondary prüfen
|
v
12. DDNS-Löschtest
|
v
13. NXDOMAIN + NSEC + RRSIG prüfen
Wichtig ist dabei:
Keine Dateien löschen, bevor eine Sicherung des Zustands existiert.
Die nachträgliche Migration einer produktiven dynamischen BIND-Zone auf DNSSEC mit Inline-Signing ist grundsätzlich unkompliziert.
Die eigentliche Herausforderung liegt weniger in der DNSSEC-Konfiguration als in der sauberen Behandlung des bestehenden dynamischen Zustands.
In diesem Projekt funktionierte die Aktivierung von DNSSEC zunächst problemlos. Erst der erste echte DDNS-Update zeigte, dass die signierte und unsignierte Zone intern nicht mehr sauber synchronisiert waren.
Die Fehlermeldungen
dns_diff_apply: ... del not exact
receive_secure_serial: not exact
waren dabei der entscheidende Hinweis.
Durch:
konnte die Zone ohne Datenverlust wieder in einen konsistenten Zustand gebracht werden.
Am Ende stand eine Konfiguration, die gleichzeitig:
unterstützt.
Für mich ist genau das der interessante Teil des Projekts: Nicht die Aktivierung von DNSSEC war die eigentliche Herausforderung, sondern der Moment, in dem eine scheinbar erfolgreiche Konfiguration beim ersten echten DDNS-Update ihren Fehlerzustand offenbarte – und die anschließende kontrollierte Recovery.