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>
173 lines
7 KiB
Markdown
173 lines
7 KiB
Markdown
# 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.
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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 :
|
|
|
|
```text
|
|
exemple.internal
|
|
```
|
|
|
|
Elle est definie dans :
|
|
|
|
```text
|
|
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 :
|
|
|
|
```text
|
|
hote dans hotes_actifs
|
|
ansible_host defini
|
|
```
|
|
|
|
Exemple :
|
|
|
|
```text
|
|
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 :
|
|
|
|
```yaml
|
|
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.
|