Über die Techniken DoT (DNS over TLS) habe ich bereits im Zusammenhang mit Bind 9.16 geschrieben. Ebenfalls DoH (DNS over HTTPS) gibt es einen kleinen Beitrag.
Zu diesem Zeitpunkt bracht BIND 9 die Unterstützung für DoH und DoT noch nicht selbst mit. Daher waren zu diesem Zeitpunkt noch Umwege über stunnel oder nginx zusammen mit doh-proxy nötig.
Zum Glück kommt die letzte stable Version 9.18.0 (26. Januar 2022) mit dem nötigen Support.
named now supports securing DNS traffic using Transport Layer Security (TLS). TLS is used by both DNS over TLS (DoT) and DNS over HTTPS (DoH).
Warum möchte man noch gleich DoH oder DoT benutzen? Ganz einfach… Über diese Techniken werden DNS Abfragen verschlüsselt übertragen. Dieses ist ein weiterer Schutz davor manipulierte Antworten zu bekommen und selbstverständlich, damit die eigenen DNS Abfragen erst überhaupt nicht mitgelesen werden. Denn wenn von einem Gerät im Netzwerk die DNS Abfrage zu z.B.: www.tagesschau.de kommt, könnte man davon bereits Dinge ableiten.
Wie die meisten Bind Konfigurationen ist dieses ebenfalls straightforward. Ab Version 9.18 bringt Bind alles Nötige mit. Da wir nun TLS mit dem Bind sprechen möchten, benötigen wir natürlich ein gültiges Zertifikat, wie z.B. beim nginx für seine Webseite.
Ebenfalls sollte man ein paar frische Diffie-Hellmann Parameter generieren:
openssl dhparam -out dhparam.pem 4096
Die eigentliche bind Konfiguration kann in der named.conf.options geschehen:
options { [...] listen-on port 853 tls local-tls { 37.120.183.220; }; listen-on-v6 port 853 tls local-tls { 2a03:4000:38:20e::853; }; listen-on port 443 tls local-tls http default { 37.120.183.220; }; listen-on-v6 port 443 tls local-tls http default { 2a03:4000:38:20e::853; }; [...] allow-recursion-on { 127.0.0.0/8; ::1/128; 2a03:4000:38:20e::853; 37.120.183.220; }; [...] };
Da der bind auf weiteren Ports lauschen soll erweitert man diese für IPv4 und IPv6. Der Default Port für DoH ist dabei 443 und der default Port für DoT ist 853, beides TCP.
listen-on sowie listen-on-v6 sind wohl selbsterklärend.
port ist der TCP Port und erklärt sich ebenfalls.
tls sagt dem Bind das wir tls sprechen möchten.
local-tls verweißt auf den gleichnamigen tls Block über welchen man seine TLS Konfiguration vornimmt.
http ist für DoH.
default gibt den eigentlichen endpoint für die DoH Abfragen an, im default ist es /dns-query
Da der Server unsere DNS Abfragen erledigen soll, müssen wir ihm dieses noch per allow-recursion-on auf den jeweiligen Adressen erlauben.
Als nächstes wird die eigentliche TLS Terminierung konfiguriert (das lässt sich ebenfalls auslagern, wenn gewünscht). Dafür wird der folgende Block, außerhalb der Options Blocks, ergänzt:
tls local-tls { cert-file "/usr/local/etc/ssl/wild.kernel-error.de/2022/ecp/chain.crt"; key-file "/usr/local/etc/ssl/wild.kernel-error.de/2022/ecp/http.key"; dhparam-file "/usr/local/etc/ssl/dhparam.pem"; protocols { TLSv1.2; TLSv1.3; }; ciphers "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256"; prefer-server-ciphers yes; session-tickets no; };
local-tls ist dabei der name des Blocks. Auf diesen verweisen wir oben.
cert-file ist der Pfad zum Zertifikat. Ich habe dort nicht nur das Zertifikat, sondern die gesamte Chain, also mit Intermediate und Root.
key-file ist der Pfad zum Key des Zertifikates.
dhparam-file ist der Pfad zu den Diffie-Hellman Parametern.
protocols definiert die zu verwendenden TLS Protokolle. In diesem Beispiel TLS1.2 sowie TLS1.3.
ciphers definiert die zu verwendenden cipher. Es soll ja „sicher“ bleiben.
prefer-server-ciphers übermittelt dem Client die Information, in welcher Reihenfolge protokoll/cipher Kombinationen probiert werden sollen um einen Match zu finden. Erst das vermeintlich sicherste und dann immer „schlechter“.
session-tickets regelt ob eine Wiederaufnahme von TLS Sessions erlaubt ist oder nicht. Da ich forward secrecy nutzen möchte, ist es deaktiviert.
Damit ist die Konfiguration schon abgeschlossen (Firewall ggf. nicht vergessen!). Also testen….
Ein einfaches Tool dafür ist dog, oder natürlich dig aus den bind-tools aber Version 9.18. Für bind gibt es dann die Optionen +https oder auch +tls
dig +https @dns.kernel-error.de www.kernel-error.de A dig +tls @dns.kernel-error.de www.kernel-error.de A
Der gleiche Test mit dog, sieht wie folgt aus:
dog www.kernel-error.de --tls "@dns.kernel-error.de" A www.kernel-error.de. 6h00m00s 148.251.40.23 dog www.kernel-error.de --https "@https://dns.kernel-error.de/dns-query" A www.kernel-error.de. 6h00m00s 148.251.40.23
Das war es auch schon! Viele Spaß mit einem „besseren“ DNS und wenn es noch Fragen gibt, einfach fragen 🙂
Was passiert beim forwarding, wenn ein „normales“ DNS packet auf Port 53 ankommt. Wird es dann auch unverschluesselt weitergeleitet? Oder kann man bind9 so configurieren, dass er alles ueber TLS (also DoT) weiterleitet?
Danke und LG
Hallo Jakob,
vielen Dank für deine Frage! Das Verhalten von BIND9 hängt von der Konfiguration ab. Standardmäßig leitet BIND9 eingehende unverschlüsselte DNS-Anfragen (Port 53) auch unverschlüsselt weiter, wenn Forwarding aktiviert ist. Wenn du möchtest, dass BIND9 solche Anfragen ausschließlich über TLS (DoT) weiterleitet, kannst du das durch entsprechende Konfiguration erreichen.
Mögliche Lösung:
Forwarding zu DoT-Servern konfigurieren:
Du kannst in der named.conf BIND9 anweisen, für alle Weiterleitungen TLS (DoT) zu nutzen. Dafür musst du explizit DoT-Server mit dem forwarders-Block und der tls-Option konfigurieren.
forwarders { 1.1.1.1 port 853 tls; 8.8.8.8 port 853 tls; }; forward only;
Unverschlüsselte DNS-Weiterleitung verhindern:
Stelle sicher, dass keine Fallbacks auf unverschlüsselte Weiterleitungen erfolgen, indem du
forward only;
setzt. So wird garantiert, dass nur DoT verwendet wird.Mögliche Probleme:
Das Erzwingen von DoT beim Forwarding kann jedoch folgende Herausforderungen mit sich bringen:
Verfügbarkeit der DoT-Forwarder: Wenn die konfigurierten DoT-Server (z. B.
1.1.1.1
oder8.8.8.8
) nicht verfügbar sind, können keine Anfragen weitergeleitet werden, da Fallback auf unverschlüsselte DNS-Server deaktiviert ist.Performance: Die TLS-Verbindungen zu den Forwardern erfordern zusätzlichen Overhead. Bei hohen Anfragelasten kann dies die Antwortzeiten erhöhen.
Fehlkonfigurationen oder Netzwerkprobleme: Wenn dein Netzwerk DoT nicht unterstützt (z. B. blockierte Port-853-Verbindungen), schlagen Weiterleitungen fehl.
Empfohlene Vorgehensweise:
Wenn du sicherstellen möchtest, dass deine Konfiguration stabil bleibt:
Teste die Erreichbarkeit der DoT-Server vor der Aktivierung von
forward only;
.Stelle sicher, dass deine Netzwerkinfrastruktur DoT-Verbindungen zulässt.
Überlege, eine Fallback-Option für unverschlüsselte Weiterleitungen bereitzustellen, falls maximale Verfügbarkeit wichtiger als vollständige Verschlüsselung ist.
Bei mir kommt:
Error initializing TLS context: error:8000000D:system library::Permission denied
wenn ich bind started will.
Ich muss die Dateien in .pem umbennen und dem user named die Rechte geben damit es funktioniert.
Aber wenn letsencrypt automatisch das neue cert lädt müsste ich diesen Prozess manuell wiederholen, was sehr mühsam ist.
gibt es da eine Lösung?
Danke für deinen Kommentar und das Teilen deines Problems! Das liegt höchstwahrscheinlich an den Berechtigungen und am Handling der Zertifikate durch named. Hier ein paar Tipps, um das zu lösen:
Zertifikate direkt lesbar für named machen:
Stelle sicher, dass die Zertifikate von Let’s Encrypt für den named-User lesbar sind. Das kannst du mit diesen Befehlen erreichen:
chown root:named /etc/letsencrypt/live/<deine-domain>/* chmod 640 /etc/letsencrypt/live/<deine-domain>/*
Automatisierung mit Certbot –deploy-hook:
Du kannst Certbot anweisen, nach einer Zertifikatserneuerung automatisch ein Skript auszuführen. Dieses Skript könnte:
Die Dateiberechtigungen setzen.
Die Dateien ggf. umbenennen.
Den bind-Dienst neu laden.
Beispiel für ein Skript:
#!/bin/bash chown root:named /etc/letsencrypt/live/<deine-domain>/* chmod 640 /etc/letsencrypt/live/<deine-domain>/* systemctl reload bind9
Füge das Skript als –deploy-hook hinzu:
certbot renew --deploy-hook "/path/to/your/script.sh"
TLS-Zertifikat zusammenführen:
Bind benötigt oft eine einzige .pem-Datei, die Zertifikat und privaten Schlüssel enthält. Dies kannst du mit folgendem Befehl automatisieren:
cat /etc/letsencrypt/live/<deine-domain>/fullchain.pem /etc/letsencrypt/live/<deine-domain>/privkey.pem > /etc/bind/doh-cert.pem chown named:named /etc/bind/doh-cert.pem chmod 640 /etc/bind/doh-cert.pem
Systemd-Timer für Automatisierung:
Falls Certbot über einen Systemd-Timer läuft, kannst du den Deploy-Hook direkt in der Timer-Konfiguration angeben. Das macht den Prozess komplett automatisiert.
Ich hoffe, das hilft dir weiter! Wenn du noch Fragen hast oder etwas nicht klappt, lass es mich wissen. 😊
Vielen Dank!
Genau, ich habe es jetzt auch mit:
/etc/letsencrypt/live//fullchain.pem
/etc/letsencrypt/live//privkey.pem
in der named.conf
Ich habe es zu spät gelesen aber ich habe es leicht anders gelöst mit ACL:
setfacl -R -m u:named:rX /etc/letsencrypt/{live,archive}/
setfacl -m u:named:rX /etc/letsencrypt/{live,archive}
Jetzt funktioniert es.
Bis jetzt habe ich DoT aktiviert.
Mein nameserver ist eigentlich nur für die domains die dort hinterlegt sind. Zuhause benutze ich weiter Quad9 mit TLS.
Aber meine Hoffnung ist es, dass vielleicht die Nameserver untereinander irgendwann auch per TLS kommunizieren.
Dazu gibt es einen Standard in der Mache, wenn ich das richtig verstehe, erfüllen wir das jetzt damit:
https://datatracker.ietf.org/doc/rfc9539/