--- serveur_powerdns_packages: - pdns-server - pdns-backend-bind - bind9-utils - dnsutils serveur_powerdns_service_name: "pdns" serveur_powerdns_zone_directory: "/etc/powerdns/zones" serveur_powerdns_bind_config: "/etc/powerdns/bindbackend.conf" serveur_powerdns_zone: "{{ domaine_interne }}" serveur_powerdns_nameserver: "ns1" serveur_powerdns_contact: "hostmaster.{{ domaine_interne }}" serveur_powerdns_ttl: 3600 serveur_powerdns_serial: 2026062201 serveur_powerdns_soa_refresh: 3600 serveur_powerdns_soa_retry: 900 serveur_powerdns_soa_expire: 1209600 serveur_powerdns_soa_minimum: 3600 # L'adresse du tenant SEULEMENT, pas `0.0.0.0` : lier toutes les interfaces occupe aussi # `127.0.0.1:53`, ou un resolveur recursif local voudrait s'installer. Ce n'est pas un # probleme theorique — c'est la raison pour laquelle `client_resolveur` exempte cet hote. # PowerDNS reste autoritatif pur : il repond pour la zone souveraine et REFUSE le reste. # LE RESOLVEUR DU TENANT PARTAGE CET HOTE (2026-08-24). Quand c'est le cas, l'autoritatif # lui laisse le port 53 de l'adresse LAN et se replie sur la loopback, sur un autre port : # le resolveur devient la SEULE porte, et personne n'interroge l'autoritatif directement. # # Derive de l'inventaire, pas declare a la main : l'exploitant ne doit pas avoir a se # souvenir de deplacer un port parce qu'il a ajoute un role. serveur_powerdns_colocalise_resolveur: >- {{ inventory_hostname in (groups['serveur_resolveur'] | default([])) }} serveur_powerdns_listen_port: "{{ 5300 if (serveur_powerdns_colocalise_resolveur | bool) else 53 }}" serveur_powerdns_listen_addresses: >- {{ ['127.0.0.1'] if (serveur_powerdns_colocalise_resolveur | bool) else [ansible_host | default('0.0.0.0')] }} serveur_powerdns_allow_axfr_ips: [] # Enregistrements additionnels geres explicitement. serveur_powerdns_records: - name: "dns" type: "CNAME" value: "ns1.{{ serveur_powerdns_zone }}." # Groupes dont les hotes actifs avec ansible_host seront ajoutes a la zone. serveur_powerdns_inventory_groups: - hotes_actifs # Publier des A pour les FQDN d'exposition (champ 'expose' des applications) vers l'edge # qui les sert (domaines.edge). Ferme la boucle : declarer 'expose' -> vhost + cert + DNS. serveur_powerdns_publier_expositions: true serveur_powerdns_expositions: [] # ZONES INVERSES — DERIVEES, JAMAIS ECRITES. # # Rien dans le moteur ne touchait `in-addr.arpa` avant le 2026-08-08 : un hote pouvait # etre resolu par son nom et rester anonyme a l'envers, ce que le courriel et la # journalisation reprochent en silence. # # La premiere derivation supposait un supernet /16 — la forme d'un TENANT, qui tire tout # de son index. Un SITE ne derive pas : il declare ses reseaux, et il en declare # plusieurs. `setops_supernet` y vaut le /24 de la machine, jamais un /16, si bien que la # derivation rendait une chaine vide et qu'AUCUNE zone inverse n'etait generee (mesure du # 2026-08-25 : les cinq machines du site, sans PTR). # # On couvre desormais EXACTEMENT ce que l'ecosysteme occupe : un /16 quand il en a un, # sinon un /24 par reseau ou vit reellement une machine. Pour le site, les quatre zones # `31.0.10`, `32.0.10`, `33.0.10`, `34.0.10` — et rien au-dela. Revendiquer tout # `0.10.in-addr.arpa` aurait ete plus simple et faux : cette zone couvre aussi la # frontiere, le transit et les hyperviseurs, qui ne sont pas a lui. Une autorite qu'on # s'attribue sans l'exercer est une panne differee. # # LA DERIVATION VIT DANS UN FILTRE (`zones_inverses`), parce qu'elle a DEUX appelants : # `serveur_powerdns` ecrit ces zones, `serveur_resolveur` les delegue a l'autoritatif. # Deux calculs separes finiraient par diverger, et la divergence ne se verrait qu'au # premier PTR interroge. # # Le nom d'une zone dit sa profondeur : trois etiquettes numeriques valent un /24, deux # valent un /16. Le modele en deduit seul la forme du PTR ; rien n'est ecrit deux fois. serveur_powerdns_zones_inverses: >- {{ (serveur_powerdns_inventory_groups | map('extract', groups) | select | flatten | map('extract', hostvars, 'ansible_host') | select | list) | zones_inverses(setops_supernet | default('')) }}