DNS : résolveur Unbound en cache — configurez-le en 15 minutes (et évitez le piège courant)

Cet article vous a aidé ?

Les problèmes DNS ne se présentent pas comme des problèmes DNS. Ils se manifestent par « la page de connexion est lente », « Kubernetes est bizarre », « apt ne peut pas récupérer » ou « notre monitoring est vert mais les utilisateurs sont mécontents ». Et quand vous regardez de plus près, vous réalisez que chaque hôte effectue ses propres requêtes récursives via un chemin réseau instable, ou pire, que vous avez construit une chaîne de résolveurs qui se ronge elle‑même.

Unbound est l’outil simple et fiable pour ce travail : un résolveur validant et en cache que vous pouvez exécuter localement ou centralement, avec des réglages sensés et un comportement prévisible. Vous pouvez le configurer en 15 minutes. L’astuce est d’éviter le piège courant : créer une boucle avec votre résolveur existant (souvent systemd-resolved), puis passer l’heure suivante à vous demander pourquoi tout renvoie SERVFAIL.

Pourquoi Unbound (et ce que vous construisez réellement)

Unbound est un résolveur DNS récursif avec cache et validation DNSSEC optionnelle. « Récursif » signifie qu’il parcourt lui‑même la hiérarchie DNS (root → TLD → autorités), plutôt que de demander à quelqu’un d’autre de le faire. « En cache » signifie que si 5000 processus demandent le même enregistrement, vous ne faites pas 5000 requêtes en amont. Et la validation DNSSEC signifie que vous pouvez rejeter des réponses falsifiées — au prix d’une complexité accrue si votre environnement est désordonné.

Ce que vous construisez réellement est une frontière de dépendance :

  • Vos hôtes dépendent de votre résolveur, pas de ce que le DHCP leur a attribué dans un café l’année dernière.
  • Vos applications obtiennent une meilleure latence extrême‑inférieure pour les workflows gourmands en DNS (découverte de services, CDNs, appels API, gestionnaires de paquets).
  • Vous gagnez un point unique pour observer le DNS : logs, comportement du cache, modes de défaillance.

Le schéma classique en production est l’un des suivants :

  • Cache local par nœud : Unbound sur chaque machine, à l’écoute sur 127.0.0.1, en renvoi vers un amont. Idéal pour les ordinateurs portables, serveurs seuls ou nœuds sensibles à la latence.
  • Résolveur central : un petit pool de serveurs Unbound, les clients les pointent. Idéal pour des flottes, une politique cohérente et une observabilité plus simple.
  • Hybride : Unbound local renvoyant vers Unbound central qui effectue la récursion. Idéal quand vous voulez un cache local + politique centrale.

Choisissez délibérément. « Ce qui marche » est la façon dont on se retrouve avec une boucle de résolveur, un DNSSEC incohérent et une salle de crise pleine de personnes qui se souviennent soudain que le DNS est difficile.

Faits rapides et courte histoire qui importent vraiment

Les faits et le contexte ne sont pas des anecdotes ici ; ils expliquent pourquoi certains choix par défaut existent et pourquoi certains modes de défaillance se répètent.

  1. Le DNS est plus ancien que le web. La RFC DNS date du début des années 1980, conçue pour un réseau plus petit, plus amical et moins hostile.
  2. Le TTL est un contrat, pas une suggestion. Les caches sont un comportement attendu. Si votre appli « a besoin » de changements DNS instantanés, c’est votre appli qui a le problème.
  3. Le cache négatif existe. NXDOMAIN peut aussi être mis en cache, voilà pourquoi une faute de frappe peut vous hanter pendant des minutes.
  4. DNSSEC a été ajouté plus tard. Il apporte une vérification d’intégrité, mais il ajoute aussi des façons de tomber en panne (décalage d’horloge, chaînes cassées, problèmes MTU/fragmentation).
  5. Les résolveurs ne sont pas « juste un serveur ». Ce sont des machines à états : requêtes en attente, nouvelles tentatives, délais, cache et politique.
  6. Le fichier de root hints n’est pas optionnel pour la récursion complète. Si vous faites une vraie récursion, vous avez besoin d’un moyen de trouver les serveurs root. Les paquets modernes gèrent cela, mais le concept compte.
  7. EDNS0 a changé la donne. Des paquets UDP plus larges et des enregistrements DNSSEC ont rendu les réponses plus volumineuses, exposant des équipements réseaux qui n’aiment pas la fragmentation.
  8. systemd-resolved a popularisé un modèle de stub‑resolver. Un stub local sur 127.0.0.53 peut aller — jusqu’à ce que vous l’empiliez avec un autre résolveur local et créiez une boucle.
  9. Unbound vient de l’écosystème NLnet Labs. Il est développé par des personnes qui vivent et respirent la justesse du DNS ; ce n’est pas un projet amateur.

Une citation à garder en tête pendant que vous faites cela :

« L’espoir n’est pas une stratégie. » — James Cameron

Le travail sur la fiabilité DNS est l’endroit où cette phrase trouve toute sa valeur. Vous ne « croyez » pas que votre chaîne de résolveurs est saine. Vous le prouvez.

15-minute setup: Ubuntu/Debian, production-safe

Cette configuration est optimisée pour « obtenir un résolveur en cache stable rapidement » sans vous enfermer. Elle suppose que systemd est présent (Ubuntu/Debian), et que vous acceptez qu’Unbound écoute d’abord sur localhost. Vous pourrez ensuite le lier à une IP LAN pour les clients.

Étape 1 : Installer Unbound (et les outils)

cr0x@server:~$ sudo apt-get update
...output...
cr0x@server:~$ sudo apt-get install -y unbound dnsutils
...output...

Ce que signifie la sortie : Vous devez voir Unbound installé et une unité systemd créée. Si apt installe quelque chose d’inattendu (comme un autre résolveur que vous n’aviez pas prévu), faites une pause et lisez la liste des dépendances.

Décision : N’avancez que si vous comprenez ce qui fournit maintenant le DNS sur l’hôte (systemd-resolved vs Unbound). Deux résolveurs peuvent coexister, mais seulement si vous explicitez leurs rôles.

Étape 2 : Créer une configuration Unbound minimale et sûre

Sur Debian/Ubuntu, la config principale d’Unbound se trouve couramment dans /etc/unbound/unbound.conf et inclut des fragments dans /etc/unbound/unbound.conf.d/. Nous allons déposer un extrait pour que les mises à jour de paquet ne vous écrasent pas.

cr0x@server:~$ sudo tee /etc/unbound/unbound.conf.d/local-cache.conf >/dev/null <<'EOF'
server:
  # Listen only on localhost to start. Expand later.
  interface: 127.0.0.1
  port: 53

  # Allow local queries only (for now).
  access-control: 127.0.0.0/8 allow

  # Basic hardening and privacy.
  hide-identity: yes
  hide-version: yes
  qname-minimisation: yes

  # Cache tuning: safe defaults.
  cache-min-ttl: 0
  cache-max-ttl: 86400
  cache-max-negative-ttl: 300
  prefetch: yes

  # Reliability.
  do-daemonize: no
  use-syslog: yes
  verbosity: 1

  # DNSSEC validation on (default on many distros, but be explicit).
  auto-trust-anchor-file: "/var/lib/unbound/root.key"

  # Avoid UDP fragmentation pain by advertising a conservative buffer.
  edns-buffer-size: 1232
EOF
...output...

Ce que signifie la sortie : Si vous voyez le fichier renvoyé, il a été écrit. Si vous voyez « Permission denied », vous avez oublié sudo ou le chemin est incorrect.

Décision : Gardez‑le localhost uniquement jusqu’à ce que vous l’ayez vérifié. Exposer un résolveur sur le réseau sans access-control est la façon dont on se retrouve avec un résolveur ouvert. Ça finit mal et bruyamment.

Étape 3 : Démarrer et activer Unbound

cr0x@server:~$ sudo systemctl enable --now unbound
...output...
cr0x@server:~$ systemctl status unbound --no-pager
● unbound.service - Unbound DNS server
     Loaded: loaded (/lib/systemd/system/unbound.service; enabled; vendor preset: enabled)
     Active: active (running) ...
...output...

Ce que signifie la sortie : « active (running) » est le minimum. Si c’est « failed », lisez les dernières lignes ; Unbound est habituellement franc sur les erreurs de parsing de config.

Décision : Si Unbound ne fonctionne pas, ne touchez pas à resolv.conf. Corrigez d’abord Unbound. Sinon vous risquez de couper votre propre session SSH.

Étape 4 : Pointer l’hôte vers Unbound (sans casser systemd-resolved)

C’est ici que naît le piège courant. Sur beaucoup de systèmes modernes, /etc/resolv.conf est un lien symbolique vers le fichier stub de systemd-resolved, et il pointe vers 127.0.0.53. Si vous configurez naïvement Unbound pour renvoyer vers « ce qui est dans resolv.conf », vous pouvez créer une boucle : Unbound → stub → Unbound → stub… jusqu’à ce que tout expire.

Nous allons le faire proprement :

  • Option A (simple) : Désactiver systemd-resolved et laisser Unbound être le résolveur.
  • Option B (coexistence) : Conserver systemd-resolved mais le configurer pour utiliser 127.0.0.1 (Unbound) en amont, et assurer qu’Unbound ne renvoie pas vers le stub.

Option A : Unbound comme seul résolveur local

cr0x@server:~$ sudo systemctl disable --now systemd-resolved
...output...
cr0x@server:~$ sudo rm -f /etc/resolv.conf
...output...
cr0x@server:~$ printf "nameserver 127.0.0.1\noptions edns0 trust-ad\n" | sudo tee /etc/resolv.conf
nameserver 127.0.0.1
options edns0 trust-ad

Ce que signifie la sortie : /etc/resolv.conf est maintenant un fichier réel pointant vers Unbound. L’option trust-ad demande des données authentifiées (bit AD) quand c’est possible.

Décision : Utilisez l’Option A sur des serveurs où vous voulez moins de pièces mobiles et vous contrôlez le réseau. C’est aussi plus facile à raisonner à 03:00 du matin.

Option B : Conserver systemd-resolved, utiliser Unbound en amont

Cela évite certains cas limites avec des clients VPN et du DNS split qui reposent sur systemd-resolved. Configurez resolved pour utiliser Unbound :

cr0x@server:~$ sudo mkdir -p /etc/systemd/resolved.conf.d
...output...
cr0x@server:~$ sudo tee /etc/systemd/resolved.conf.d/unbound-upstream.conf >/dev/null <<'EOF'
[Resolve]
DNS=127.0.0.1
Domains=~.
DNSStubListener=yes
EOF
...output...
cr0x@server:~$ sudo systemctl restart systemd-resolved
...output...

Ce que signifie la sortie : resolved reste le stub sur 127.0.0.53, mais il renvoie vers Unbound sur 127.0.0.1. C’est acceptable tant qu’Unbound ne renvoie pas en arrière.

Décision : Choisissez l’Option B quand vous avez besoin des fonctionnalités de systemd-resolved (DNS par lien, intégration VPN), mais que vous voulez quand même le cache/la validation d’Unbound.

Le piège courant : boucles de résolveur (symptômes, preuve, correction)

La boucle se produit généralement ainsi :

  1. Le système pointe vers un stub resolver à 127.0.0.53 (systemd-resolved).
  2. Vous installez Unbound et le configurez pour renvoyer vers « ce qui est dans /etc/resolv.conf ».
  3. Unbound renvoie vers 127.0.0.53.
  4. systemd-resolved est configuré (explicitement ou via une automatisation) pour utiliser 127.0.0.1 (Unbound) ou « le DNS local ».
  5. Félicitations : vous avez créé un ouroboros DNS.

Modèle de symptômes : courts succès suivis de délais d’attente ; SERVFAIL ; CPU élevé sur Unbound ; logs montrant des requêtes répétées ; dig prenant ~5 secondes et ne renvoyant rien d’utile.

Preuve : identifiez qui votre système interroge réellement

cr0x@server:~$ readlink -f /etc/resolv.conf
/run/systemd/resolve/stub-resolv.conf

Ce que signifie la sortie : Vous utilisez le stub de systemd-resolved, pas Unbound directement.

Décision : Si vous aviez prévu l’Option A, corrigez resolv.conf. Si vous aviez prévu l’Option B, assurez‑vous qu’Unbound ne renvoie pas vers 127.0.0.53.

Preuve : voyez où Unbound renvoie (si c’est le cas)

cr0x@server:~$ sudo unbound-checkconf
unbound-checkconf: no errors in /etc/unbound/unbound.conf

Ce que signifie la sortie : La config est parsée. Cela ne signifie pas que votre renvoi est sain ; cela signifie simplement qu’Unbound peut lire le fichier sans planter.

Décision : Si vous avez une forward-zone configurée, vérifiez qu’elle pointe vers de vrais résolveurs en amont (pas votre stub local sauf si vous en avez absolument l’intention).

Correction : choisissez une direction et rendez‑la unidirectionnelle

Règles unidirectionnelles qui vous évitent des ennuis :

  • Si Unbound est récursif, ne renvoyez pas vers systemd-resolved.
  • Si Unbound fait du forwarding, renvoyez vers des IP amont connues (résolveurs d’entreprise, ou externes) — pas « ce que resolv.conf dit ».
  • Si systemd-resolved renvoie vers Unbound, Unbound ne doit pas renvoyer vers systemd-resolved.

Blague n°1 (courte, pertinente) : les boucles DNS ressemblent aux organigrammes en entreprise : tout a l’air correct jusqu’à ce que vous réalisiez que tout le monde dépend de lui‑même.

Vérification : prouvez que c’est en cache et validant

Le DNS est un de ces systèmes où « ça a l’air bien » est un piège. Vérifiez :

  • Les requêtes sont répondues par Unbound (et ne le contournent pas).
  • La seconde requête est plus rapide (le cache fonctionne).
  • Le statut DNSSEC est correct (si activé).
  • La latence et les délais sont dans la plage attendue.

Test de requête basique

cr0x@server:~$ dig @127.0.0.1 example.com A +noall +answer +stats
example.com.		86396	IN	A	93.184.216.34
;; Query time: 28 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
...output...

Ce que signifie la sortie : La ligne SERVER: doit être 127.0.0.1 (Unbound). Un temps de requête de quelques dizaines de millisecondes pour un cache froid est normal.

Décision : Si le serveur n’est pas 127.0.0.1, vos clients n’utilisent pas Unbound. Corrigez la configuration des résolveurs avant d’optimiser quoi que ce soit.

Preuve du cache : exécutez deux fois

cr0x@server:~$ dig @127.0.0.1 example.com A +noall +answer +stats
example.com.		86396	IN	A	93.184.216.34
;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
...output...

Ce que signifie la sortie : 1–2 ms indique un hit de cache (ou au moins un chemin très rapide). C’est tout l’intérêt.

Décision : Si la seconde requête n’est pas plus rapide, vérifiez si vous contournez Unbound, ou si le cache est désactivé par la configuration/politique.

Signal DNSSEC : demandez le bit AD

cr0x@server:~$ dig @127.0.0.1 dnssec-failed.org A +dnssec +noall +comments +answer
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 12345
...output...

Ce que signifie la sortie : dnssec-failed.org est intentionnellement mal signé ; un résolveur validant doit échouer. SERVFAIL ici est un bon signe.

Décision : Si vous avez besoin de validation DNSSEC pour la politique/sécurité, conservez ce comportement. Si cela casse des noms internes critiques (parce que votre DNS interne est « créatif »), vous devrez peut‑être restreindre DNSSEC ou renvoyer des zones internes.

Tâches pratiques (commandes, signification des sorties, décisions)

Vous avez demandé des tâches réelles. Voici plus d’une douzaine. Chacune vous dit quelque chose d’actionnable opérationnellement.

Tâche 1 : Confirmer qu’Unbound écoute là où vous le pensez

cr0x@server:~$ sudo ss -lntup | grep -E ':(53)\b'
udp   UNCONN 0      0        127.0.0.1:53        0.0.0.0:*    users:(("unbound",pid=1234,fd=5))
tcp   LISTEN 0      128      127.0.0.1:53        0.0.0.0:*    users:(("unbound",pid=1234,fd=6))

Ce que signifie la sortie : UDP et TCP 53 sur 127.0.0.1. TCP est important pour les réponses volumineuses et le comportement de repli.

Décision : Si vous voyez 0.0.0.0:53 de façon inattendue, vous avez peut‑être exposé votre résolveur. Corrigez interfaces/access-control avant de continuer.

Tâche 2 : Confirmer quel résolveur votre hôte utilise (et si c’est un symlink)

cr0x@server:~$ ls -l /etc/resolv.conf
lrwxrwxrwx 1 root root 39 Jan  1 10:00 /etc/resolv.conf -> /run/systemd/resolve/stub-resolv.conf

Ce que signifie la sortie : le stub de systemd-resolved est en jeu.

Décision : Décidez : désactiver resolved (Option A), ou le configurer pour utiliser Unbound en amont (Option B). Ne restez pas indécis.

Tâche 3 : Vérifier les upstreams actuels de systemd-resolved

cr0x@server:~$ resolvectl status
Global
       LLMNR setting: yes
MulticastDNS setting: no
  DNSOverTLS setting: no
      DNSSEC setting: allow-downgrade
    DNSSEC supported: yes
  Current DNS Server: 127.0.0.1
         DNS Servers: 127.0.0.1
...output...

Ce que signifie la sortie : resolved renvoie vers 127.0.0.1 (Unbound). C’est cohérent seulement si Unbound ne renvoie pas en retour vers resolved.

Décision : Si Current DNS Server est 127.0.0.53 ou un serveur DHCP obsolète que vous ne faites pas confiance, corrigez la config de resolved ou votre gestionnaire réseau.

Tâche 4 : Valider la syntaxe de la config Unbound (prévention d’échec rapide)

cr0x@server:~$ sudo unbound-checkconf /etc/unbound/unbound.conf
unbound-checkconf: no errors in /etc/unbound/unbound.conf

Ce que signifie la sortie : La syntaxe est correcte. Si elle imprime une erreur, elle pointera la ligne exacte.

Décision : Ne jamais recharger/redémarrer Unbound en production sans un step unbound-checkconf dans l’automatisation. Les humains font des fautes. Le DNS ne pardonne pas.

Tâche 5 : Vérifier les statistiques live d’Unbound (sert‑il réellement ?)

cr0x@server:~$ sudo unbound-control status
version: 1.17.1
verbosity: 1
threads: 1
modules: 2 [ subnetcache validator iterator ]
uptime: 320 seconds
options: control(ssl)
unbound-control statistics not enabled

Ce que signifie la sortie : Le contrôle fonctionne, mais les statistiques ne sont pas activées par défaut sur certaines compilations.

Décision : Si vous voulez de l’observabilité, activez les stats et remote-control explicitement (section suivante). Si control échoue, corrigez permissions/certs avant d’en dépendre.

Tâche 6 : Vérifier les logs pour une boucle ou des timeouts en amont évidents

cr0x@server:~$ sudo journalctl -u unbound -n 50 --no-pager
...output...
unbound[1234]: info: resolving example.com. A IN
unbound[1234]: info: response for example.com. A IN
...output...

Ce que signifie la sortie : Vous voulez voir « resolving » suivi de « response ». Des motifs répétés « timed out » ou « SERVFAIL » sont votre premier signal d’alerte.

Décision : Si les timeouts dominent, suspectez le chemin réseau, un firewall ou un problème MTU/fragmentation. Si SERVFAIL domine, suspectez DNSSEC ou une boucle.

Tâche 7 : Confirmer que l’hôte utilise Unbound via le chemin libc (pas seulement dig)

cr0x@server:~$ getent ahosts example.com | head
93.184.216.34   STREAM example.com
93.184.216.34   DGRAM  example.com
93.184.216.34   RAW    example.com

Ce que signifie la sortie : Le resolver libc obtient une réponse utilisable. Cela attrape les cas où dig marche mais le résolveur système non (bizarreries NSS/nsswitch, domaines de recherche, etc.).

Décision : Si getent échoue mais dig fonctionne, vous avez probablement un problème NSS/nsswitch ou resolv.conf, pas Unbound lui‑même.

Tâche 8 : Vérifier les signaux de hit de cache en chronométrant des recherches répétées

cr0x@server:~$ for i in 1 2 3; do dig @127.0.0.1 www.cloudflare.com A +noall +stats | grep -E 'Query time|SERVER'; done
;; Query time: 24 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)

Ce que signifie la sortie : Comportement froid → chaud du cache visible. Si c’est toujours lent, vous ne mettez pas en cache efficacement.

Décision : Si c’est toujours lent, vérifiez si prefetch est désactivé, si la taille du cache est trop petite, ou si vous renvoyez vers un amont qui désactive le comportement de cache (rare mais possible avec des gateways « intelligentes »).

Tâche 9 : Détecter rapidement les échecs liés à DNSSEC

cr0x@server:~$ dig @127.0.0.1 www.iana.org A +dnssec +noall +comments | head -n 5
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4242
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
...output...

Ce que signifie la sortie : Le drapeau ad indique des données validées (quand disponibles). Si vous ne voyez jamais ad, la validation peut ne pas fonctionner, ou le client ne la demande/imprime pas correctement.

Décision : Si vous exigez la validation et ne voyez pas AD, inspectez les trust anchors, la synchro d’heure et si vous avez accidentellement désactivé le module validator.

Tâche 10 : Vérifier la synchro d’heure (dépendance discrète de DNSSEC)

cr0x@server:~$ timedatectl status
Local time: Wed 2025-12-31 10:00:00 UTC
Universal time: Wed 2025-12-31 10:00:00 UTC
RTC time: Wed 2025-12-31 10:00:01
System clock synchronized: yes
NTP service: active
...output...

Ce que signifie la sortie : La validation DNSSEC peut échouer si votre horloge est suffisamment décalée pour rendre les signatures expirées ou non encore valides.

Décision : Si l’horloge n’est pas synchronisée, corrigez NTP avant d’accuser Unbound ou des résolveurs en amont.

Tâche 11 : Inspecter les règles firewall pour le DNS (UDP et TCP)

cr0x@server:~$ sudo iptables -S | grep -E 'dport 53|sport 53' || true
-A OUTPUT -p udp -m udp --dport 53 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 53 -j ACCEPT

Ce que signifie la sortie : Le DNS sortant est autorisé. Si TCP est bloqué, vous verrez des échecs intermittents étranges quand les réponses ne tiennent pas dans UDP.

Décision : Autorisez TCP/53 en sortie. Le bloquer est une politique classique « ça marche jusqu’à ce que ça ne marche plus ».

Tâche 12 : Confirmer la joignabilité des upstreams (si vous faites du forwarding)

cr0x@server:~$ dig @1.1.1.1 example.com A +time=2 +tries=1 +noall +stats
;; Query time: 18 msec
;; SERVER: 1.1.1.1#53(1.1.1.1)
...output...

Ce que signifie la sortie : Si votre forwarder choisi est lent/injoignable depuis cet hôte, Unbound paraîtra mauvais même s’il est innocent.

Décision : Choisissez des forwarders joignables, à faible latence et compatibles avec la politique (surtout dans les réseaux d’entreprise avec split DNS).

Tâche 13 : Attraper une boucle de résolveur par observation de paquets

cr0x@server:~$ sudo tcpdump -ni lo port 53 -c 10
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
10:00:01.000000 IP 127.0.0.1.55555 > 127.0.0.1.53: 1234+ A? example.com. (28)
10:00:01.000100 IP 127.0.0.1.53 > 127.0.0.1.55555: 1234* 1/0/0 A 93.184.216.34 (44)
...output...

Ce que signifie la sortie : Du trafic DNS sur loopback existe (bon pour un résolveur local). Si vous voyez des requêtes répétées sans réponses, ou du trafic rebondissant entre 127.0.0.1 et 127.0.0.53 en motifs, vous avez construit la boucle.

Décision : Si les preuves suggèrent une boucle, arrêtez de deviner et corrigez la chaîne. Un résolveur doit être « le dernier saut ».

Tâche 14 : Vérifier que le fichier de trust anchor root existe

cr0x@server:~$ sudo ls -l /var/lib/unbound/root.key
-rw-r--r-- 1 root root 1091 Jan  1 10:00 /var/lib/unbound/root.key

Ce que signifie la sortie : Le fichier des trust anchors est présent. S’il manque, la validation se comportera de façon imprévisible ou échouera.

Décision : S’il manque, installez le paquet qui le fournit (souvent un comportement unbound-anchor ou des hooks spécifiques à la distro) ou générez correctement les anchors, puis redémarrez.

Transfert vs récursion complète : choisissez délibérément

Unbound peut faire de la récursion complète, ou renvoyer tout (ou des zones spécifiques) vers des résolveurs en amont. Il n’y a pas de pureté morale ici. Il y a des compromis.

Récursion complète : autonomie, moins de dépendances, plus de surface d’exposition

Avec la récursion complète, Unbound interroge les serveurs root et descend. Avantages :

  • Moins de dépendance au comportement d’un résolveur amont.
  • Politique de cache et de validation prévisible.
  • Souvent plus de résilience si un fournisseur amont a un mauvais jour.

Coûts :

  • Plus de diversité de trafic (beaucoup de serveurs autoritaires), ce qui peut déclencher des politiques egress restrictives.
  • Plus d’exposition aux bizarreries MTU et au « DNS bloqué sauf vers nos résolveurs d’entreprise ».
  • Plus de responsabilité : vous possédez tout le chemin de récursion.

Forwarding : simplicité, conformité et réalité d’entreprise

Le forwarding est courant en entreprise : Unbound met en cache localement mais envoie les manques à un résolveur récursif connu (interne, ISP, stack de sécurité). C’est souvent le bon choix quand :

  • Vous avez du DNS split‑horizon interne et ne pouvez pas répliquer les zones ailleurs.
  • Vous avez un filtrage ou un logging imposé en amont.
  • La sortie vers l’extérieur est restreinte à quelques IP de résolveurs.

Config de forwarding sûre (et comment ne pas se renvoyer soi‑même)

Ajoutez un fichier de forward zone. Utilisez des IP explicites. Pas resolv.conf. Pas 127.0.0.53.

cr0x@server:~$ sudo tee /etc/unbound/unbound.conf.d/forwarders.conf >/dev/null <<'EOF'
forward-zone:
  name: "."
  forward-addr: 1.1.1.1
  forward-addr: 1.0.0.1
EOF
...output...
cr0x@server:~$ sudo unbound-checkconf
unbound-checkconf: no errors in /etc/unbound/unbound.conf
cr0x@server:~$ sudo systemctl restart unbound
...output...

Décision : Si vous êtes sur un réseau d’entreprise avec des zones internes, vous voudrez probablement renvoyer vers des résolveurs d’entreprise (pas publics), plus des renvois explicites pour des suffixes internes si nécessaire.

Performance et réglages de fiabilité qui ne vous mordront pas plus tard

La plupart des installations Unbound n’ont pas besoin d’optimisations héroïques. Le DNS est léger comparé aux bases de données. Les erreurs viennent d’« optimiser » sans modèle, et de traiter le DNS comme sans état.

Threads et descripteurs de fichiers

Si vous exécutez un résolveur central servant de nombreux clients, envisagez plusieurs threads et assurez‑vous que les limites système ne sont pas basses. Sur un cache local sur un seul hôte, un thread suffit.

Vérifications typiques :

cr0x@server:~$ systemctl show unbound -p LimitNOFILE
LimitNOFILE=1048576

Décision : Si LimitNOFILE est petit (comme 1024) sur un résolveur chargé, augmentez‑le via un override systemd. Si c’est déjà élevé, ne le touchez pas juste parce que vous le pouvez.

EDNS buffer size : la correction discrète pour les échecs « aléatoires »

Nous avons fixé edns-buffer-size: 1232 pour une raison : cela réduit le risque de fragmentation sur des chemins modernes typiques. C’est particulièrement utile dans des environnements avec VPN, tunnels ou firewalls qui maltraitent les fragments.

Quand cela compte, les symptômes sont pénibles : certains domaines fonctionnent, d’autres expirent, et les tentatives réussissent mystérieusement parfois via TCP. DNSSEC aggrave le problème car les réponses sont plus volumineuses.

Prefetch : bon si vous avez du trafic répété, mauvais sinon

prefetch: yes signifie qu’Unbound peut rafraîchir les enregistrements populaires avant leur expiration. Cela lisse la latence pour les noms chauds. Mais si vous avez un résolveur servant une grande variété de noms uniques (pensez tracking, ad tech), le prefetch peut générer une charge amont supplémentaire.

Ne réfléchissez pas trop ; mesurez. Si le trafic amont explose et que vous n’avez pas d’ensembles chauds stables, désactivez prefetch.

Logging : la verbosité n’est pas de l’observabilité

Unbound peut beaucoup logger. En production, « beaucoup » devient « bruit plus factures ». Gardez‑le bas par défaut. Quand vous avez besoin de détails, augmentez temporairement.

Contrôles d’accès : évitez de devenir le relais d’un botnet

Si vous liez Unbound à une IP LAN, vous devez configurer correctement access-control. Un résolveur récursif ouvert sera utilisé pour des attaques d’amplification. Vous ne voulez pas que votre serveur DNS joue le premier rôle dans un rapport d’incident d’autrui.

Blague n°2 (courte, pertinente) : Exécuter un résolveur ouvert est une excellente façon de se faire de nouveaux amis sur Internet. Malheureusement, ils ne viennent que lorsqu’ils ont besoin de bande passante.

Trois mini‑histoires d’entreprise (anonymisées, réalistes)

Incident #1 : la mauvaise hypothèse (le fallacieux « resolv.conf dit la vérité »)

Une entreprise SaaS de taille moyenne voulait accélérer les déploiements. Leurs runners CI faisaient beaucoup de DNS : pulls d’images, accès aux stores d’artefacts, appels API internes. Quelqu’un a suggéré « installez Unbound sur les runners pour le cache ». Raisonnable.

L’ingénieur a écrit un rôle Ansible qui installait Unbound puis créait une config de forward pointant vers le résolveur trouvé dans /etc/resolv.conf. L’idée était de « respecter les paramètres réseau locaux ». Sur le papier, très poli. En réalité, beaucoup de runners avaient /etc/resolv.conf lié au stub de systemd-resolved à 127.0.0.53.

Séparément, un autre changement d’automatisation avait configuré systemd-resolved pour utiliser 127.0.0.1 afin d’« utiliser le cache local ». Personne n’a relié les deux changements car ils sont arrivés à des semaines d’intervalle et étaient gérés par des équipes différentes.

L’incident était subtil au début. Les jobs CI ont commencé à expirer pendant des étapes « aléatoires » : parfois des pulls docker, parfois un curl vers une API interne, parfois même apt. Quelques relances réussissaient. La longueur de la file augmentait ; les ingénieurs blâmaient le système de build.

Ce qui a fini par révéler le problème est une capture de paquets sur loopback montrant des requêtes DNS rebondissant entre 127.0.0.1 et 127.0.0.53 avec des IDs répétés. Boucle de résolveur. La correction fut ennuyeuse : arrêter de renvoyer basé sur resolv.conf, configurer des upstreams explicites, et documenter une chaîne de résolveurs supportée unique. Après incident, la nouvelle règle était : « resolv.conf n’est pas une source de vérité ; c’est un résultat de politique. »

Incident #2 : une optimisation qui s’est retournée contre eux (cache agressif et outages surprenants)

Une équipe plateforme interne gérait Unbound comme cluster de résolveurs centraux. Ils étaient fiers de leurs graphiques de performance DNS. Un trimestre, ils ont décidé de « réduire la charge amont » en augmentant fortement cache-max-ttl et en mettant cache-min-ttl à une valeur non nulle pour garder les enregistrements chauds même si les TTL autoritaires étaient faibles.

En quelques jours, une équipe a effectué une rotation d’adresses IP de service derrière un nom DNS dans le cadre d’un déploiement blue/green. Le TTL autoritaire était volontairement bas. Le cluster de résolveurs, maintenant appliquant un TTL minimum plus élevé, a continué à servir des IP obsolètes. Le trafic a afflué vers des nœuds vidés. Le déploiement a paru comme une panne partielle.

L’équipe plateforme a argumenté que « le DNS ne devrait pas être utilisé pour le load balancing de toute façon ». Ils n’avaient pas tort en principe, mais ils avaient tort en pratique : l’organisation le faisait déjà, et le changement de résolveur a silencieusement changé la sémantique du TTL. Ce n’est pas une optimisation ; c’est un changement sémantique dans une dépendance centrale.

La correction fut double : revenir cache-min-ttl à 0, et créer une liste d’exceptions politiques seulement pour les domaines où ils contrôlaient tout le cycle de vie et pouvaient accepter la staleness. Ils ont aussi ajouté une revue pré‑changement : « Ce changement modifiera‑t‑il le comportement des TTL ? » Vous seriez surpris combien d’incidents commencent parce que quelqu’un oublie que le DNS fait partie du contrat.

Incident #3 : la pratique ennuyeuse et correcte qui a sauvé la situation (staging + canary + rollback rapide)

Une société de services financiers exploitait une paire de résolveurs Unbound par datacenter, frontés par anycast dans chaque site. Leur DNS était volontairement ennuyeux : personnalisation minimale, forwarders explicites pour les zones internes, récursion pour le reste, et contrôles d’accès stricts.

Un mardi, une équipe réseau a déployé une mise à jour de politique firewall. Elle a involontairement bloqué TCP/53 sortant depuis le VLAN des résolveurs, tout en laissant UDP/53 autorisé. La plupart des requêtes ont continué de fonctionner. Puis les échecs ont commencé : certains domaines (surtout signés DNSSEC avec des réponses plus larges) ont commencé à expirer. Les applications dépendantes de ces domaines ont échoué de façons ressemblant à des « problèmes de handshake TLS » ou des « timeouts API aléatoires ».

Voici ce qui les a sauvés : ils avaient un résolveur canari dans chaque site sur un chemin de politique séparé, et ils exécutaient régulièrement une petite suite de vérifications DNS contre lui (y compris des requêtes DNS forcées en TCP). Le canari s’est allumé en quelques minutes. Ils ont pu dire, avec confiance, « c’est le transport DNS, pas l’application ».

Le rollback a été propre car leur config Unbound était gérée par une approche simple et versionnée, et leur équipe firewall avait une procédure de revert testée. L’impact service est resté contenu. Personne n’a reçu de médaille de héros. C’est le but.

Mode opératoire de diagnostic rapide

Quand le DNS est « lent » ou « en panne », vous n’avez pas le temps pour la philosophie. Vous avez besoin d’une séquence serrée qui trouve le goulet d’étranglement rapidement.

Premier : confirmez à qui vous parlez

  1. Vérifiez /etc/resolv.conf et si c’est un symlink.
  2. Exécutez dig explicitement contre Unbound (@127.0.0.1).
  3. Comparez dig example.com (par défaut) vs dig @127.0.0.1 example.com.

Si les requêtes par défaut sont lentes mais direct‑vers‑Unbound rapides, le problème est le chemin résolveur système (resolved/NSS/VPN), pas Unbound.

Second : déterminez si c’est l’amont, DNSSEC ou le transport

  1. Vérifiez les logs Unbound pour motifs timeouts vs SERVFAIL.
  2. Testez des domaines connus bons avec +dnssec et cherchez ad ou SERVFAIL attendu sur des domaines mal signés.
  3. Forcez TCP avec +tcp pour voir si la fragmentation UDP est impliquée.

Si TCP marche et UDP échoue de façon intermittente, suspectez MTU/firewall. Si SERVFAIL apparaît surtout sur des domaines signés, suspectez DNSSEC/heure/trust anchor.

Troisième : vérifiez les contraintes de ressources et la saturation

  1. Vérifiez si Unbound est CPU‑bound (load, CPU processus) ou limité en descripteurs de fichiers.
  2. Vérifiez la perte de paquets et les retransmissions sur l’interface egress du résolveur.
  3. Vérifiez le taux de hits du cache via unbound-control stats_noreset (si activé).

Si vous n’avez pas les stats activées, activez‑les avant le prochain incident. « On ajoutera de l’observabilité plus tard » est la façon dont « plus tard » devient jamais.

Erreurs courantes : symptômes → cause racine → correctif

1) Symptom: SERVFAIL pour la plupart des requêtes, marche parfois après réessai

Cause racine : Boucle de résolveur (Unbound renvoyant vers le stub de systemd, qui renvoie en arrière), ou timeouts en amont.

Fix : Rendez la chaîne unidirectionnelle. Utilisez des forwarders explicites dans Unbound, ou désactivez systemd-resolved. Confirmez avec readlink -f /etc/resolv.conf et tcpdump -ni lo port 53.

2) Symptom: Certains domaines échouent toujours ; d’autres sont corrects

Cause racine : Échecs de validation DNSSEC, problèmes MTU/fragmentation, ou TCP/53 bloqué.

Fix : Testez avec dig +dnssec et dig +tcp. Mettez edns-buffer-size: 1232. Assurez‑vous que TCP/53 sortant est autorisé. Vérifiez la synchro d’heure.

3) Symptom: Le DNS « marche » sur l’hôte résolveur, mais les clients ne peuvent pas l’utiliser

Cause racine : Unbound lié uniquement à 127.0.0.1 ; manque d’access-control pour les sous‑réseaux clients ; firewall bloquant le 53 entrant.

Fix : Ajoutez interface: 0.0.0.0 ou une IP LAN spécifique, ajoutez access-control: 10.0.0.0/8 allow (ou votre sous‑réseau), et autorisez UDP/TCP 53 entrant sur l’interface.

4) Symptom: Pics de latence élevés toutes les quelques minutes

Cause racine : Cache trop petit, comportement de prefetch causant des pics, rate limiting côté amont, ou perte de paquets.

Fix : Activez les stats et inspectez hit/miss du cache. Si vous faites du forwarding, testez la latence amont directement. Envisagez de désactiver prefetch si votre ensemble de requêtes est extrêmement divers.

5) Symptom: Domaines internes échouent, domaines publics réussissent

Cause racine : Vous avez choisi la récursion complète mais vos zones internes ne sont résolubles que via des résolveurs d’entreprise (split‑horizon). Ou vous renvoyez « . » vers des résolveurs publics qui ne voient pas les noms internes.

Fix : Ajoutez des forwarders par zone pour les suffixes internes vers les serveurs DNS d’entreprise. Conservez récursion ou forwarding pour le reste selon le besoin.

6) Symptom: Tout casse après activation de la validation DNSSEC

Cause racine : Décalage d’horloge, trust anchor manquant, ou chaîne DNSSEC cassée en amont (courant avec certains middleboxes et anciens forwarders).

Fix : Corrigez NTP/heure. Vérifiez /var/lib/unbound/root.key. Si vous renvoyez vers un amont qui altère DNSSEC, changez d’amont ou désactivez la validation pour des zones internes spécifiques plutôt que globalement.

7) Symptom: NXDOMAIN aléatoires pour des noms qui devraient exister

Cause racine : Mauvaise gestion des domaines de recherche, confusion split DNS, ou cache négatif après une défaillance transitoire en amont.

Fix : Inspectez les domaines de recherche du résolveur et essayez des noms pleinement qualifiés avec un point final dans dig. Envisagez d’abaisser cache-max-negative-ttl si des NXDOMAINs transitoires sont fréquents (mais ne le mettez pas à zéro à moins d’aimer la charge amont).

Listes de contrôle / plan pas à pas

Plan A : Résolveur en cache localhost sur un seul serveur (version 15 minutes)

  1. Installer unbound et dnsutils.
  2. Configurer Unbound pour écouter uniquement sur 127.0.0.1.
  3. Activer DNSSEC, définir edns-buffer-size: 1232.
  4. Démarrer Unbound et confirmer qu’il écoute sur 127.0.0.1:53 (UDP+TCP).
  5. Choisir : désactiver systemd-resolved (plus simple) ou le configurer pour renvoyer vers Unbound.
  6. Vérifier avec dig @127.0.0.1 et getent.
  7. Exécuter le test de boucle : assurez‑vous qu’Unbound ne renvoie pas vers 127.0.0.53.

Plan B : Résolveur central pour un sous‑réseau (faites‑le si vous voulez que d’autres machines l’utilisent)

  1. Lier Unbound à une IP LAN (pas 0.0.0.0 sauf si vous le voulez).
  2. Ajouter des entrées access-control pour les sous‑réseaux clients.
  3. Firewall : autoriser UDP/TCP 53 entrant depuis ces sous‑réseaux ; autoriser UDP/TCP 53 sortant vers les upstreams ou Internet (si récursif).
  4. Décider récursion vs forwarding ; configurer des forwarders explicites si nécessaire.
  5. Test canari depuis un client : dig @resolver-ip example.com.
  6. Ajouter un second résolveur pour la redondance ; pointer les clients vers les deux.
  7. Instrumenter : activer les stats Unbound ; s’assurer que les logs sont raisonnables et limités en débit.

Plan C : Gestion des changements qui prévient les incidents DNS

  1. Rendre la chaîne de résolveurs explicite dans la doc : client → stub (optionnel) → Unbound → amont.
  2. Ajouter la validation de config au déploiement (unbound-checkconf doit réussir).
  3. Requêtes canari : inclure un domaine test DNSSEC et une requête forcée TCP.
  4. Avoir une procédure de rollback : revert de config, restart, confirmation écoute et succès des requêtes.

FAQ

1) Dois‑je exécuter Unbound sur chaque hôte ou centralement ?

Si vous voulez l’histoire de fiabilité la plus simple pour une flotte, exécutez un petit pool central et pointez les clients vers lui. Si vous voulez la meilleure latence par hôte et la résilience contre des fluctuations réseau, exécutez‑le localement. L’hybride va bien si vous documentez la chaîne et évitez les boucles.

2) Unbound est‑il meilleur que systemd-resolved ?

Ils résolvent des problèmes différents. systemd-resolved est un stub resolver avec une logique par lien ; Unbound est un vrai résolveur récursif en cache. Utilisez resolved pour la plomberie réseau et Unbound pour la politique/caching/validation DNS. Juste : ne les laissez pas se poursuivre en rond.

3) Ai‑je besoin de la validation DNSSEC ?

Si vous pouvez maintenir une synchronisation horaire solide et que votre réseau ne maltraite pas le DNS, la validation est un bon filet de sécurité. Si votre environnement inclut des middleboxes instables ou un DNS interne cassé côté DNSSEC, scindez‑la soigneusement ou vous échangerez sécurité contre pannes.

4) Pourquoi ai‑je besoin de TCP/53 si le DNS est « UDP » ?

Parce que les réponses volumineuses existent (DNSSEC, grands TXT, gros ensembles NS), et la troncation force le repli TCP. Bloquer TCP/53 crée des échecs intermittents, spécifiques à certains domaines, qui ressemblent à des fantômes.

5) Quelle est la façon la plus sûre de configurer des forwarders ?

Utilisez des IP explicites dans forward-zone. Ne « renvoyez pas vers resolv.conf ». resolv.conf est souvent un stub, et les stubs sont la voie vers les boucles.

6) Unbound peut‑il servir aussi d’autoritaire DNS ?

Il peut gérer quelques local-data, mais ce n’est pas un serveur autoritaire au sens de NSD ou d’un mode autoritatif de BIND. Utilisez‑le principalement comme résolveur et gardez l’autoritatif séparé sauf si vous faites un petit hack intentionnel (par ex. surcharger quelques noms).

7) Comment savoir que le cache fonctionne réellement ?

Exécutez la même requête dig deux fois contre Unbound et comparez le Query time. Pour une preuve plus approfondie, activez les statistiques et surveillez les métriques de hits du cache. Vérifiez aussi que les clients envoient réellement les requêtes à Unbound, pas qu’ils le contournent.

8) Quel est un bon TTL de cache négatif ?

Cinq minutes (cache-max-negative-ttl: 300) est une valeur pragmatique. Abaissez‑le si les NXDOMAINs transitoires vous nuisent. Des valeurs plus élevées peuvent laisser des erreurs et des défaillances en amont persister plus longtemps que souhaité.

9) J’ai activé Unbound, mais le split DNS du VPN a cessé de fonctionner. Pourquoi ?

Beaucoup de clients VPN s’intègrent à systemd-resolved pour installer des routes DNS par domaine ou par interface. Si vous désactivez resolved (Option A), vous pouvez perdre ce comportement. Utilisez l’Option B (stub resolved + Unbound en amont) ou gérez le split DNS explicitement dans Unbound avec des zones forward.

10) Comment éviter de devenir un résolveur ouvert ?

Liez seulement aux interfaces nécessaires et configurez access-control pour n’autoriser que vos réseaux clients. Ne l’exposez pas à l’internet public. Vérifiez aussi avec ss que vous n’écoutez pas sur 0.0.0.0 sauf si c’est intentionnel.

Étapes suivantes que vous devriez réellement faire

Vous pouvez lancer Unbound rapidement. Le faire fonctionner correctement est la partie qui vous évitera des incidents futurs.

  • Verrouillez la chaîne de résolveurs : décidez si systemd-resolved fait partie du chemin et rendez‑le unidirectionnel. Pas de boucles.
  • Vérifiez avec des preuves : dig @127.0.0.1 deux fois pour le cache, +dnssec pour la validation, +tcp pour la robustesse du transport.
  • Choisissez récursion vs forwarding intentionnellement : les réseaux d’entreprise veulent généralement du forwarding (au moins pour les zones internes).
  • Ajoutez un check canari : un test DNSSEC, un test TCP forcé, un nom interne. Exécutez‑le en continu.
  • Gardez la configuration ennuyeuse : évitez les overrides de TTL ingénieux et n’« optimisez » qu’après mesure.

Le DNS est une dépendance que vous ne pouvez pas éviter. La bonne nouvelle est que vous pouvez la rendre prévisible. Unbound est l’un des rares outils dans cet espace qui se comporte comme s’il voulait que vous dormiez tranquille.

← Précédent
Checklist de sécurité Proxmox : 2FA, RBAC, pare-feu, mises à jour et accès distant sécurisé
Suivant →
Ubuntu 24.04 : les caches DNS mentent — videz le bon cache (et arrêtez de vider le mauvais) (cas n°26)

Laisser un commentaire