Set-OPS-Public/roles/serveur_powerdns/templates/zone.db.j2
Daniel Allaire a74e35bf21
Some checks are pending
verifier / verifier (push) Waiting to run
site : le plancher survit au redemarrage, et la zone dit les vraies adresses
Le decoupage du site en quatre zones a deplace cinq machines. Ni le plancher
/etc/hosts ni la zone DNS n'avaient suivi. Quatre defauts, tous dans le moteur.

LE PLANCHER ETAIT EFFACE A CHAQUE DEMARRAGE — ET LE PREMIER CORRECTIF N'EN
ETAIT PAS UN.

`hosts_statiques` posait `99-setops-hosts.cfg` avec `manage_etc_hosts: false`,
pendant que `cloud_init` posait `99_setops.cfg` avec `true`. Dans `cloud.cfg.d`
l'ordre est LEXICAL et le dernier gagne : `-` vaut 0x2D, `_` vaut 0x5F. On a
donc retire la cle de `cloud_init` — le role qui POSSEDE le fichier decide —
puis renomme notre fragment `zz-` pour passer apres le `99_chezlepro.cfg` du
gabarit dore.

Et ca ne suffisait toujours pas. Redemarrage d'epreuve : plancher encore efface.
La cause reelle est ailleurs — Proxmox inscrit `manage_etc_hosts: true` dans la
USER-DATA de son lecteur cloud-init, et la user-data prime sur `cloud.cfg.d`
tout entier. Aucun fragment ne pouvait gagner ; renommer pour parler en dernier
ne servait a rien, le dernier mot n'appartenant pas a ce repertoire.

Ce que cloud-init regenere, il le regenere depuis `hosts.debian.tmpl` — le
gabarit le documente lui-meme. `hosts_statiques` le pose desormais avec le MEME
contenu que /etc/hosts, et une garde compare les deux a chaque passage.
Redemarrage d'epreuve : les neuf entrees sont la.

La garde precedente affirmait « conforme » en mesurant l'ordre lexical — vrai,
et sans rapport avec ce qui se passait. Une garde qui mesure la mauvaise chose
est pire qu'aucune.

LA ZONE DNS NE PUBLIAIT PAS LES NOMS DE SERVICE.

`forge.genese.internal` et `pki.genese.internal` — des noms que les certificats
portent et que les clients appellent — n'avaient aucun enregistrement. Seul le
plancher savait les resoudre. Trois causes empilees :

  - le plan du site coupait `serveur_powerdns_publier_expositions`, au motif que
    « le site n'a pas d'edge » : ca confondait PUBLIC et EXPOSE ;
  - `expositions_des_applications` rendait `domaine: None` faute de
    `domaines.yml`, et le modele de zone ecarte les expositions dont le domaine
    n'est pas la zone. Repli ajoute, symetrique de celui deja ecrit pour `edge` :
    sans domaine public declare, le domaine est celui que porte le FQDN ;
  - `serveur_powerdns` exigeait les deux registres et echouait si `domaines.yml`
    manquait — le meme tout-ou-rien que `hosts_statiques` a corrige le meme jour.

Puis `named-checkzone` a refuse la zone : `dns.genese.internal` heritait d'un
CNAME par defaut du role ET d'un A par exposition. La garde a bien joue son role
— elle a arrete une zone cassee avant qu'elle soit servie. Le plan l'emporte
desormais sur le defaut du role.

Un service ne doit pas dependre d'un plancher pour etre joignable : le plancher
est un filet, pas le sol.

VERIFICATION. Les huit noms — cinq machines, trois services — resolvent vers les
bonnes adresses depuis les cinq hotes, par le plancher ET par le DNS, et le
plancher survit au redemarrage.

P46 refuse desormais deux choses : plus d'un role ecrivant `manage_etc_hosts`,
et l'absence du gabarit maitre. Controle negatif verifie.

RESTE NOMME, PAS CORRIGE : la zone INVERSE. `serveur_powerdns_zone_inverse`
derive d'un supernet /16 — la forme d'un tenant. Un site declare plusieurs /24
et n'a pas de supernet unique : aucune zone inverse n'est generee.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 20:31:01 -04:00

54 lines
2.5 KiB
Django/Jinja

$ORIGIN {{ serveur_powerdns_zone }}.
$TTL {{ serveur_powerdns_ttl }}
@ IN SOA {{ serveur_powerdns_nameserver }}.{{ serveur_powerdns_zone }}. {{ serveur_powerdns_contact }}. (
{{ serveur_powerdns_serial }}
{{ serveur_powerdns_soa_refresh }}
{{ serveur_powerdns_soa_retry }}
{{ serveur_powerdns_soa_expire }}
{{ serveur_powerdns_soa_minimum }}
)
@ IN NS {{ serveur_powerdns_nameserver }}.{{ serveur_powerdns_zone }}.
{{ serveur_powerdns_nameserver }} IN A {{ hostvars[groups['serveur_powerdns'][0]].ansible_host | default('127.0.0.1') }}
{# LE PLAN L'EMPORTE SUR LE DEFAUT DU ROLE (2026-08-25).
`serveur_powerdns_records` porte un defaut de commodite : `dns IN CNAME ns1`. Le plan
du site, lui, expose `dns.genese.internal` pour `serveur_resolveur` — ce qui produit un
`dns IN A`. Un nom ne peut pas porter a la fois un CNAME et un A : `named-checkzone` a
refuse la zone (« CNAME and other data »), et PowerDNS ne l'a pas servie du tout.
La garde a bien fonctionne — elle a arrete une zone cassee avant qu'elle soit servie.
Mais elle laissait le DNS du site sans zone tant que la collision durait.
On ecarte donc le record statique quand le plan expose le meme nom. C'est le sens de
marche du depot : ce qui est DECLARE AU PLAN prime sur ce qu'un role suppose par
defaut. Les deux pointaient de toute facon vers la meme machine. #}
{% set _exposes = [] %}
{% if serveur_powerdns_publier_expositions | default(false) %}
{% for expo in serveur_powerdns_expositions | default([]) if expo.domaine == serveur_powerdns_zone %}
{% set _ = _exposes.append(expo.fqdn[:-(serveur_powerdns_zone | length + 1)]) %}
{% endfor %}
{% endif %}
{% for record in serveur_powerdns_records if record.name not in _exposes %}
{{ record.name }} IN {{ record.type }} {{ record.value }}
{% endfor %}
{% set emitted = [] %}
{% for group_name in serveur_powerdns_inventory_groups %}
{% for host_name in groups.get(group_name, []) | sort %}
{% if hostvars[host_name].ansible_host is defined and host_name not in emitted %}
{{ host_name }} IN A {{ hostvars[host_name].ansible_host }}
{% set _ = emitted.append(host_name) %}
{% endif %}
{% endfor %}
{% endfor %}
{% if serveur_powerdns_publier_expositions | default(false) %}
{% for expo in serveur_powerdns_expositions | default([]) if expo.domaine == serveur_powerdns_zone %}
{% set edge_hosts = groups.get(expo.edge, []) %}
{% if edge_hosts and hostvars[edge_hosts[0]].ansible_host is defined %}
{{ expo.fqdn[:-(serveur_powerdns_zone | length + 1)] }} IN A {{ hostvars[edge_hosts[0]].ansible_host }}
{% endif %}
{% endfor %}
{% endif %}