Einrichten eines lokalen DNS-Resolvers mit Unbound unter Arch Linux

Bild: Unbound Logo Mit Hilfe von Unbound kann ist ein validierender, rekursiver, cachender DNS-Resolver realisiert werden. Bei der Entwicklung, die in erster Linie von NLnet Labs erfolgt, wurde grosser Wert auf Schnelligkeit und Schlankheit und Sicherheit gelegt. Hierzu konzentriert sich Unbound auf den Schutz der Privatsphäre und die Sicherheit rund um das Domain Name System, jedoch beim Bereitstellen des Dienstes keineswegs Einschränkungen beim Funktionsumfang, bei Leistung oder Geschwindigkeit zu machen.

Herausforderung / Aufgabenstellung

Betrachten wir kurz die grundlegende Infrastruktur, mit der wir uns nun hier befassen wollen. Im vorigen Einrichten eines DNS-Daemons auf Basis von ISC Bind unter Arch Linux hatten wir bereits unseren DNS-Server erfolgreich aufgesetzt, der DNS-Anfragen lediglich auf den beiden localhost-Adressen 127.0.0.1 und ::1 beantworten kann. Im nun zweiten Schritt wollen wir für die workload der Clients aus den einzelnen Zonen einen unbound-Resolver aufsetzen.

Die nachfolgende Übersicht gestattet einen Überblick über die Infrastruktur, mit der wir uns anschließend befassen wollen.


Bild: Übersicht der Infrastruktur bei nausch.org, mit den einzelnen Schutzzonen und der Lösung für das Thema DNS

Der DNS-Resolver unbound soll Fragen nach Adressen aus dem WWW eigenständig abarbeiten. Anfragen an die eigenen Domains und Zonen hingegen sollen an den „hidden master“,also unseren ISC Bind weiterreichen. Unser DNS-Resolver unbound wird dabei DNSSec gesicherte Antworten ausliefern, bei denen das ad-Flag gesetzt ist.

DNSSEC

Nun könnte man durchaus fragen, warum man denn vor den ISC Bind Server noch unbedingt einen unbound-Resolver sich ans Bein binden möchte. Werfen wir dazu kurz einen Blick auf eine Anfrage an unseren ISC Bind Namserver, wen wir im Kapitel Orchestrierung - Installation und Konfiguration des BIND9 inkl. der Zonen-Datei-Pflege mit Hilfe von Ansible aufgesetzt hatten.

Als ersten fragen wir nach dem AAAA-Record eines unserer Hosts und nutzen dabei die Option +dnssec:

 # dig @::1 AAAA zerberus.nausch.org +dnssec
; <<>> DiG 9.20.18 <<>> @::1 AAAA zerberus.nausch.org +dnssec
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24233
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 2, ADDITIONAL: 5

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
; COOKIE: da549b6bb36e0109010000006978ed5d309da6924efba5dd (good)
;; QUESTION SECTION:
;zerberus.nausch.org.		IN	AAAA

;; ANSWER SECTION:
zerberus.nausch.org.	3600	IN	AAAA	fd00::3:10:0:0:9a37
zerberus.nausch.org.	3600	IN	RRSIG	AAAA 13 3 3600 20260206134310 20260123131754 51016 nausch.org. 3j+thdBQ945lvaYhKV7+Dljm2XIMV9aIdCJeYnyk3qE+9iG2ap3YlplF eLpqlE7Qd19t3Zb3tiT60qr4zwiLtQ==

;; AUTHORITY SECTION:
nausch.org.		3600	IN	NS	ns1.nausch.org.
nausch.org.		3600	IN	RRSIG	NS 13 2 3600 20260206100216 20260123131754 51016 nausch.org. 4m4o1JFHE8mJMhKq+oN53tI/mM79zHo4d/8M60ac7VmLduxlwgRaTSYa 0R67uVQJhhO4lL0CZNWORLnlXKU7iw==

;; ADDITIONAL SECTION:
ns1.nausch.org.		3600	IN	AAAA	fd00::3:10:0:0:110
ns1.nausch.org.		3600	IN	A	10.0.0.110
ns1.nausch.org.		3600	IN	RRSIG	A 13 3 3600 20260206025452 20260123131754 51016 nausch.org. nope0syW3S4rSB4txOMgkZRHsdRhwxqzAWZRqZF5O5u0oAHK9H+bNuwh 80yvH6443bPx7LP+B8Nj3ftP5IsL/Q==
ns1.nausch.org.		3600	IN	RRSIG	AAAA 13 3 3600 20260206025452 20260123131754 51016 nausch.org. 5gwNtzrGINCHIIpYcEOr9h8m9LrqnC3QkSdKzavKRWSD6RU/61SVQWqI u1yhot48pjI1OQxEiMH4g3yO2TelBw==

;; Query time: 0 msec
;; SERVER: ::1#53(::1) (UDP)
;; WHEN: Tue Jan 27 17:52:45 CET 2026
;; MSG SIZE  rcvd: 590

Bei der Antwort sehen wir, dass die Flags qr aa rd ra gesetzt sind. Diese Flags haben folgende Bedeutungen:

  • AA = Authoritative Answer (die Anfrage wird autoritativ beantwortet, also aus einer lokalen Zonendatei, beantwortet. Eine Überprüfung der eignen Antwort des autoritativer DNS-Server ist somit nicht nötig, dementsprechend ist auch das ad-Flag nicht gesetzt, da der Server sich selbst das nötige Vertrauen schenkt.)
  • TC = Truncation
  • RD = Recursion Desired (in einer Abfrage festgelegt und in die Antwort kopiert, wenn Rekursion unterstützt wird)
  • RA = Recursion Available (wenn festgelegt, bedeutet dies, dass rekursive Abfragen unterstützt werden)
  • AD = Authenticated Data (nur für DNSSEC; gibt an, dass die Daten authentifiziert wurden)
  • CD = Checking Disabled (nur DNSSEC; deaktiviert die Überprüfung auf dem empfangenden Server)

Da wir später immer validierte Antworten sehen möchten, müssen wir dafür sorgen, daß unser Resolver eben dieses setzen kann und hier kommt unbound ins Spiel. Das Ergebnis und den Unterschied zu dem gerade genannte Abfragebeispiel sehen wir uns dann hier genauer an.

Installation und Konfiguration des DNS-Resolvers unbound

Dokumentation / Man-Pages

unbound DNS Validation Resolver

Was uns der unbound DNS Validation Resolver bietet und welche Optionen beim Aufruf der Daemon bietet offenbart uns die betreffende Man-Page des Programms.

 # man unbound

unbound manpage

Manual-Page der Konfigurationsdatei unbound.conf

Interessantes rund um die Konfigurationsoptionen des Resolvers finden wir in der Man-Page unbound.conf

 # man unbound.conf

unbound.conf manpage

Resolver Konfigurationsdatei Syntax Prüftool unbound-checkconf

Zum Überprüfen der Konfiguration /etc/unbound.conf die wir später noch erstellen werden, befindet sich in dem ArchLinux-Paket das Hilfsprogramm unbound-checkconf. Die manpage des Programms liefert eine entsprechende Hilfe und zeigt auch die entsprechenden Optionen auf, mit deren Hilfe umfangreiche Tests durchgeführt werden können.

 # man unbound-checkconf

unbound-checkconf manpage

Hauptvertrauensankers für die DNSSEC-Validierung mit Hilfe von unbound-anchor

unbound-anchor führt die Einrichtung oder Aktualisierung des Hauptvertrauensankers für die DNSSEC-Validierung aus. Die manpage des Programms liefert eine entsprechende Hilfe und zeigt auch die entsprechenden Optionen auf, mit deren Hilfe umfangreiche Tests durchgeführt werden können.

 # man unbound-anchor

unbound-anchor manpage

unbound Remote Server Control Utility unbound-control

unbound-control führt die Management des DNS-Resolvers unbound durch. Es liest die Konfigurationsdatei, kontaktiert den Unbound-Server über TLS, sendet den Befehl und zeigt das Ergebnis an. Die manpage des Programms liefert eine entsprechende Hilfe und zeigt auch die entsprechenden Optionen auf, mit deren Hilfe umfangreiche Tests durchgeführt werden können.

 # man unbound-control

unbound-control manpage

Paketinstallation

Die Installation und Konfiguration des DNS-Resolvers unbound gestaltet sich relativ einfach. Zur Installation des Paketes verwenden wir unter Arch Linux den Paketmanager pacman.

  1. Als User:
     $ sudo pacman -S unbound
  2. Als Nutzer mit Root-Rechten entsprechend:
     # pacman -S unbound

Was uns das Paket unbound alles in das System unseres Arch Linux Server gebracht hat, können wir wie folgt abfragen:

 # pacman -Qil unbound

Paketinhalte

Grund-Konfiguration

Firewall/Paketfilter - firewalld

Bevor wir nun unseren unbound Resolver konfigurieren und starten müssen wir natürlich sicherstellen, dass auf dem betreffendem Host auch die Kommunikationsbeziehungen entsprechend erlaubt sind.

Wie auch schon früher bei CentOS ab Release 7 bzw. den nachfolgenden Release-Kandidaten Stream von RHEL nutzen wir auch unter Arch Linux den dynamischen firewalld Service. Ein grosser Vorteil der dynamischen Paketfilterregeln ist unter anderem, dass zur Aktivierung der neuen Firewall-Regel(n) nicht der Daemon durchgestartet werden muss und somit alle aktiven Verbindungen kurz getrennt werden. Sondern unsere Änderungen können on-the-fly aktiviert oder auch wieder deaktiviert werden.

In folgendem Konfigurationsbeispiel gehen wir von einem Host aus, der zwei Firewall-Zonen hält, einmal die Zone idmz und einmal die Zone intra. In beiden Zonen sollen später die DNS-Anfragen der Clients entsprechend beantworten werden.

Damit unsere Clients Verbindungen zu dem geöffneten 53/UDP- und 53/TCP-Ports des Unbound-Resolvers aufbauen können, müssen wir für diese noch Änderungen am Paketfilter firewalld vornehmen.

Mit Hilfe des Programms firewall-cmd legen wir nun jeweils eine permanente Regel in den beiden Zonen idmz und intra an. Genug der Vorrede, mit nachfolgendem Befehl werden die Ports für den Service dns geöffnet.

 # firewall-cmd --permanent --zone=idmz --add-service=dns
success
 # firewall-cmd --permanent --zone=intra --add-service=dns
success

Anschliessend können wir den Firewall-Daemon einmal neu laden und überprüfen, ob die Regeln auch entsprechend unserer Definition, gezogen haben.

 # firewall-cmd --reload
success

Werfen wir noch kurz einen Blick in die Zone idmz:

 # firewall-cmd --zone=idmz --list-services
dhcp dhcpv6 dns ssh

Gleiches gilt natürlich für die Zone intra:

 # firewall-cmd --zone=intra --list-services
dhcp dhcpv6 dns ssh
Firewall/Paketfilter - firewalld auf einem Transitknoten (FWB)
# firewall-cmd --permanent --policy=edmz_2_idmz  --add-rich-rule='rule family="ipv4" destination address="10.0.0.110" port port=53 protocol=tcp accept'
# firewall-cmd --permanent --policy=edmz_2_idmz  --add-rich-rule='rule family="ipv4" destination address="10.0.0.110" port port=53 protocol=udp accept'
# firewall-cmd --permanent --policy=edmz_2_idmz  --add-rich-rule='rule family="ipv6" destination address="fd00::3:10:0:0:110" port port=53 protocol=tcp accept'
# firewall-cmd --permanent --policy=edmz_2_idmz  --add-rich-rule='rule family="ipv6" destination address="fd00::3:10:0:0:110" port port=53 protocol=udp accept'
# firewall-cmd --permanent --policy=edmz_2_idmz  --add-rich-rule='rule family="ipv6" destination address="2003:a:e0d:7603:10::110" port port=53 protocol=tcp accept'
# firewall-cmd --permanent --policy=edmz_2_idmz  --add-rich-rule='rule family="ipv6" destination address="2003:a:e0d:7603:10::110" port port=53 protocol=udp accept'

jeweils success

# firewall-cmd --reload 
success
 # firewall-cmd --policy=edmz_2_idmz --list-all
edmz_2_idmz (active)
  priority: -1
  target: REJECT
  ingress-zones: edmz
  egress-zones: idmz
  services: 
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 
	rule family="ipv6" destination address="2003:a:e0d:7603:10::110" icmp-type name="echo-request" accept
	rule family="ipv4" destination address="10.0.0.110" port port="53" protocol="tcp" accept
	rule family="ipv4" destination address="10.0.0.110" port port="53" protocol="udp" accept
	rule family="ipv6" destination address="fd00::3:10:0:0:110" port port="53" protocol="tcp" accept
	rule family="ipv6" destination address="fd00::3:10:0:0:110" port port="53" protocol="udp" accept

automatischer Start des Daemon

Damit der unbound-Servicedaemon namens unbound automatisch bei jedem Systemstart startet, kann die Einrichtung eines Start-Scriptes über folgenden Befehl erreicht werden:

 # systemctl enable unbound.service
Created symlink '/etc/systemd/system/multi-user.target.wants/unbound.service' → '/usr/lib/systemd/system/unbound.service'.

Ein Überprüfung ob der Dienste (Daemon) named wirklich bei jedem Systemstart automatisch mit gestartet wird, kann durch folgenden Befehl erreicht werden:

 # systemctl is-enabled unbound.service
enabled

Starten werden wir den Dienst aber jetzt noch nicht, da wir zunächst den Resolver noch konfigurieren und die zugehörigen Zonen-Dateien anlegen müssen!

Basis-Konfiguration

Die Konfiguration unseres DNS Resolvers und dessen auch des Controll-Agenten erfolgt über Konfigurationsdateien im Verzeichnis /etc/unbound/.

Management mit Hilfe von remote-control

Unser unbound DNS-Resolver soll eine Management-Möglichkeit bereitstellen, welche wir mit Hilfe des Befehls unbound-control nun einrichten werden. Zur Generierung des nötigen Schlüsselmaterials rufen wir das Programm unbound-control-setup ohne weitere Optionen auf. Es wird die mitgelieferte Standard-Konfigurationsdatei /etc/unbound/unbound.conf gelesen und die Schlüsseldateien im Konfigurationsverzeichnis /etc/unbound/ abgelegt.

 # unbound-control-setup
setup in directory /etc/unbound
Certificate request self-signature ok
subject=CN=unbound-control
removing artifacts
Setup success. Certificates created. Enable in unbound.conf file to use
 # ls -l /etc/unbound/unbound_*
-rw-r----- 1 root root 2484 Jan 27 18:24 /etc/unbound/unbound_control.key
-rw-r----- 1 root root 1501 Jan 27 18:24 /etc/unbound/unbound_control.pem
-rw------- 1 root root 2484 Jan 27 18:24 /etc/unbound/unbound_server.key
-rw-r----- 1 root root 1549 Jan 27 18:24 /etc/unbound/unbound_server.pem

DNS-Rootserver - root.hints

Wie auch schon bei der Konfiguration unseres eigenen Nameservers, werden wir auch hier nicht einen x-beliebigen externen Nameserver wie z.B. den des Anschlußnetzbetreibers verwenden, sondern werden hier die offiziellen Root-Name-Server „top-down“ befragen. Damit unser unbound ordnungsgemäß solche DNS-Anfragen durchführen kann, muß dieser natürlich Kenntnis von den 13 Root Nameservern haben. Bei der Installation des ArchLinux Pakets unbound keine Default-Konfigurationsdatei mit diesen Informationen mitgeliefert wurde, werden wir uns nun die betreffenden Informationen besorgen und in der Datei /var/named/named.root ablegen.

 # curl --output /etc/unbound/root.hints https://www.internic.net/domain/named.cache

Wir haben nun die nötigen Informationen vorliegen:

# ll /etc/unbound/root.hints
-rw-r--r-- 1 root root 3313 Jan 28 10:17 /etc/unbound/root.hints

Diese Datei hat nun folgenden Inhalt.

# bat /etc/unbound/root.hints

Inhalt der erzeugten Konfigurationsdatei /var/named/root.hints

Gesetzt den Fall bei den 13 Root-Nameservern würde sich an den Adressen etwas ändern, möchten wir natürlich auch sicherstellen daß das zuvor manuell heruntergeladene File auch aktuell gehalten werden kann. HIerzu legen wir uns einen systemd-Timer an, der 1x im Monat die Datei neu holt und den Resolver anschließend neu startet, damit der Resolver Kenntnis von der neuen Datei hat.

 # vim /etc/systemd/system/root-hints.timer
/etc/systemd/system/root-hints.timer
[Unit]                
Description=Run root-hints monthly to get actual root.hints
 
[Timer]               
OnCalendar=monthly    
Persistent=true       
Unit=root-hints.service                   
 
[Install]             
WantedBy=multi-user.target
 # vim /etc/systemd/system/root-hints.service
/etc/systemd/system/root-hints.service
[Unit]                                                                                                            
Description=Update root hints for unbound
After=network.target
 
[Service]
ExecStart=/usr/bin/curl -o /etc/unbound/root.hints https://www.internic.net/domain/named.cache && systemctl restart unbound.service

Anschließend Starten wir den Timer und enablen diesen, so daß disser auch nach einem Neustart der Maschine aktiv ist.

 # systemctl start root-hints.timer 
 # systemctl enable root-hints.timer 
Created symlink '/etc/systemd/system/timers.target.wants/root-hints.timer' → '/etc/systemd/system/root-hints.timer'.

DNSSEC-Schlüsselmaterial des hidden-master DNS-Daemon

Damit unser DNS-Resolver unbound die Antworten des hidden masters, also unseres DNS-Daemons auf Basis von ISC Bind unter Arch Linux entsprechend validieren kann, benötigt unser Resolver entsprechendes Schlüsselmaterial. Hierzu legen wir als erstes das entsprechende Zielverzeichnis an:

 # mkdir -p /etc/unbound/keys

Hier passen wir nun die Dateirechte an, so dass nur och unser Resolver seklbst darauf zugreifen kann.

 # chmod 770 /etc/unbound/keys/
 # chown unbound /etc/unbound/keys

Anschließend kopieren wir das nötige Schlüsselmaterial, welches wir bei der DNSSEC-Konfiguration unseres ISC-BIND DNS-Daemon erzeugt hatten.

 # cp -av /var/named/keys/*.key /etc/unbound/keys

Auch hier passen wir die Rechte entsprechend an.

 # chown unbound /etc/unbound/keys/*.key
 # chmod 640 /etc/unbound/keys/*.key

Bei Bedarf können wir uns noch anzeigen lassen, welche Dateien kopiert wurden. Hierzu rufen wir auf:

 # ll /etc/unbound/keys

Ausgabe des Befehlsaufrufes ls -al /etc/unbound/keys

Konfiguration des Resolvers - unbound.conf

Die Konfiguration des Resolvers erfolgt über die Datei /etc/unbound/unbound.conf die uns bei der Paketinstallation mitgeliefert wurde. Damit wir Änderungen, die beim Updaten des installierten Paketes ggf. neu hinzukommen oder wegfallen, besser von der Originaldatei unterscheiden können kopieren wir uns als erstes diese Datei.

 # cp -av /etc/unbound/unbound.conf /etc/unbound/unbound.conf.orig

Die Konfigurationsdatei des Resolvers ist außerordentlich gut dokumentiert, was diese auf eine stattliche Zahl von 1424 Zeilen anwachsen ließ. Werfen wir einen kurzen Blick mal in diese Konfigurationsdatei.

 # bat /etc/unbound/unbound.conf

Ausgabe des Befehlsaufrufes bat unbound.conf

Wir werden nun die relavanten Einträge von Oben nach unten in der Konfigurationsdatei Schritt für Schritt unseren Bedürnissen nach anpassen. Dazu öffnen wir die Datei mit dem editor unserer Wahl.

 # vim /etc/unbound.unbound.conf
interface

Zunächst definieren wir, auf welchen Netzwerkinterfaces bzw. IP-Adressen der Resolver DNS-Anfragen entgegennehmen soll.

  interface: fd00::7:10:0:10:110
  interface: 10.0.10.110
  interface: fd00::3:10:0:0:110
  interface: 10.0.0.110
interface-action

Dann definieren wir, welche Schnittstellen (rekursive) Abfragen für diesen Server akzeptieren dürfen. Die angegebenen Schnittstellen sollten mit denen übereinstimmen, die unter „interface:“ angegeben sind, gefolgt von der Aktion.

  interface-action: fd00:0:0:7:10:0:10:110 allow
  interface-action: 10.0.10.110 allow
  interface-action: fd00:0:0:3:10:0:0:110 allow
  interface-action: 10.0.0.110 allow
prefer-ip6

Diesen Wert setzen wir auf yes, da wir IPv6 bei den Upstream-Server gegenüber IPv4 zu bevorzugen wollen.

  prefer-ip6: yes
root-hints

Hier definieren wir, wo die Datei mit den Adressen der 13-Root-Nameserver, welche wir im DNS-Rootserver - root.hints angelegt hatten, zu finden ist.

  root-hints: "/etc/unbound/root.hints"
hide-identity

Anfragen bzgl der id.server und hostname.bind verbergen.

  hide-identity: yes
hide-version

Auch Anfragen bzgl. der version.server und version.bind lassen wir unbeantwortet.

  hide-version: yes
do-not-query-localhost

Zum Testen und debuggen lassen wir Anfragen zu localhost zu.

  do-not-query-localhost: no
auto-trust-anchor-file

Die DNSSEC-Validierung wird nur durchgeführt, wenn der abgefragte DNS-Server dies unterstützt. Wenn allgemeine Weiterleitungsabfragen an DNS-Server gerichtet wurden, die DNSSEC nicht unterstützen, sollten deren Antworten, unabhängig davon, wie sie ausfallen, als unsicher betrachtet werden, da keine DNSSEC-Validierung durchgeführt werden konnte. Damit nun die DNSSEC-Validierung gegenüber unserem hidden master erfolgreich validiert werden können, definieren wir hier wo unser Resolver das betreffende Schlüsselmaterial, welches wir im Absachnitt DNSSEC-Schlüsselmaterial des hidden-master DNS-Daemon kopiert hatten, vorfinden und aktualisieren kann. Diese Dateien mit vertrauenswürdigen Schlüsseln, die mit Hilfe von RFC5011-Probes auf dem neuesten Stand gehalten werden, speichern dann auch die nötigen Metadaten.

  auto-trust-anchor-file: "/etc/unbound/keys/Kintra.nausch.org.+013+60679.key"
  auto-trust-anchor-file: "/etc/unbound/keys/K10.0.10.in-addr.arpa.+013+34902.key"
  auto-trust-anchor-file: "/etc/unbound/keys/K7.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa.+013+31560.key"
  auto-trust-anchor-file: "/etc/unbound/keys/Kidmz.nausch.org.+013+46346.key"
  auto-trust-anchor-file: "/etc/unbound/keys/K0.0.10.in-addr.arpa.+013+06101.key"
  auto-trust-anchor-file: "/etc/unbound/keys/K3.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa.+013+35476.key"
  auto-trust-anchor-file: "/etc/unbound/keys/Kedmz.nausch.org.+013+09230.key"
  auto-trust-anchor-file: "/etc/unbound/keys/K2.17.172.in-addr.arpa.+013+47194.key"
  auto-trust-anchor-file: "/etc/unbound/keys/K0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa.+013+06001.key"
  auto-trust-anchor-file: "/etc/unbound/keys/Knausch.org.+013+08020.key"                                          
  auto-trust-anchor-file: "/etc/unbound/keys/K13.92.217.in-addr.arpa.+013+07117.key"
  auto-trust-anchor-file: "/etc/unbound/keys/Kebersberger-liedersammlung.de.+013+26039.key"
  auto-trust-anchor-file: "/etc/unbound/keys/Komni128.de.+013+29371.key"
  auto-trust-anchor-file: "/etc/unbound/keys/Kwetterstation-pliening.info.+013+03760.key"
trusted-keys-file

Datei bzw Dateien mit vertrauenswürdigen Schlüsseln zur Validierung. Dies ist ähnlich wie trust-anchor-file, jedoch mit einem anderen Dateiformat. Das Format entspricht dem BIND-9-Stil, wobei die Klauseln trusted-keys { name flag proto algo „key“; }; gelesen werden.

  trusted-keys-file: "/etc/unbound/keys/*.key"
domain-insecure

Damit auch eine forward Anfrage nach localhost und eine reverse Anfrage nach 127.0.0.1 bzw ::1 erfolgreich beantwortet werden können, ist es notwendig diese von den DNSSec gesicherten Zonen auszunehmen.

  domain-insecure: "localhost."
  domain-insecure: "1.0.0.127.in-addr.arpa."
  domain-insecure: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."
local-zone

Standardmäßig ist für eine Reihe von Zonen eine kleine Standardantwort „nothing here“ integriert und somit die Abfrage blockiert. Da wir aber explizit solche Zone bedienen wollen müssen wir diese entsprechend definieren |ausnehmen. Da wir für unsere eignen Zonen unseren hidden master befragen wollen und dies sowohl für die vorwärts wie auch rückwärts Anfragen, müssen wir diese hier explizit angeben und mit der Option transparent angeben.

  local-zone: "localhost." nodefault
  local-zone: "127.in-addr.arpa." nodefault
  local-zone: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa." nodefault
  local-zone: "10.in-addr.arpa." transparent                                                                      
  local-zone: "2.17.172.in-addr.arpa." transparent
  local-zone: "0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa." transparent
  local-zone: "3.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa." transparent
  local-zone: "7.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa." transparent
  local-zone: "13.92.217.in-addr.arpa." transparent
  #local-zone: "d.0.e.0.a.0.0.0.3.0.0.2.ip6.arpa." transparent
forward-zone

Hier definieren wir nun spezielle Forward-Zonen, bei der bestimmte Netzte vorwärts bzw. rückwärts aufgelöst werden sollen und welcher Ziel-Nameserver hierzu anzusprechen ist.

forward-zone:
        name: "localhost"
        forward-addr: ::1
forward-zone:
        name: "1.0.0.127.in-addr.arpa"
        forward-addr: ::1
forward-zone:
        name: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa"
        forward-addr: ::1
forward-zone:
        name: "intra.nausch.org"
        forward-addr: ::1
forward-zone:
        name: "10.0.10.in-addr.arpa"
        forward-addr: ::1
forward-zone:
        name: "7.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa"
        forward-addr: ::1
forward-zone:
        name: "idmz.nausch.org"
        forward-addr: ::1
forward-zone:
        name: "0.0.10.in-addr.arpa"
        forward-addr: ::1
forward-zone:
        name: "3.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa"
        forward-addr: ::1
forward-zone:
        name: "edmz.nausch.org"
        forward-addr: ::1
forward-zone:
        name: "2.17.172.in-addr.arpa"
        forward-addr: ::1
forward-zone:
        name: "0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa"
        forward-addr: ::1
forward-zone:
        name: "nausch.org"
        forward-addr: ::1
forward-zone:
        name: "13.92.217.in-addr.arpa"
        forward-addr: ::1                                                                                                                               
#forward-zone:
#        name: "d.0.e.0.a.0.0.0.3.0.0.2.ip6.arp"
#        forward-addr: ::1
forward-zone:
        name: "ebersberger-liedersammlung.de"
        forward-addr: ::1
forward-zone:
        name: "omni128.de"
        forward-addr: ::1
forward-zone:
        name: "wetterstation-pliening.info"
        forward-addr: ::1
control-enable

Hier wird definiert, ob Unbound Remote Control aktiviert werden soll?

  control-enable: yes
control-interface

Definition der Schnittstelle(n) auf welchen Unbound Remote Control bedient werden soll.

  control-interface: ::1
  control-interface: 127.0.0.1
control-port

Definition des Ports auf dem der Unbound Remote Control Service lauschen soll.

  control-port: 8953
control-use-cert

Soll ein Zertifikat für remoite control verwendet werden?

  control-use-cert: "yes"
server-key-file

Unbound Server Key-Datei.

  server-key-file: "/etc/unbound/unbound_server.key"
server-cert-file

Unbound Server Zertifikats-Datei.

  server-cert-file: "/etc/unbound/unbound_server.pem"
control-key-file

Unbound-control Schlüssel-Datei.

  control-key-file: "/etc/unbound/unbound_control.key"
control-cert-file

Unbound-control Zertifikatsdatei.

  control-cert-file: "/etc/unbound/unbound_control.pem"

Somit haben wir nun alle für unseren Einsatz relevanten Optionen gesetzt. Eine Zusammenfassung aller Optionen ohne die Kommentare können wir mit Hilfe eines grep Befehls mit den Optionen -Ev uns ausgeben lassen.

 # grep -Ev '(^#|^.*#|^$)' /etc/unbound/unbound.conf | bat

Ausgabe des Befehlsaufrufes bat unbound.conf

Optimierung Netzwerk-Stack (Puffergröße)

Standardmäßig ist der Linux-Netzwerkstack nicht für die Übertragung großer Dateien mit hoher Geschwindigkeit über WAN-Verbindungen konfiguriert. Dies geschieht, um Speicherressourcen zu sparen. Die standardmäßigen maximalen TCP-Puffergrößen unter Linux kann unter Umständen viel zu klein sein, da der TCP-Speicher wird automatisch auf Basis des Systemspeichers berechnet. Ist der Send-/Receive-Buffer zu klein dimensioniert, tauchen im jourmnal beim Starten von unbound folgende Warnmeldungen auf:

Jan 27 21:29:48 vml000110 unbound[4987]: [1769545788] unbound[4987:0] warning: so-sndbuf 4194304 was not granted. Got 425984. To fix: start with root permissions(linux) or sysctl bigger net.core.wmem_max(linux) or kern.ipc.maxsockbuf(bsd) values. or set so-sndbuf: 0 (use system value).
Jan 27 21:29:48 vml000110 unbound[4987]: [1769545788] unbound[4987:0] warning: so-sndbuf 4194304 was not granted. Got 425984. To fix: start with root permissions(linux) or sysctl bigger net.core.wmem_max(linux) or kern.ipc.maxsockbuf(bsd) values. or set so-sndbuf: 0 (use system value).
Jan 27 21:29:48 vml000110 unbound[4987]: [1769545788] unbound[4987:0] warning: so-sndbuf 4194304 was not granted. Got 425984. To fix: start with root permissions(linux) or sysctl bigger net.core.wmem_max(linux) or kern.ipc.maxsockbuf(bsd) values. or set so-sndbuf: 0 (use system value).
Jan 27 21:29:48 vml000110 unbound[4987]: [1769545788] unbound[4987:0] warning: so-sndbuf 4194304 was not granted. Got 425984. To fix: start with root permissions(linux) or sysctl bigger net.core.wmem_max(linux) or kern.ipc.maxsockbuf(bsd) values. or set so-sndbuf: 0 (use system value).

Wir müssen also den Speicher den der Netzwerkstack benutzen darf entsprechend anpassen. Hierzu legen wir uns folgende Datei an:

 # vim /etc/sysctl.d/60-net-memory.conf
/etc/sysctl.d/60-net-memory.conf
# Configure default and maximum amount for the receive socket memory. 
net.core.rmem_max=4194304
 
# Configure default and maximum amount for the send socket memory.
net.core.wmem_max=4194304

Zum aktivieren der Änderung ohne Neustart des Systems verwenden wir folgenden Befehl.

 # sysctl --system

Ausgabe des Befehlsaufrufes sysctl --system

Start des Daemon unbound

Prüfen der Konfigurationsdatei auf syntaktische Fehler.

Bevor wir nun das erste mal unseren unbound-Resolvewr-Daemon starten, prüfen wir noch, ob sich in unserer Konfiguirationsdatei irgendwelche syntaktischen Fehler oder fehlerhafte Definitionen eingeschlichen haben. Hierzu verwenden wir das Programm unbound-checkconf.

 # unbound-checkconf /etc/unbound/unbound.conf
/etc/unbound/keys/Kwetterstation-pliening.info.+013+47591.key: No such file or directory
[1769543476] unbound-checkconf[4443:0] fatal error: auto-trust-anchor-file: "/etc/unbound/keys/Kwetterstation-pliening.info.+013+47591.key" does not exist in chrootdir /etc/unbound

In diesem Beispiel bekommen wir den Hinweis, dass das definierte auto-trust-anchor-file: „/etc/unbound/keys/Kwetterstation-pliening.info.+013+47591.key“ nicht existiert.

Wir kopieren die fehlende Datei und starten dann anschließend noch einmal die Überprüfung der Konfigurationsdatei.

 # unbound-checkconf /etc/unbound/unbound.conf
unbound-checkconf: no errors in /etc/unbound/unbound.conf

Nun sieht das schon viel besser aus und wir können uns daran machen den Rexolver das erste mal zu starten.

Mit nachfolgendem Befehl kann die syntaktische Richtigkeit der Konfigurationsdatei:

  • /etc/unbound/unbound.conf

durchgeführt werden und sollte keine Meldungen ausgeben, wenn die Konfigurationsdatei syntaktische richtig ist:

# /usr/sbin/unbound-checkconf /etc/unbound/unbound.conf
unbound-checkconf: no errors in /etc/unbound/unbound.conf

Starten des unbound Daemon

Da die vorherigen Tests keinerlei Konfigurationsfehler aufzeigten, spricht nun nichts mehr dagegen unseren DNS-Daemon named zu starten.

 # systemctl start unbound.service

Im Journal wir der Start entsprechend dokumentiert.

Protokollierung des unbound im journal

Bei Bedarf können wir natürlich auch den Status unseres Daemons jederzeit abfragen.

 # systemctl status named.service

 unbound.service - Validating, recursive, and caching DNS resolver
     Loaded: loaded (/usr/lib/systemd/system/unbound.service; enabled; preset: disabled)
   Active:active (running) since Tue 2026-01-27 21:12:03 CET; 8s ago
 Invocation: cb532dc297ef448ab2abf24a76dd7579
       Docs: man:unbound(8)
   Main PID: 4822 (unbound)
      Tasks: 1 (limit: 9501)
     Memory: 9M (peak: 9.5M)
        CPU: 153ms
     CGroup: /system.slice/unbound.service
             └─4822 /usr/bin/unbound -d -p

Jan 27 21:12:06 vml000110 unbound[4822]: [4822:0] info: generate keytag query _ta-8116.0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa. NULL IN
Jan 27 21:12:06 vml000110 unbound[4822]: [4822:0] info: failed to prime trust anchor -- could not fetch DNSKEY rrset 3.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa. DNSKEY IN
Jan 27 21:12:06 vml000110 unbound[4822]: [4822:0] info: generate keytag query _ta-3e8c.3.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa. NULL IN
Jan 27 21:12:06 vml000110 unbound[4822]: [4822:0] info: failed to prime trust anchor -- could not fetch DNSKEY rrset 7.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa. DNSKEY IN
Jan 27 21:12:06 vml000110 unbound[4822]: [4822:0] info: generate keytag query _ta-5e5c.7.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa. NULL IN
Jan 27 21:12:06 vml000110 unbound[4822]: [4822:0] info: failed to prime trust anchor -- could not fetch DNSKEY rrset 0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa. DNSKEY IN
Jan 27 21:12:06 vml000110 unbound[4822]: [4822:0] info: generate keytag query _ta-8116.0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa. NULL IN
Jan 27 21:12:06 vml000110 unbound[4822]: [4822:0] info: failed to prime trust anchor -- could not fetch DNSKEY rrset 3.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa. DNSKEY IN
Jan 27 21:12:07 vml000110 unbound[4822]: [4822:0] info: failed to prime trust anchor -- could not fetch DNSKEY rrset 7.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa. DNSKEY IN
Jan 27 21:12:07 vml000110 unbound[4822]: [4822:0] info: failed to prime trust anchor -- could not fetch DNSKEY rrset 0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa. DNSKEY IN

Alternativ dazu können wir auch einen Blick in die Prozess-Liste werfen um uns zu vergewissern ob der Daemon läuft.

 # ps auxwf | grep unbound

root          12  0.0  0.0      0     0 ?        I    15:12   0:00  \_ [kworker/u16:0-events_unbound]
root          70  0.0  0.0      0     0 ?        I<   15:12   0:00  \_ [kworker/R-quota_events_unbound]
root        1705  0.0  0.0      0     0 ?        I    19:16   0:00  \_ [kworker/u18:2-events_unbound]
root        1862  0.0  0.0      0     0 ?        I    20:05   0:00  \_ [kworker/u18:3-events_unbound]
root        1892  0.0  0.0      0     0 ?        I    20:33   0:00  \_ [kworker/u20:1-events_unbound]
root        4503  0.0  0.0      0     0 ?        I    20:58   0:00  \_ [kworker/u20:2-events_unbound]
root        4551  0.0  0.0      0     0 ?        I    21:04   0:00  \_ [kworker/u19:2-events_unbound]
root        4672  0.0  0.0      0     0 ?        I    21:09   0:00  \_ [kworker/u19:1-events_unbound]
root        4850  0.0  0.0      0     0 ?        I    21:14   0:00  \_ [kworker/u17:3-events_unbound]
root        4882  0.0  0.0   7952  6184 pts/0    S+   21:19   0:00                      \_ grep --color=auto unbound
unbound     4822  0.0  0.2  26512 21536 ?        Ss   21:12   0:00 /usr/bin/unbound -d -p

Wir können jetzt auch schon mit Hilfe des Utility ss abfragen ob der unbound nun Ports auf zugehörigen Addressen geöffnet hat.

 # ss -tulpn

Ausgabe des Befehls ss -tulpn

(remote) Management mit unbound-control

Mit Hilfe von unbound-control haben wir im Abschnitt Management mit Hilfe von remote-control bereits das Schlüssel- und Zertifikatsmaterial erzeugt. Möchte man einen Überblick über alle Möglichkeiten dieses Programms nutzt man beim Aufruf die Option --help.

 # unbound-control --help

Ausgabe des Befehls unbound-control --help

In folgendem Beispiel lassen wir uns den Status unseres Resolvers ausgeben.

 # unbound-control status
version: 1.24.2
verbosity: 1
threads: 1
modules: 2 [ validator iterator ]
uptime: 10711 seconds
options: reuseport control(ssl)
unbound (pid 2013) is running...

Möchte man wissen, welche Zonen an einen anderen DNS-Server, in unserem Beispiel der hidden matser der nur auf Port ::1 lauscht, delegiert wurden benutzt man die Option list_forwards.

 # unbound-control list_forwards
omni128.de. IN forward ::1
ebersberger-liedersammlung.de. IN forward ::1
nausch.org. IN forward ::1
edmz.nausch.org. IN forward ::1
idmz.nausch.org. IN forward ::1
intra.nausch.org. IN forward ::1
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. IN forward +i ::1
0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa. IN forward ::1
3.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa. IN forward ::1
7.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa. IN forward ::1
0.0.10.in-addr.arpa. IN forward ::1
10.0.10.in-addr.arpa. IN forward ::1
1.0.0.127.in-addr.arpa. IN forward +i ::1
2.17.172.in-addr.arpa. IN forward ::1
13.92.217.in-addr.arpa. IN forward ::1
wetterstation-pliening.info. IN forward ::1
localhost. IN forward +i ::1

Bei Bedarf kann man sich z.B. auch den Cache des Resolvers ausgeben lassen. Diese erreichen wir mit dem Befehl|Option dump_cache.

 # unbound-control dump_cache

Beispiel einer Ausgabe des Befehlsaufrufes unbound-control dump_cache

Eine aktuelle Statistik des Resolvers erhalten wir beim Aufruf mit der Option stats_noreset.

 # unbound-control stats_noreset

Mögliche Ausgabe des Befehlsaufrufes unbound-control stats_noreset

Möchte man den Cache leeren und die Konfiguration neu laden so benutzt man die Option reload.

 # unbound-control reload
ok

DNSSEC-Abfragen

Nun können wir auch die ersten DNS-Abfragen an unseren Resolver richten und prüfen ob wir eine signierte Antwort erhalten. Im Eingangs gezeigtem Beispiel hatten wir gesehen, daß bei einer Anfrage direkt an unseren hidden master ISC Bind zwar das aa Flag richtiger Weise gesetzt war, da dieser die Anfrage aus einer lokalen Zonendatei autoritativ beantwortet hat. Eine Überprüfung der eignen Antwort des autoritativer DNS-Server ist somit aber nicht möglich, da der Server sich selbst das nötige Vertrauen schenkt und dementsprechend das ad-Flag nicht gesetzt hat.

Wir fragen also nun unseren Resolver wer den nun der MX, also der Mailserver der Zone nausch.org ist. Dabei soll in der Antwort ersichtlich sein, daß die Antwort mit Hilfe vpn DNSSec abgesichert wurde und bei der die DNS-Vertrauenskette (Chain-of-Trust) im lokalen Netzwerk überprüfbar ist, was durch das ad-Flag in der Antwort entsprechend bestätigt wird.

 # dig MX nausch.org +dnssec +multi
# dig MX nausch.org +dnssec +multi

; <<>> DiG 9.20.18 <<>> MX nausch.org +dnssec +multi
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8998
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
;; QUESTION SECTION:
;nausch.org.		IN MX

;; ANSWER SECTION:
nausch.org.		3445 IN	MX 10 mx1.nausch.org.
nausch.org.		3445 IN	RRSIG MX 13 2 3600 (
				20260211124901 20260128191743 8020 nausch.org.
				nlh4YOYjjep8e7d+dY1AmZSFq5UzMIIYp2S1G1Ae+qcd
				Mxm/xVQzBWHM3BrEurQAZOmRYaPQAYwNrWrx4sxTpw== )

;; Query time: 3 msec
;; SERVER: fd00::3:10:0:0:110#53(fd00::3:10:0:0:110) (UDP)
;; WHEN: Thu Jan 29 15:03:38 CET 2026
;; MSG SIZE  rcvd: 165

Wollen wir den zugehörigen DNSKEY des Combined Signing Key CSK einer DNS ZONE (Sub-)Domain abfragen, verwenden wir folgende Abfrage:

 # dig intra.nausch.org dnskey +dnssec +multi +cd
; <<>> DiG 9.20.18 <<>> intra.nausch.org dnskey +dnssec +multi +cd
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30911
;; flags: qr rd ra ad cd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
;; QUESTION SECTION:
;intra.nausch.org.	IN DNSKEY

;; ANSWER SECTION:
intra.nausch.org.	2658 IN	DNSKEY 257 3 13 (
				y9mFr6fcHVSxcbY58bCmUHc0X51eY4qhxyagcyMtsQtV
				RGUQr7xIQJ9aLYLbmstDl7yqDcIYLybd6B+9P19AzQ==
				) ; KSK; alg = ECDSAP256SHA256 ; key id = 60679
intra.nausch.org.	2658 IN	RRSIG DNSKEY 13 3 3600 (
				20260212075344 20260129065344 60679 intra.nausch.org.
				rYggAc4HUnqX+OxFUFtXy8aAZ1o+lsomAkHAYH5Svftn
				4TjmqVKhe+v7FikoTICtKGAitHlmfZaFfIX/9edbMg== )

;; Query time: 0 msec
;; SERVER: fd00::3:10:0:0:110#53(fd00::3:10:0:0:110) (UDP)
;; WHEN: Thu Jan 29 15:10:37 CET 2026
;; MSG SIZE  rcvd: 237

Auch hier wird mit dem gesetzten ad-Flag angezeigt, daß die Daten authentifiziert wurden, also DNSsec gesichert übermittelt und geprüft wurden.

Orchestrierung - Installation und Konfiguration des Unbound-Resolvers mit Hilfe von Ansible

Aufgabenstellung

Wie auch schon bei der Einrichtung unseres "Hidden Master" wollen wir auch hier weder eine manuelle Installation und Konfiguration unseres Unbound-Resolver sehen noch betreiben. Setzen wir einen neue virtuellen Server unter Arch Linux neu auf, oder wollen wir bei einem bestehenden Host die Konfiguration aktualisieren, verwenden wir wie zuvor schon angeschnitten Ansible als Orchestrierungswerkzeug. So ist sichergestellt, daß all unsere Hosts entsprechend gleich aufgebaut, konfiguriert und betrieben werden, es also keine Bastel-/Frickellösung geben wird!

Lösung

Der ungeduldigen Leser kann auch direkt zur Tat schreiten und das manuelle Anlegen der Inventory-Hülle, des Playbooks und der zugehörigen Rolle überspringen und diese Aufgaben mit folgendem Befehl sozusagen auf einem Rutsch erledigen:

 $ mkdir -p ~/devel/ansible ; wget https://gitlab.nausch.org/django/example_unbound/-/archive/main/example_unbound-main.tar.gz \
         -O - | tar -xz --strip-components=1 -C ~/devel/ansible

Nach Anpassung der Daten im Inventory kann man anschließend direkt zur Ausführung schreiten.

Vorbereitung - (Server-)Daten im Inventory

Bei unserem Konfigurationsbeispiel hier gehen wir von folgenden Host-Parametern aus:

  • zone: intra
  • hostname: vml010110

Die Konfigurationsdatei unseres inventory in unsere, Ansible-Verzeichnis beinhaltet demnach unter anderem:

 $ vim inventories/production/hosts

inventories/production/hosts

Die beiden Beispiel-Hosts aus der Gruppe|Zone intra in diesem Inventory symbolisieren folgende unterschiedlichen Knoten.

  • Der Host pml010007 steht exemplarisch für einen Client im Intranet. In dessen Inventory-File inventories/production/host_vars/pnc010007 sind die ihn beschreibenden Dateien enthalten.
  • Der Host vml010110 ist in diesem Beispiel unser Server auf dem unser ISC Bind als hidden master läuft und auch unseren unbound-Resolver beheimaten soll. Außerdem stellt dieser Host die Verbindung zwischen der Zone intra und der Zone idmz herstellt. Auf diesem Konten läuft bereits ein Chrony Timeserver| wie auch eine Firewall auf Basis von firewalld der eine Zonendefinition intra besitzt, die die Regeln für diese Zone beinhalten. Sowohl Timeserver wie auch Firewall werden in diesem Beispiel hier nur erwähnt, da in dem Playbook bzw.genauer gesagt im Inventory darauf referenziert wird.

Wir legen uns also nun die Hostdefinitionsdatei für unsere Adminworkstation an.

 $ vim inventories/production/host_vars/pml010068

inventories/production/host_vars/pnc010068

Als nächstes legen wir die Datei für den KVM-Host, auf dem unser Kea-Daemon laufen soll an und definieren darin die zugehörigen Eigenschaften.

$ vim inventories/production/host_vars/vml010110/kvm_vhost

inventories/production/host_vars/vml010110/kvm_vhost

Die für den Unbound-Resolver relevanten Konfigurationsparameter legen wir in der Inventory-Datei inventories/production/host_vars/vml010110/unbound ab, bzw. ergänzen diese um weitere Domains odser Netzsegmente/Zonen.

 $ vim inventories/production/host_vars/vml010110/unbound

inventories/production/host_vars/vml010110/unbound

Unser Beispiels-Inventory hat also nunmehr folgenden Aufbau:

inventories/production/
├── hosts
└── host_vars
    ├── pml010068
    └── vml010110
        ├── kvm_vhost
        └── unbound

3 directories, 4 files

Playbook

Unser Playbook zum Installieren und Konfigurieren des ISC Bind-Daemon ist wie immer schlank, unscheinbar und unspektakulär, beinhaltet aber Hinweise zur Aufgabe und wie es aufzurufen ist.

 $ vim playbooks/bind.yml

playbooks/bind.yml

Rolle

Für die Konfiguration des Unbound-Daemon verwenden wir eine eigene Rolle unbound, die wir bei unserem zuvor angelegten Playbooks später einfach mit aufrufen werden. Hierzu kopieren wir uns zunächst die Mustervorlage common, welche wir bei der initialen Ansible-Einrichtung angelegt hatten.

 $ cp -avr roles/common/ roles/unbound

Ausgabe von cp -avr roles/common/ roles/unbound

Bei Bedarf können wir uns die Struktur die somit angelegt wurde mit nachfolgendem Befehl anzeigen lassen.

 $ tree roles/unbound/

Ausgabe von tree roles/unbound/

Wie wir sehen ist die Rolle durchaus überschaubar, im Task main.yaml verweisen wir lediglich auf die folgenden Tasks:

  • install, in die die Installation des Paketes erfolgt,
  • grundkonfig, in die die vorbereitende Installation erfolgt,
  • keyfilename, in der wir pro definierter Zone im Inventory entsprechend die Key-Datei des ISC Bind ermiteln und in das Konfigurationsverzeichnis /etc/unbound/keys kopieren,
  • konfig, mit deren Hilfe wir mit den Daten aus denm Inventory unseren Resolver konfgurieren werden sowie
  • firewalld wo wir abschließend die Konfiguration unseres nftables-basierten Paketfilters definieren.
 $ vim roles/unbound/tasks/main.yml

roles/unbound/tasks/main.yml

Die Installation des Unbound-Resolvers-Servers wird in der ersten Task-Gruppe mit dem tag install vorgenommen.

 $ vim roles/unbound/tasks/install.yml

roles/unbound/tasks/install.yml

Für die vorbereitende Grundkonfiguration des Resolvers, wie im Abschnitt vorbereitende Installation erklärt, werden die nötigen Schritte in der Task-Gruppe mit dem tag grundkonfig definiert.

 $ vim roles/unbound/tasks/grundkonfig.yml

roles/unbound/tasks/grundkonfig.yml

Das ermitteln der Keydateien je Zone und anschließende Kopieren aus dem Verzeichnis /var/named/keys in das Konfigurationsverzeichnis von unbound erfolgt in der Task-Gruppe mit dem tag keyfilename.

 $ vim roles/unbound/tasks/keyfilename.yml

roles/unbound/tasks/keyfilename.yml

Anschließen muß noch der Unbound-Resolver konfiguriert werden; dies wird in der Task-Gruppe konfig erledigt.

 $ vim roles/unbound/tasks/konfig.yml

roles/unbound/tasks/konfig.yml

Zum Schluß konfigurieren wir abschließend noch die Paketfilter-Regeln für unseren Firewall-Daemon firewalld.

 $ vim roles/unbound/tasks/firewalld.yml

roles/unbound/tasks/firewalld.yml

Sollte bei der Abarbeitung des Playbook die Konfigurationsdatei unbound.conf bzw. bei den Key-Dateien des ISC BInd unter /var/named/keys in das entsprechende Verzeichnis des Unbound-Resolvers kopiert werden, ist natürlich hierbei ein Restart der betreffenden Unbound-Daemon notwendig. Hierzu verwenden wir die Ansible Playbook Handlers. Dieser Handler wird bei den betreffenden Tasks zur Erstellung der Unbound-Konfigurationsdatei bzw. der Keyfiles mit Hilfe eines handler-Calls aufgerufen, sofern sich die Dateien verändert hat.

Wir brauchen wir noch eine Konfiguration der Aufgaben die bei einem notify abgearbeitet werden sollen.

 $ vim roles/unbound/handlers/main.yml

roles/unbound/handlers/main.yml

Für die Erstellung der Konfigurationsdatei /etc/unbound.conf brauchen wir nun noch ein Jinja2 Templates.

 $ vim roles/unbound/templates/unbound.j2

roles/unbound/templates/unbound.j2

Für die Erstellung der systemd-Timers für das monatliche Updaten der root.hints Datei sind noch die zwei betreffenden Templates notwendig.

 $ vim roles/unbound/templates/root-hints.j2

roles/unbound/templates/root-hints.j2

und:

 $ vim roles/unbound/templates/root-hints-timer.j2

roles/unbound/templates/root-hints-timer.j2

Zu guter Letzt brauchen wir dann noch ein Template für die Datei /etc/sysctl.d/60-net-memory.conf mit deren Hilfe wir die Optimierung Netzwerk-Stack (Puffergröße) vornehmen.

 $ vim roles/unbound/templates/net-memory.j2

roles/unbound/templates/net-memory.j2

Ausführung - Playbooklauf

Die orchestrierte Variante der Installation und Konfiguration unseres unbounda-Daemon gestaltet sich ab sofort sehr einfach, brauchen wir doch lediglich die Konfigurationswerte im Inventory zu hinterlegen und zu pflegen und letztendlich das Playbook entsprechend aufzurufen:

 $ ansible-playbook playbooks/unbound.yml
[16:19:29] Gathering Facts
↳  vml010110 | SUCCESS | 2.10s
[16:19:31] unbound : Installation des Unbound-Daemon.
↳  vml010110 | SUCCESS | 18ms
[16:19:32]     ↳ install: Installation der benötigten unbound Paketes.
↳  vml010110 | SUCCESS | 1.91s
[16:19:33] unbound : Vorbereitende Konfiguration des Unbound-Resolvers.
↳  vml010110 | SUCCESS | 27ms
[16:19:33]     ↳ grundkonfig: Checken ob es bereits eine Backupdatei von unbound.conf gibt.
↳  vml010110 | SUCCESS | 746ms
[16:19:34]     ↳ grundkonfig: Backupdatei der Konfigurationsdatei unbound.conf erstellen.
vml010110 | SKIPPED | 21ms
[16:19:34]     ↳ grundkonfig: Checken ob unbound_control bereits initialisiert worden ist.
↳  vml010110 | SUCCESS | 641ms
[16:19:35]     ↳ grundkonfig: Zertifikate und Schlüssel für unbound_control erzeugen.
vml010110 | SKIPPED | 16ms
[16:19:35]     ↳ grundkonfig: Checken ob es bereits eine Datei /etc/unbound/root.hints.
↳  vml010110 | SUCCESS | 703ms
[16:19:36]     ↳ grundkonfig: Liste der 13 Root-Nameserver holen und ablegen.
vml010110 | SKIPPED | 12ms
[16:19:36]     ↳ grundkonfig: Systemd Unit File für Update der root.hints erzeugen.
↳  vml010110 | SUCCESS | 1.32s
[16:19:37]     ↳ grundkonfig: Systemd Timer für Update der root.hints erzeugen.
↳  vml010110 | SUCCESS | 1.24s
[16:19:38]     ↳ grundkonfig: Systemd Service root-hints.timer aktivieren.
↳  vml010110 | SUCCESS | 1.12s
[16:19:39]     ↳ grundkonfig: Sicherstellen dass das Verzeichnis für die Schlüssel des hidden-master existiert.
↳  vml010110 | SUCCESS | 674ms
[16:19:40]     ↳ grundkonfig: Optimierung Netzwerk-Stack.
↳  vml010110 | SUCCESS | 1.29s
[16:19:41] unbound : Keyfilename ermitteln.
↳  vml010110 | SUCCESS | 72ms
[16:19:42]     ↳ keyfilename: Vollständigen Bind-Pfad des Schlüssels ermitteln: nausch.org
↳  vml010110 | SUCCESS | 684ms
[16:19:42]     ↳ keyfilename: Dateiname und Pfad des Schlüssels merken: nausch.org
↳  vml010110 | SUCCESS | 21ms
[16:19:42]     ↳ keyfilename: Schlüsseldatei vom ISC BIND zum Unbound kopieren: nausch.org
↳  vml010110 | CHANGED | 739ms
[16:19:43]     ↳ keyfilename: Vollständigen Bind-Pfad des Schlüssels ermitteln: 13.92.217.in-addr.arpa
↳  vml010110 | SUCCESS | 666ms
[16:19:44]     ↳ keyfilename: Dateiname und Pfad des Schlüssels merken: 13.92.217.in-addr.arpa
↳  vml010110 | SUCCESS | 17ms
[16:19:44]     ↳ keyfilename: Schlüsseldatei vom ISC BIND zum Unbound kopieren: 13.92.217.in-addr.arpa
↳  vml010110 | CHANGED | 666ms
[16:19:44]     ↳ keyfilename: Vollständigen Bind-Pfad des Schlüssels ermitteln: omni128.de
↳  vml010110 | SUCCESS | 662ms
[16:19:45]     ↳ keyfilename: Dateiname und Pfad des Schlüssels merken: omni128.de
↳  vml010110 | SUCCESS | 23ms
[16:19:45]     ↳ keyfilename: Schlüsseldatei vom ISC BIND zum Unbound kopieren: omni128.de
↳  vml010110 | CHANGED | 654ms
[16:19:46]     ↳ keyfilename: Vollständigen Bind-Pfad des Schlüssels ermitteln: ebersberger-liedersammlung.de
↳  vml010110 | SUCCESS | 700ms
[16:19:46]     ↳ keyfilename: Dateiname und Pfad des Schlüssels merken: ebersberger-liedersammlung.de
↳  vml010110 | SUCCESS | 21ms
[16:19:46]     ↳ keyfilename: Schlüsseldatei vom ISC BIND zum Unbound kopieren: ebersberger-liedersammlung.de
↳  vml010110 | CHANGED | 653ms
[16:19:47]     ↳ keyfilename: Vollständigen Bind-Pfad des Schlüssels ermitteln: wetterstation-pliening.info
↳  vml010110 | SUCCESS | 664ms
[16:19:48]     ↳ keyfilename: Dateiname und Pfad des Schlüssels merken: wetterstation-pliening.info
↳  vml010110 | SUCCESS | 23ms
[16:19:48]     ↳ keyfilename: Schlüsseldatei vom ISC BIND zum Unbound kopieren: wetterstation-pliening.info
↳  vml010110 | CHANGED | 679ms
[16:19:49]     ↳ keyfilename: Vollständigen Bind-Pfad des Schlüssels ermitteln: intra.nausch.org
↳  vml010110 | SUCCESS | 677ms
[16:19:49]     ↳ keyfilename: Dateiname und Pfad des Schlüssels merken: intra.nausch.org
↳  vml010110 | SUCCESS | 29ms
[16:19:49]     ↳ keyfilename: Schlüsseldatei vom ISC BIND zum Unbound kopieren: intra.nausch.org
↳  vml010110 | CHANGED | 644ms
[16:19:50]     ↳ keyfilename: Vollständigen Bind-Pfad des Schlüssels ermitteln: 10.0.10.in-addr.arpa
↳  vml010110 | SUCCESS | 648ms
[16:19:51]     ↳ keyfilename: Dateiname und Pfad des Schlüssels merken: 10.0.10.in-addr.arpa
↳  vml010110 | SUCCESS | 42ms
[16:19:51]     ↳ keyfilename: Schlüsseldatei vom ISC BIND zum Unbound kopieren: 10.0.10.in-addr.arpa
↳  vml010110 | CHANGED | 608ms
[16:19:51]     ↳ keyfilename: Vollständigen Bind-Pfad des Schlüssels ermitteln: 7.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa
↳  vml010110 | SUCCESS | 667ms
[16:19:52]     ↳ keyfilename: Dateiname und Pfad des Schlüssels merken: 7.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa
↳  vml010110 | SUCCESS | 20ms
[16:19:52]     ↳ keyfilename: Schlüsseldatei vom ISC BIND zum Unbound kopieren: 7.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa
↳  vml010110 | CHANGED | 710ms
[16:19:53]     ↳ keyfilename: Vollständigen Bind-Pfad des Schlüssels ermitteln: idmz.nausch.org
↳  vml010110 | SUCCESS | 547ms
[16:19:53]     ↳ keyfilename: Dateiname und Pfad des Schlüssels merken: idmz.nausch.org
↳  vml010110 | SUCCESS | 21ms
[16:19:53]     ↳ keyfilename: Schlüsseldatei vom ISC BIND zum Unbound kopieren: idmz.nausch.org
↳  vml010110 | CHANGED | 674ms
[16:19:54]     ↳ keyfilename: Vollständigen Bind-Pfad des Schlüssels ermitteln: 0.0.10.in-addr.arpa
↳  vml010110 | SUCCESS | 692ms
[16:19:55]     ↳ keyfilename: Dateiname und Pfad des Schlüssels merken: 0.0.10.in-addr.arpa
↳  vml010110 | SUCCESS | 44ms
[16:19:55]     ↳ keyfilename: Schlüsseldatei vom ISC BIND zum Unbound kopieren: 0.0.10.in-addr.arpa
↳  vml010110 | CHANGED | 676ms
[16:19:56]     ↳ keyfilename: Vollständigen Bind-Pfad des Schlüssels ermitteln: 3.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa
↳  vml010110 | SUCCESS | 691ms
[16:19:56]     ↳ keyfilename: Dateiname und Pfad des Schlüssels merken: 3.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa
↳  vml010110 | SUCCESS | 43ms
[16:19:56]     ↳ keyfilename: Schlüsseldatei vom ISC BIND zum Unbound kopieren: 3.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa
↳  vml010110 | CHANGED | 649ms
[16:19:57]     ↳ keyfilename: Vollständigen Bind-Pfad des Schlüssels ermitteln: edmz.nausch.org
↳  vml010110 | SUCCESS | 622ms
[16:19:58]     ↳ keyfilename: Dateiname und Pfad des Schlüssels merken: edmz.nausch.org
↳  vml010110 | SUCCESS | 22ms
[16:19:58]     ↳ keyfilename: Schlüsseldatei vom ISC BIND zum Unbound kopieren: edmz.nausch.org
↳  vml010110 | CHANGED | 625ms
[16:19:58]     ↳ keyfilename: Vollständigen Bind-Pfad des Schlüssels ermitteln: 2.17.172.in-addr.arpa
↳  vml010110 | SUCCESS | 641ms
[16:19:59]     ↳ keyfilename: Dateiname und Pfad des Schlüssels merken: 2.17.172.in-addr.arpa
↳  vml010110 | SUCCESS | 20ms
[16:19:59]     ↳ keyfilename: Schlüsseldatei vom ISC BIND zum Unbound kopieren: 2.17.172.in-addr.arpa
↳  vml010110 | CHANGED | 635ms
[16:20:00]     ↳ keyfilename: Vollständigen Bind-Pfad des Schlüssels ermitteln: 0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa
↳  vml010110 | SUCCESS | 704ms
[16:20:00]     ↳ keyfilename: Dateiname und Pfad des Schlüssels merken: 0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa
↳  vml010110 | SUCCESS | 24ms
[16:20:00]     ↳ keyfilename: Schlüsseldatei vom ISC BIND zum Unbound kopieren: 0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa
↳  vml010110 | CHANGED | 635ms
[16:20:01] unbound : Konfiguration der firewalld-Regeln für den DNS-Resolver.
↳  vml010110 | SUCCESS | 14ms
[16:20:01]     ↳ firewalld: Konfiguration der firewalld Regeln in Zone_1 für den Unbound-Resolver.
↳  vml010110 | SUCCESS | 7.91s
[16:20:09]     ↳ firewalld: Konfiguration der firewalld Regeln in Zone_2 für den Unbound-Resolver.
↳  vml010110 | SUCCESS | 7.91s
[16:20:17]     ↳ firewalld: Zum Schluss den aktuellen permanenten Regelsatz final neu laden.
↳  vml010110 | CHANGED | 1.24s
[16:20:18] unbound : Konfiguration des Unbound-Resolvers.
↳  vml010110 | SUCCESS | 16ms
[16:20:18]     ↳ konfig: Individuelle Konfigurationsdatei unbound.conf erzeugen und kopieren.
↳  vml010110 | SUCCESS | 1.27s
triggering handler | unbound : Restart unbound 
↳  vml010110 | CHANGED | 2.40s
[16:20:21] system
-- Play recap --
vml010110                  : ok=75   changed=16   unreachable=0    failed=0    skipped=3    rescued=0    ignored=0 


In diesem Beispiel haben wir nach nicht etwas mehr als 10 Sekunden einen voll funktionsfähigen DNSSEC-fähigen Unbound-Resolvers.

Links

Diese Website verwendet Cookies. Durch die Nutzung der Website stimmen Sie dem Speichern von Cookies auf Ihrem Computer zu. Außerdem bestätigen Sie, dass Sie unsere Datenschutzbestimmungen gelesen und verstanden haben. Wenn Sie nicht einverstanden sind, verlassen Sie die Website.Weitere Information
  • linux/unbound.txt
  • Zuletzt geändert: 01.02.2026 09:39.
  • von django