feat(dns_rec) : le résolveur descend en conteneur, la traversée VRF disparaît #35
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/dns-rec-container"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Étape 5 du plan conteneurs, et la dernière qui retire un mécanisme au lieu d'en déplacer un.
La traversée
xvrf-dn42/xvrf-glbexistait parce qu'un processus ne peut pas être dans deux tables de routage : la VRF pour joindre les serveurs de délégation DN42, la globale pour joindre internet. Un conteneur a nativement les deux pattes —eth0surbr-svc,eth1sur le pont NATé.Ce qui disparaît
unbound-dn42sousip vrf exec+unbound-global10.42.255.0/31, hors DN42input(lignes 9a et 9b)resolver_crossingdansas.ymldn42.de l'autreLa dernière ligne est un gain : le nœud ne recevait pas le bit
adsur les réponses DN42 et « faisait confiance au veth ».⚠ Le point qui commandait ce chantier, et il était silencieux
« DN42 au sens large n'obtient pas le clearnet » était appliqué par le routage, pas par Unbound. La configuration donnait
allowà tout DN42 ; un pair extérieur qui demandaitgoogle.coméchouait seulement parce que la récursion ne pouvait pas sortir de la VRF.Un conteneur atteint internet. Reconduire la configuration telle quelle en aurait fait un résolveur ouvert pour tout DN42, sur une adresse anycast que le réseau entier connaît — et rien ne l'aurait signalé, le service se mettant seulement à mieux répondre.
D'où la vue
dn42-only:local-zone "." refuseplus untransparentpar zone DN42, les deux tirés de la même liste que lesstub-zone.Le test négatif passe sur les quatre, depuis
fd42:d0d0:1::1posée sur lelodu conteneur (jamais annoncée — le filtre d'export de Bird ne laisse passer que la VIP) :C'est un geste et non un contrôle du rôle :
unbound-checkconfaccepte la version ouverte comme la fermée, et un contrôle qui interrogerait depuis la boucle locale tomberait dans l'ACL du nœud — il aurait l'air d'en être un.⚠ Le seul mécanisme ajouté, contre cinq retirés
L'adresse
eth1du conteneur est épinglée à10.42.0.53. Un résolveur est le seul service dont son propre hôte est client, et un processus en table globale ne joint aucun conteneur par DN42 — pas même celui de sa machine. La même adresse sur les quatre nœuds, chacun ayant son propreincusbr0dans le même /24 : locale par construction, ce que la traversée garantissait aussi.Le
DNS=du nœud est une unité systemd et non un fichier, et les deux impasses sont mesurées :resolved.confn'a qu'une listeDNS=globale — y mettre le résolveur lui confierait aussithystips.xyzet rendrait publique une zone privée ;.networkdemanderait que networkd gèreincusbr0, que Incus possède (unmanaged, vérifié) — c'est la panne quenetwork_anycast_ownersdocumente déjà.Ce que le déroulé a appris (second commit)
_→ le conteneur s'appelleresolver, d'après son service anycast. Validation ajoutée au plugin.Connect.networkctl reloadne supprime pas une interface dont le.netdeva disparu. Le veth survivait à son propre démontage, avec ses adresses, hors de tout fichier. C'est le contrôle du playbook qui l'a dit.cloudn'a aucun client DNS → le test négatif documenté n'était pas exécutable.Et une mesure écrite plutôt que corrigée : un Unbound qui démarre SERVFAIL sur le clearnet 4 à 6 s, DN42 répondant normalement. La VIP est annoncée pendant cette fenêtre.
Deux défauts de
render-check, trouvés en rendantTous deux des contrôles qui ne contrôlaient pas :
{{ … }}littéral atterrissait dans unExecStartque systemd aurait refusé, lint au vert ;access-control: {{ dn42_prefix_v4 }} allow, soit la ligne même qui décide qui peut résoudre le clearnet à travers nous.Le reste
Le gabarit Bird du conteneur est factorisé dans
ansible/templates/, paramétré par le service anycast — deux copies de 140 lignes portant cinq défauts mesurés en production auraient divergé. Il ne nomme aucune variable de rôle, leçon degai.conf.j2.La boucle
inputsurdn42_anycastne parcourt plus que ce que le nœud sert lui-même : un paquet vers la VIP d'un conteneur est forwardé et ne touche jamais cette chaîne. Les règles d'ingressy étaient mortes depuis la PR #25.Et le pare-feu du résolveur n'a demandé aucune ligne écrite : déclarer
anycast: resolvera suffi à rendre les quatre règles deforwardet la session iBGP. C'est ce que « les ports viennent du service » achète, et ça ne se voit qu'au second service.Déploiement
Les 4 nœuds et les 4 nouveaux conteneurs, un nœud à la fois. Sur chacun : plus de
xvrf, plus de marque 3, Unbound inactif sur l'hôte, VIP absente delo-dn42, route de la VIP viacnt_resolver, sonde anycast répondant avec le bon NSID en v4 et v6,whois.dn42résolu par le conteneur,thystips.xyztoujours par le plan privé. NetBox synchronisé,--checkà zéro.⚠ Reste un geste, à décider : 8 assignations périmées de la VIP sur les
lo-dn42des nœuds. Six passent le garde-fou (taginfra-dn42seul), mais les ids 421 et 422 portent undns_nameque le modèle ne pose jamais — donc annotés par quelqu'un d'autre. Non supprimées.Étape 5 du plan conteneurs, et la dernière qui RETIRE un mécanisme au lieu d'en déplacer un. La traversée `xvrf-dn42`/`xvrf-glb` existait parce qu'un processus ne peut pas être dans deux tables de routage : la VRF pour joindre les serveurs de délégation DN42, la globale pour joindre internet. Un conteneur a nativement les deux pattes. Ce qui part avec elle : la SECONDE instance Unbound, la paire veth, la marque netfilter 3, deux règles d'`input` (lignes 9a et 9b de la matrice), et `resolver_crossing` dans as.yml. ⚠ LE POINT QUI COMMANDE CE CHANTIER, et il est silencieux. « DN42 au sens large n'obtient pas le clearnet » était appliqué par le ROUTAGE et non par Unbound : la configuration donnait `allow` à tout DN42, et un pair extérieur échouait seulement parce que la récursion ne pouvait pas sortir de la VRF. Un conteneur, lui, atteint internet — reconduire la configuration telle quelle en aurait fait un RÉSOLVEUR OUVERT sur une adresse anycast que le réseau entier connaît, sans que rien ne le signale : le service se serait mis à MIEUX répondre. D'où la vue `dn42-only` : `local-zone "." refuse` plus un `transparent` par zone DN42, les deux tirés de la même liste que les `stub-zone`. Le test négatif est un GESTE, écrit dans le README — `unbound-checkconf` accepte la version ouverte comme la fermée, et un contrôle qui interrogerait depuis la boucle locale aurait l'air d'en être un. ⚠ LE SEUL MÉCANISME AJOUTÉ, contre cinq retirés : l'adresse `eth1` du conteneur est épinglée à 10.42.0.53. Un résolveur est le seul service dont son propre hôte est client, et un processus en table globale ne joint aucun conteneur par DN42, pas même celui de sa machine. La même adresse sur les quatre nœuds — chacun a son propre `incusbr0` dans le même /24 — donc LOCALE PAR CONSTRUCTION, ce que la traversée garantissait aussi. Le `DNS=` du nœud est une unité systemd et non un fichier, et les deux impasses sont mesurées : `resolved.conf` n'a qu'une liste GLOBALE (y mettre le résolveur lui confierait `thystips.xyz` et rendrait publique une zone privée), et un `.network` demanderait que networkd gère `incusbr0`, que Incus possède — `unmanaged`, vérifié. DEUX DÉFAUTS DE render-check TROUVÉS EN RENDANT, tous deux des contrôles qui ne contrôlaient pas : - les defaults du rôle RENDU n'étaient pas résolus, donc un `{{ … }}` atterrissait littéralement dans le fichier vérifié. Trouvé sur un `ExecStart` que systemd aurait refusé, et que le lint validait ; - les ÉLÉMENTS d'une liste ne l'étaient pas non plus — `access-control: {{ dn42_prefix_v4 }} allow`, soit la ligne même qui décide qui peut résoudre le clearnet à travers nous. Le gabarit Bird du conteneur est factorisé dans `ansible/templates/`, paramétré par le service anycast : deux copies de 140 lignes portant cinq défauts mesurés en production auraient fini par diverger. Il ne nomme aucune variable de rôle, leçon de `gai.conf.j2`. Et la boucle `input` sur `dn42_anycast` ne parcourt plus que ce que le nœud sert LUI-MÊME : un paquet vers la VIP d'un conteneur est forwardé et ne touche jamais cette chaîne. Les règles d'`ingress` y étaient mortes depuis la PR #25. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FGwvXLVXJ2PrRFwJTB3Xp9