Set-OPS-Public/roles/serveur_powerdns/templates/zone-publique.db.j2
Daniel Allaire 712ad9f630 DNSSEC : le locataire signe, avec la cle de sa voute
Cle CSK ECDSA P-256 tiree dans la voute du locataire, importee par le role, DS calcule
sans la machine. Refus de changer la cle ou de retirer la signature tant qu'un DS est
publie. SOA-EDIT EPOCH : INCEPTION-EPOCH aurait laisse expirer les signatures du site.
CAA sur chezlepro.ca, sonde des signatures au site, P18 deplie vault_dnssec_<zone>.

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

49 lines
3 KiB
Django/Jinja

{# LE SERVEUR DE NOMS EST CELUI DU SITE, SOUS LE NOM QUE LE SITE DECLARE (2026-09-16).
La premiere version ecrivait `ns1.<zone>` dans chaque zone. Or `ns1.chezlepro.ca`
existe en production, vers une autre adresse : basculer l'aurait deplace en silence.
Toutes les zones du site designent desormais un seul nom, `dns_public_nom`, et seule la
zone qui le contient porte son A. #}
{% set _ns = serveur_powerdns_dns_public_nom | trim | regex_replace('\\.$', '') %}
$ORIGIN {{ zone_publique }}.
$TTL {{ serveur_powerdns_ttl }}
@ IN SOA {{ _ns }}. hostmaster.{{ zone_publique }}. (
{{ serveur_powerdns_serial_public }}
{{ serveur_powerdns_soa_refresh }}
{{ serveur_powerdns_soa_retry }}
{{ serveur_powerdns_soa_expire }}
{{ serveur_powerdns_soa_minimum }}
)
{# L'ETAT DNSSEC FAIT PARTIE DU CORPS. Signer, changer de cle ou retirer la signature ne
change aucun enregistrement : sans cette ligne, le serial ne bougerait pas, et le site
garderait la version non signee (eprouve le 2026-09-16). L'empreinte d'une cle aleatoire
de 256 bits ne revele rien d'elle. #}
{% set _cle = lookup('vars', 'vault_dnssec_' ~ (zone_publique | lower | regex_replace('[^a-z0-9]', '_')), default='') %}
; DNSSEC : {{ ('signee, cle ' ~ (_cle | hash('sha256'))[:12]) if ((domaines_publics[zone_publique].dnssec | default(false) | bool) and _cle) else 'non signee' }}
@ IN NS {{ _ns }}.
{% if _ns.endswith('.' ~ zone_publique) %}
{{ _ns[:-(zone_publique | length + 1)] }} IN A {{ serveur_powerdns_ip_publique }}
{% endif %}
{# UNE ZONE PUBLIQUE NE PORTE QUE DES ADRESSES PUBLIQUES.
Un nom expose sous ce domaine resout vers l'adresse publique du site — la frontiere le
relaie ensuite a l'edge. Jamais vers l'adresse interne de l'edge : elle ne resoudrait
pour personne dehors, et renseignerait sur le reseau dedans. #}
{% for expo in serveur_powerdns_expositions | default([]) if expo.domaine == zone_publique %}
{{ expo.fqdn[:-(zone_publique | length + 1)] if expo.fqdn != zone_publique else '@' }} IN A {{ serveur_powerdns_ip_publique }}
{% endfor %}
{# LES ENREGISTREMENTS DECLARES AU PLAN : courriel, verifications, noms historiques.
`valider_domaines` les a deja passes au crible (adresses publiques, cibles completes,
CNAME seul a son nom, texte sans guillemet). Le gabarit ne fait que les ecrire. Un TXT
plus long que 255 octets — une cle DKIM — est coupe en tranches : un resolveur les
recolle, et une seule chaine trop longue rendrait la zone illisible. #}
{% for enr in (domaines_publics | default({}))[zone_publique].enregistrements | default([]) %}
{% set _t = enr.type | upper %}
{% set _v = enr.valeur | string | trim %}
{{ enr.nom }} {{ enr.ttl | default('') }} IN {{ _t }} {% if _t in ['A', 'AAAA'] %}{{ _v }}{% elif _t == 'CNAME' %}{{ _v.rstrip('.') }}.{% elif _t == 'MX' %}{{ enr.priorite }} {{ _v.rstrip('.') }}.{% elif _t == 'CAA' %}0 {{ enr.etiquette }} "{{ _v }}"{% elif _t == 'TXT' %}{% for i in range(0, _v | length, 255) %}"{{ _v[i:i + 255] }}"{{ ' ' if not loop.last }}{% endfor %}{% endif %}
{% endfor %}