Set-OPS-Public/docs/dns-interne.md
Daniel Allaire 788c5073dc DNS public, phase 1 : le locataire ecrit, le site sert
Role serveur_dns_public (secondaire public, transfert signe TSIG, aucune zone interne) ;
serveur_powerdns exerce enfin autorite primaire-cache dans une instance pdns@public a part,
pour que le site ne puisse jamais interroger la zone .internal. Relations derivees des plans
des locataires, mots de flux dns_public_site et primaires_dns_locataires. Eprouve avant
d ecrire : allow-axfr-ips et TSIG sont alternatifs, le primaire notifie aussi ses NS, le
serial fige aurait gele le secondaire. P82 refuse l exposition sans DNSSEC.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 18:08:20 -04:00

7 KiB

DNS interne

Pour qui : le mainteneur du DNS interne.

Le service DNS interne est la premiere capacite de plateforme.

Plancher de resolution independant du DNS. Le socle (hosts_statiques, dans serveur_debian) genere /etc/hosts sur chaque VM depuis l'inventaire : tout l'ecosysteme se resout par nom meme serveur DNS eteint (et au bootstrap, avant que PowerDNS ne soit la). PowerDNS devient une commodite (zone, externe, dynamique), plus un point de defaillance.

Trois couches, et une seule est optionnelle

Ce paragraphe decrivait le modele d'avant le 2026-08-24 — un Unbound sur chaque VM, en opt-in. Ce n'est plus le cas : client_resolveur n'installe plus rien, et son integration est universelle, pas elective.

1. hosts_statiques   le PLANCHER : /etc/hosts genere sur chaque VM depuis l'inventaire
                     -> l'ecosysteme se resout DNS eteint. Jamais optionnel.
2. serveur_powerdns  l'AUTORITATIF de la zone souveraine (un par ecosysteme)
3. serveur_resolveur le RECURSIF : UN seul Unbound pour tout le tenant, qui recurse
                     depuis la racine et delegue la zone souveraine a PowerDNS
   client_resolveur  l'integration : ecrit /etc/resolv.conf pour designer ce resolveur

client_resolveur n'installe plus de demon (2026-08-24). Il en posait un par VM — N demons identiques de ~21 Mo pour quelques centaines de requetes. Il ne fait plus qu'une chose : ecrire /etc/resolv.conf. Son integration est marquee universelle: true, et elle n'a aucune exemption, pas meme l'hote qui porte le resolveur : il se sert lui-meme. L'ancien nom (client_unbound) mentait des lors qu'il n'installait plus Unbound.

L'integration suit l'existence du service, elle ne se declare pas. Aucun serveur_resolveur au plan rend client_resolveur_actif faux et le role ne touche a rien : l'ecosysteme garde la resolution d'amorcage de cloud-init. C'est un choix valide, pas une panne.

Groupes

serveur_powerdns   -> autoritatif interne (PowerDNS Authoritative)
serveur_resolveur  -> LE recursif du tenant (Unbound), un seul
client_resolveur   -> integration universelle : designe ce resolveur dans /etc/resolv.conf

Zone initiale

La zone initiale est :

exemple.internal

Elle est definie dans :

instance/inventories/<inventaire>/group_vars/serveur_powerdns.yml

Enregistrement automatique

Le role serveur_powerdns genere la zone a partir de l'inventaire.

Les hotes qui remplissent ces conditions sont ajoutes automatiquement :

hote dans hotes_actifs
ansible_host defini

Exemple :

web-frontal-01 ansible_host=10.0.2.31
-> web-frontal-01.exemple.internal A 10.0.2.31

Les enregistrements additionnels explicites sont dans serveur_powerdns_records.

Backend PowerDNS

Le premier jalon utilise le backend BIND de PowerDNS.

Raison :

  • pas de dependance prematuree a PostgreSQL ;
  • zone lisible et generee par Ansible ;
  • idempotence simple ;
  • bon point de depart pour la supervision.

Quand serveur_postgresql sera stable, il sera possible de migrer vers un backend SQL si le besoin operationnel le justifie.

La bascule de /etc/resolv.conf est protegee

Le role client_resolveur ne bascule /etc/resolv.conf qu'apres avoir verifie que le resolveur repond deja — pour l'interne et pour l'Internet :

client_resolveur_apply: true
client_resolveur_confirm: true

Sans ces deux variables, le role prépare Unbound mais ne modifie pas /etc/resolv.conf.

Cette protection est volontaire : une mauvaise configuration DNS peut couper la resolution de noms. C'est la dependance la plus dangereuse du lot — basculer un hote sur un resolveur qui n'est pas encore pret le rend muet, et le runner qui devrait reparer tombe avec les autres. Le playbook de groupe applique donc l'hote qui porte le resolveur avant ceux qui s'y adressent, et la preuve P44 refuse tout ecart entre cette declaration et lui.

Le piege qui a coute deux jours : la racine signee nie notre TLD

internal. n'est pas delegue dans la racine, qui est signee : elle rend donc une preuve NXDOMAIN validee pour ce TLD. Or harden-below-nxdomain — actif par defaut dans Unbound — tient ce « non » pour prouve et repond NXDOMAIN pour tout nom sous internal. depuis son cache, sans jamais interroger la stub-zone declaree plus bas.

La delegation etait correcte. L'autoritatif repondait juste. Pas une requete ne lui parvenait.

Ce qui declenche l'empoisonnement : n'importe quelle question sur un nom inexistant sous internal. — y compris la zone d'un autre ecosysteme, que ce resolveur ne sert pas et va donc chercher a la racine. Sur un resolveur partage, ca arrive en permanence.

Et la panne parait intermittente : au redemarrage le cache est vide, tout fonctionne, on conclut que c'est regle. Le remede mesure (2026-09-02) est harden-below-nxdomain: no dans roles/serveur_resolveur/templates/setops.conf.j2 — pas aggressive-nsec, qui traite un autre symptome.

Surveillance a prevoir

Les premiers checks utiles :

  • service pdns actif ;
  • port UDP/TCP 53 disponible ;
  • SOA de exemple.internal resoluble ;
  • enregistrement ns1.exemple.internal resoluble ;
  • enregistrements des hotes actifs presents ;
  • serial de zone attendu ;
  • latence de resolution.

Zones publiques

Ajouté le 2026-09-16. Le mode primaire-cache était validé par le schéma et consommé par rien depuis sa création — une autorité qu'on s'attribue sans l'exercer est une panne différée.

plan/domaines.yml porte un champ autorite par domaine. Deux valeurs sont exercées :

autorite Ce que ça veut dire Qui sert la zone
auto-heberge zone interne (.internal), servie à l'écosystème seul l'instance principale de serveur_powerdns, sur la boucle locale
primaire-cache zone publique : le locataire l'écrit, le site la sert pdns@public chez le locataire (primaire caché), serveur_dns_public au site (secondaire public)

delegue est accepté par le validateur et n'est consommé par aucun rôle. Il ne faut pas le déclarer en croyant qu'il fait quelque chose.

Le locataire écrit, le site sert, un site pair réplique. Le primaire reste chez le locataire : quand il part, il emporte sa zone. Le détail — et ce que l'épreuve de PowerDNS a appris — est dans roles/serveur_dns_public/README.md.

Trois règles, chacune payée ou mesurée :

  • TSIG seul ouvre le transfert. allow-axfr-ips et TSIG sont alternatifs : une adresse listée obtient la zone sans signature. L'instance publique n'autorise que la boucle locale.
  • Une instance à part pour le public. Faire écouter l'instance principale sur l'adresse de l'hôte aurait permis au serveur public du site d'interroger la zone .internal.
  • Le serial suit le contenu. Un serial figé ferait garder au secondaire l'ancienne zone pour toujours.

Rien n'est exposé à Internet en phase 1. P82 refuse d'exposer le serveur public tant que toutes ses zones ne sont pas signées DNSSEC.