Some checks are pending
verifier / verifier (push) Waiting to run
Chezlepro detruite (15 VM, disques compris) et refaite depuis le gabarit minimal. 15/15 hotes, 0 echec ; make valider passe, test de restitution compris. Aucun defaut ne venait de la flotte ni du gabarit. 1. Un avertissement n est pas un echec. Proxmox rend WARNINGS: n pour une tache ABOUTIE ; la garde n acceptait que OK et declarait perdues cinq VM clonees a 100 pourcent. Le message parlait d etat stopped — celui de la TACHE, pas de la VM. 2. client_artefacts se contredisait : son commentaire disait de degrader, son code arretait. L autorite monte en premier, donc avant le cache du locataire : aucun ordre ne pouvait satisfaire la garde. 3. harden-below-nxdomain etendait le NXDOMAIN signe de la racine pour le TLD internal a toute la zone du site, sans jamais interroger l autoritatif. Declencheur : toute question sur un nom absent sous internal, y compris la zone d un autre locataire. Le cache contenait la bonne reponse ET un message negatif ; c est le negatif qui etait servi. aggressive-nsec: no avait semble marcher — c est le redemarrage qui vidait le cache, pas le reglage. 4. Un locataire doit savoir a qui demander la zone de son hebergeur, sans quoi il ne peut plus nommer son depot de sauvegarde. La derivation prenait dns_amorcage pour le resolveur du site : faux chez Technolibre, dont l amorcage est 9.9.9.9. P03 l a attrape avant tout deploiement. Au passage : instancier tentait encore le mot de passe unique d avant la separation des voutes ; comparer echouait en exit 4. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
156 lines
8.6 KiB
Django/Jinja
156 lines
8.6 KiB
Django/Jinja
# GÉNÉRÉ par Set-OPS (rôle serveur_resolveur). NE PAS éditer à la main.
|
|
server:
|
|
{% for a in serveur_resolveur_ecoutes %}
|
|
interface: {{ a }}
|
|
{% endfor %}
|
|
{% for r in serveur_resolveur_reseaux_autorises %}
|
|
access-control: {{ r }} allow
|
|
{% endfor %}
|
|
access-control: 127.0.0.0/8 allow
|
|
hide-identity: yes
|
|
hide-version: yes
|
|
prefetch: yes
|
|
do-ip6: no
|
|
# LA RACINE PROUVE QUE NOTRE TLD N'EXISTE PAS, ET UNBOUND ETEND CE « NON »
|
|
# A TOUT CE QUI EST DESSOUS (mesure du 2026-09-02).
|
|
#
|
|
# `internal.` n'est pas delegue dans la racine, qui est SIGNEE : elle rend donc une
|
|
# preuve NXDOMAIN validee pour ce TLD. `harden-below-nxdomain` (actif par defaut)
|
|
# tient ce « non » pour prouve et repond NXDOMAIN pour TOUT nom sous `internal.`
|
|
# DEPUIS SON CACHE — sans jamais interroger la `stub-zone` ni la `forward-zone`
|
|
# declarees plus bas. La delegation etait correcte, l'autoritatif repondait juste, et
|
|
# 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 par plusieurs
|
|
# locataires, ca arrive en permanence.
|
|
#
|
|
# POURQUOI LE DIAGNOSTIC A DEMANDE DEUX JOURS. La panne parait INTERMITTENTE : au
|
|
# redemarrage le cache est vide, tout fonctionne, on conclut que c'est regle. Puis
|
|
# une seule requete l'eteint pour des heures. Pire, le cache contenait EN MEME TEMPS
|
|
# la bonne reponse (`A 10.0.35.11`) et un message negatif pour le meme nom — c'est le
|
|
# message qui etait servi. Il a fallu lire le cache pour le voir.
|
|
#
|
|
# MESURE QUI TRANCHE (trois essais, cache vide puis une requete empoisonnante) :
|
|
# harden-below-nxdomain: no seul -> repond 10.0.35.11
|
|
# aggressive-nsec: no seul -> ne repond pas
|
|
# Le second avait ete essaye d'abord et avait semble marcher : le REDEMARRAGE qu'il
|
|
# imposait vidait le cache. C'est le vidage qui soignait, pas le reglage.
|
|
#
|
|
# Ce qu'on perd : une protection anti-usurpation qui suppose que la racine dit vrai
|
|
# sur nos noms. Elle ne le peut pas — nos zones ne sont pas dans la racine. Ce qu'on
|
|
# garde : la validation DNSSEC complete de tout ce qui, lui, y est delegue.
|
|
harden-below-nxdomain: no
|
|
# La zone souveraine n'est pas signée : on ne la soumet pas à la validation DNSSEC.
|
|
domain-insecure: "{{ serveur_resolveur_zone_interne }}"
|
|
# LA RACINE NIE NOTRE TLD, ET UNBOUND ÉTEND CE NON À TOUT CE QUI EST DESSOUS
|
|
# (mesuré le 2026-09-01).
|
|
#
|
|
# `internal.` n'existe pas dans la racine, qui rend donc un NXDOMAIN **signé** —
|
|
# `dig internal. SOA` le montre avec le drapeau `ad`. `harden-below-nxdomain`
|
|
# (actif par défaut) tient ce non pour prouvé et fabrique lui-même un NXDOMAIN pour
|
|
# tout nom sous `internal.`, SANS JAMAIS interroger la `stub-zone` déclarée plus
|
|
# bas. La délégation était correcte, l'autoritatif répondait juste, et pas une seule
|
|
# requête ne lui parvenait.
|
|
#
|
|
# CE QUE ÇA COÛTAIT : aucun locataire ne pouvait nommer un service du site. Chacun
|
|
# gravait donc des ADRESSES dans sa configuration — le cache, le résolveur, la
|
|
# forge — et le site devenait indéplaçable un intrant à la fois. Le défaut ne s'est
|
|
# pas vu parce que les machines du site, elles, ont le plancher `/etc/hosts` : le
|
|
# nom marchait partout où on le testait, et nulle part où on en avait besoin.
|
|
#
|
|
# `transparent` sur NOTRE zone seulement : la question reprend son cours normal —
|
|
# donc atteint la `stub-zone` — sans rien changer pour le reste de l'Internet.
|
|
# Même remède que pour les zones inverses ci-dessous, même cause : un « non »
|
|
# d'Unbound qu'on ne distingue pas d'une absence.
|
|
local-zone: "{{ serveur_resolveur_zone_interne }}." transparent
|
|
{% for zone_inverse in serveur_resolveur_zones_inverses | default([]) %}
|
|
# Les zones inverses ne le sont pas davantage — et `in-addr.arpa`, LUI, est signé
|
|
# publiquement. Sans cette ligne, la validation chercherait une chaîne de confiance
|
|
# vers une délégation qui n'existe pas, et tous les PTR rendraient SERVFAIL.
|
|
domain-insecure: "{{ zone_inverse }}"
|
|
# UNBOUND BLOQUE L'INVERSE PRIVÉ PAR DÉFAUT (2026-08-25).
|
|
#
|
|
# Il embarque des `local-zone` pour tout l'espace RFC1918 inversé, et y répond
|
|
# lui-même. Avec la `stub-zone` pourtant bien déclarée, `dig -x` rendait NXDOMAIN
|
|
# avec le drapeau `aa` — une réponse AUTORITAIRE d'Unbound, qui n'avait jamais
|
|
# interrogé l'autoritatif. Le même NXDOMAIN qu'un nom qui n'existe pas : rien ne
|
|
# distinguait le blocage de l'absence.
|
|
#
|
|
# `transparent` laisse la requête suivre son cours — donc atteindre la `stub-zone`
|
|
# ci-dessous — pour CETTE zone seulement.
|
|
#
|
|
# Pas `nodefault` : ce mode ne retire un blocage que si le nom correspond EXACTEMENT
|
|
# à une zone par défaut d'Unbound. La sienne est `10.in-addr.arpa`, le /8 entier ; nos
|
|
# `/24` n'y correspondent pas, et la ligne restait sans effet — mesuré, le NXDOMAIN
|
|
# autoritaire persistait après rechargement.
|
|
#
|
|
# Pas `unblock-lan-zones: yes` non plus : il aurait débloqué tout l'espace privé
|
|
# inversé, y compris ce que cet écosystème ne sert pas.
|
|
local-zone: "{{ zone_inverse }}" transparent
|
|
{% endfor %}
|
|
# UNBOUND REFUSE D'INTERROGER UNE LOOPBACK PAR DÉFAUT (2026-08-24).
|
|
#
|
|
# `do-not-query-localhost` vaut `yes` d'origine — une protection contre les boucles.
|
|
# Or l'autoritatif de l'écosystème vit désormais SUR 127.0.0.1:5300, derrière ce
|
|
# résolveur. Sans cette ligne, toute la zone souveraine rend SERVFAIL.
|
|
#
|
|
# Et la panne était MASQUÉE : le plancher /etc/hosts répondait pour les noms de la
|
|
# flotte, si bien qu'un `getent hosts forge.genese.internal` semblait prouver que la
|
|
# résolution marchait. Seul un `dig` explicite l'a montrée.
|
|
do-not-query-localhost: no
|
|
{% for d in serveur_resolveur_zones_deleguees | default([]) %}
|
|
# LA ZONE D'UN AUTRE — CELLE DE L'HÉBERGEUR (2026-09-02).
|
|
#
|
|
# Un locataire dépend de services du SITE par leur NOM : son cache d'artefacts, sa
|
|
# forge, son dépôt de sauvegarde, son autorité. Ces noms vivent dans une zone que ce
|
|
# résolveur ne sert pas et n'a pas à servir — il doit savoir À QUI les demander.
|
|
#
|
|
# CE QUE SON ABSENCE A COÛTÉ : tant que les machines du locataire pointaient
|
|
# directement sur le résolveur du site, ça marchait — par accident. Reconstruites
|
|
# proprement, elles utilisent LEUR résolveur, qui ignorait la zone de l'hébergeur :
|
|
# la recette de validation a échoué sur la RESTITUTION d'une sauvegarde, avec
|
|
# « Could not resolve hostname sauvegarde.genese.internal ». La sauvegarde était
|
|
# intacte ; c'est le chemin pour la nommer qui manquait.
|
|
#
|
|
# Mêmes deux lignes que pour notre propre zone, même cause : la racine rend un
|
|
# NXDOMAIN signé pour le TLD, et `harden-below-nxdomain` l'étendrait à toute la zone
|
|
# sans jamais interroger le transitaire déclaré plus bas.
|
|
domain-insecure: "{{ d.nom }}"
|
|
local-zone: "{{ d.nom }}." transparent
|
|
{% endfor %}
|
|
|
|
stub-zone:
|
|
name: "{{ serveur_resolveur_zone_interne }}"
|
|
stub-addr: {{ serveur_resolveur_autoritatif }}@{{ serveur_resolveur_autoritatif_port }}
|
|
{# LES ZONES INVERSES SE DELEGUENT COMME LA DIRECTE (2026-08-25). Sans ces stubs,
|
|
l'autoritatif servait les PTR et personne ne les lui demandait : `dig -x` rendait vide
|
|
depuis les cinq machines, alors que la meme requete posee directement a l'autoritatif
|
|
repondait juste. Un service correct derriere un chemin que rien n'emprunte. #}
|
|
{% for zone_inverse in serveur_resolveur_zones_inverses | default([]) %}
|
|
|
|
stub-zone:
|
|
name: "{{ zone_inverse }}"
|
|
stub-addr: {{ serveur_resolveur_autoritatif }}@{{ serveur_resolveur_autoritatif_port }}
|
|
{% endfor %}
|
|
{% for d in serveur_resolveur_zones_deleguees | default([]) %}
|
|
|
|
{# `forward-zone` ET NON `stub-zone` : on s'adresse au RÉSOLVEUR de l'hébergeur, qui
|
|
recursera pour nous, et non à son autoritatif — que rien ne nous autorise à joindre
|
|
et dont l'adresse ne nous regarde pas. Le locataire connaît une seule adresse du
|
|
site en matière de noms : celle par laquelle il a été amorcé. #}
|
|
forward-zone:
|
|
name: "{{ d.nom }}"
|
|
{% for a in d.adresses %}
|
|
forward-addr: {{ a }}
|
|
{% endfor %}
|
|
{% endfor %}
|
|
{% if serveur_resolveur_transitaires %}
|
|
|
|
forward-zone:
|
|
name: "."
|
|
{% for f in serveur_resolveur_transitaires %}
|
|
forward-addr: {{ f }}
|
|
{% endfor %}
|
|
{% endif %}
|