DNS mit Docker Teil II – Recusor

Im letzten Post hatte ich den Anfang des Setups eines vollständigen DNS-Servers mit Docker und PowerDNS beschrieben. Nun folgen die nächsten Schritte. Eigentlich wollte ich diesen Post schon geraume Zeit fertig machen aber besser spät als nie.

PowerDNS-Recursor

Wie beschrieben teilt sich PowerDNS in drei Teile auf, im klassischen BIND-Server ist es ein monolitscher Block (bei dem man per Konfiguration ggf. einzelne Teile stillegen kann).
Der Recursor von PowerDNS übernimmt die Aufgabe der Namensauflösung für Anfragen die der Server nicht selbst auflösen kann. Diese Funktion braucht man im ersten Augenblick ür einen reinenNameserver nicht, aber in der Regel laufen auf dem Server ja auch noch andere Prozesse oder der DNS-Server dient für Clients im Netzwerk als Schnittstelle zum Netz. Dabei legt er praktischer Weise auch noch einen Cache an. Etwas ganz ähnliches macht ganz häufig Router für einen mit, wobei dieser die Anfragen initial dann auch nur an den nächst größeren Nameserver (z.B. beim Provider) abfragt. Ein solcher Cache ist auch für andere Serverprozesse sinnvoll, die viele DNS-Abfragen durchführen. Ein klassicher Fall hierfür ist der Mailserver, wenn er Echtzteit-Blacklists verwendet – diese teilen ihre Einschätzung anhand bestimmter DNS-Antworten mit (das ist schneller und effizienter als http(s), da tcp sondern nur eine upd-Verbindung aufgebaut wird.

Der Recursor ist auch recht schnell eingerichtet, das Dockerfile enthält auch hier keine großen Überraschungen bereit


FROM pschiffe/pdns-recursor:alpine
COPY recursor.conf /etc/pdns/recursor.conf
ENTRYPOINT [ "/usr/sbin/pdns_recursor" ]

Wobei das Config-File wie folgt aussieht:


allow-from=127.0.0.0/8,::1/128,2001:db8:ffff:ffff::/64,192.168.1.0/16
any-to-tcp=yes
#api-key=xxxx
#api-readonly=yes
daemon=no
local-address=::,0.0.0.0
local-port=53
lowercase-outgoing=yes
setgid=recursor
setuid=recursor

das einzig spannende an dieser Stelle ist die oberste Zeile “allow-from” – sie legt fest von welchen Adressen aus überhaupt auf den Server zugegriffen werden kann. Hier führt man natürlich die Localhost-Adressen an, genauso wie die eigene IPv6-Range (ich erlaube es dem gesamten Bereich der mir zugewiesen ist, damit auch andere auf dem Server laufende Prozesse den DNS-Service nutzen können). Zudem erlaube ich dem eigenen Docker-Netzwerk auf IPv4-Basis den Zugriff, das ist aber eher eine Fallback-Möglichkeit. Man sollte sich überlegen einen Recursor generell für jedermann zu öffnen. Der Recursor kann das durchaus ab, aber es besteht leider die Gefahr, dass er missbraucht wird und dann andere Systeme per Denial-of-Service angreift. Hier kann man ggf. mit dem Load-Balancer vornedran die Menge der Requests von extern limitieren, aber selbst dann bekommt man recht bald wahrscheinlich eine Mail vom BSI die auf die Problematik hinweist – ich hatte es beim Aufbauen mit einem Load-Limit auf 10 externe Anfragen pro Minute versucht, aber der Bot der das automatisiert prüft ist etwas stumpfsinnig und prüft nur ob man generell Abfragen für externe Domains an den Port 53 schicken darf.  Wie sinnvoll derartige Prüfungen sind, darf jeder für sich selbst entscheiden.
Auch diese Definition baut man zu einem Image:


docker build -t powerdns-recursor .

Danach startet man den Server ebenfalls im eingerichteten Docker-Netzwerk für die DNS-Services, natürlich auch hier wieder mit einer festen IPv6-Adresse da man auch hier sonst recht schnell ein Henne-Ei-Problem bekommt was die Namensauflösung betrifft.


docker run --ip6 2001:db8:ffff:ffff:ffff:ffff:0053:4 --network dns --name power_dns_recursor -d powerdns-recursor

Es kann natürlich auch als Dokumentation die vergebenen IP-Adressen mit Namen in der eingenen Datenbank in der eingenen DNS-Zone zu hinterlegen z.B. in einem eigenen DNS-Abschnitt wie dns.my.example.com mit sprechenden Namen: primary,secondary,recursor – denn so richtig einprägsam waren schon IPv4-Adressen nur bedingt und mit der zusätzlichen Länge wird das bei Ipv6 nicht besser.


INSERT INTO `records` VALUES (4, 1, 'authorative.my.example.com', 'AAAA', '2001:db8:ffff:ffff:ffff:ffff:0053:3', 3600, 0, NULL, 0, NULL, 1);

INSERT INTO `records` VALUES (4, 1, 'recursor.my.example.com', 'AAAA', '2001:db8:ffff:ffff:ffff:ffff:0053:4', 3600, 0, NULL, 0, NULL, 1);

Den Recursor kann man dann natürlich auch testen und nach beliebigen nicht eigenen Adressen wie www.google.com, www.amazon.de, www.meine-website.org
{{Beispiel mit dig}}