Proxmox refuse un corps sur DELETE (501) : aucun IPSet n etait jamais retire
par l applicateur. SDN, frontiere et pare-feu Proxmox ne portent plus rien de
l index 29 ; le journal dit comment, et ce qui reste (strophe FRR).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Les IPSets et groupes t29- restaient poses : le perimetre ne retenait que
les prefixes des tenants presents. Les etiquettes des zones retirees
(ANCIEN_NOMMAGE du SDN) y entrent, pour etre retirees. Et un cluster muet
arrete le plan au lieu de se lire vide.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Les deux devis balayaient tous les dossiers freres. Le runner du site, qui
gardait un clone de patient 0, proposait de recreer ses groupes t29 ; le poste
comptait un dossier de CI comme tenant. La frontiere et le SDN filtraient deja
par underlay.tenants : ces deux-la suivent maintenant la meme liste.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ses machines n existaient plus depuis le 2026-09-06 (D-83), mais son plan
restait sur disque : la federation lui reservait l index 29 et quatre machines
du site lui ouvraient SSH, apt, DNS et HTTPS. Les commentaires et documents
vivants gardent leur lecon sans le nommer ; les archives restent telles quelles.
Pas encore sur le reseau : les regles regenerees attendent le runner du site.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Un outil tiers veut n'offrir de ce moteur que ce qui n'agit pas. Le seul champ
qui le lui dise est `nature`. Il fallait donc qu'il ne mente pas, et il mentait
dans les deux sens.
`filiation` → `emancipation-prouver` se declarait « mesure » en portant
`fixes: {CONFIRMER: "true"}`. La cible tranche elle-meme — son refus dit
« cette preuve COUPE l'amont quelques secondes pour mesurer ». Un constat
rapporte ne rend pas inerte le geste qui l'obtient : l'etape passe a
`ecriture`.
Dans l'autre sens, trois cibles — flotte-creer, deployer-tout, reconstruire —
refusent sans confirmation sans que le registre le declare : un assistant les
lancait telles quelles, et sortait en 2. Comparer `nature` a `fixes` ne les
voyait pas, car c'est comparer deux champs ecrits par la meme main. `verifier`
lit desormais la RECETTE, qui ne ment pas.
Effet de bord traite : une etape qui agit barre celles qui la suivent dans la
console, alors qu'une « mesure » se debloque d'office. `depots-perimes` est
marque `facultative` — il nettoie ce que la filiation a laisse, il n'en est pas
le prealable.
`lister --json` rend le registre assemble d'un bloc, et le drapeau est refuse
hors de son action : rendre la prose humaine a qui demande du JSON est pire
qu'un refus. L'affichage humain ne bouge pas, et la preuve mesure ce qu'il
PORTE — un identifiant, un libelle, les marques de nature — et non seulement
qu'il n'est pas du JSON.
Valide : `verifier` a 0 ecart, test_runbooks.py 25/25, et sept des neuf
epreuves de `make test` ; test_raser et test_raser_resultat echouent sur
« Aucune instance montee », avant comme apres. Mesure : 127 etapes, dont 84 de
nature « mesure » — la surface qui n'agit pas.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RbXr5vv4Rat6PCPGG9GoG8
L'exploitant a demande si l'adressage derive ne valait pas pour toute flotte, site compris.
Oui — decision du 12 septembre, index 37 pour le site. J'avais affirme le contraire a
l'entree (11) du CHANGELOG, en recopiant un commentaire perime de huit jours au lieu de
mesurer. Un commentaire perime se propage : celui-la s'etait aussi loge dans la docstring de
ConsoleSite.
P20 s'appelle « Adressage 100% derive du seed (aucun stocke) » et sa portee etait
« l'instance liee + les modeles » : elle ne regardait jamais le site, qui stockait
sous_reseau et passerelle pour ses sept zones. Elle juge desormais les deux natures d'un
underlay et refuse une entree qui ne declare pas la sienne — on ne peut pas juger ce qu'on
ne sait pas lire. Controle negatif joue : une zone remise a 10.36.31.0/24 est refusee, en
nommant l'index dont elle aurait du descendre.
Le loader derive sous_reseau et passerelle a la lecture, pour que rien ne change chez les
consommateurs. Mesure : 14 valeurs retirees du fichier, zero ecart sur ce qu'ils lisent, et
make underlay, devis-sdn et devis-reseau passent.
Valide : make test a 0 echec, P20 verte sur 2 nomenclatures et 7 zones de site. P02 et P60
restent, pour les raisons deja consignees.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Il y avait deux assembleurs de charge, un par sorte de console. Ils ont derive deux fois le
meme jour : en forme (serveurs valait [] d'un cote et {} de l'autre, et charger() levait),
puis en contenu (cinq registres servis vides alors que le site a SON plan — 9 serveurs,
21 applications, 2 bases, 1 domaine, tous invisibles).
Console assemble, une seule fois, et fixe les clefs et leurs formes. Les branches ne
decident que de ce qui leur appartient : d'ou vient le plan, d'ou vient l'inventaire, quels
pouvoirs elles portent. ConsoleLocataire configure, ConsoleSite materialise et sert
desormais son propre plan, ConsolePoste herite du locataire et sait en plus sur quelle
fabric poser.
Le role et la portee ne se confondent pas : le role est une propriete de la classe, la
portee se calcule depuis les pouvoirs. Un poste prive de la voute du site reste l'atelier du
mainteneur et n'engendre pourtant rien. Le decoupage a montre un trou aussitot : ConsolePoste
heritait du refus d'un locataire — « elle ne sait pas sur quelle fabric poser » — alors qu'il
monte la carte ; ce qui lui manque est la voute, et accuser la mauvaise absence fait chercher
au mauvais endroit.
Le jugement des assistants remonte dans le tronc : il etait ecrit dans la route qui liste ET
dans celle qui execute, et celle qui se trompe est toujours celle qui execute.
Valide : make test a 0 echec, 8 tests de rendu sous node dont deux neufs, console lancee pour
de vrai (13 serveurs, 24 applications, 17 runbooks, 127 etapes, 0 ecart). make verifier a
aussi attrape une faute que j'avais laissee passer sur depots_perimes.yml — risky-shell-pipe,
corrige. P02 et P60 restent, et P60 demande une republication du wiki.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
La console du runner de SITE-Chezlepro ne montrait rien. Elle a douze machines.
inventaire_api sert serveurs en LISTE, inventaire_api_du_site le servait en TABLE. Les deux
sont vides et la page ne les lit pas pareil : (data.serveurs || []).map trouve {} — truthy,
sans .map — et charger() leve. La console d'un site mourait avant sa premiere vue, et le
message accusait une methode manquante plutot qu'une forme qui ment.
Et la vue regardait au mauvais endroit : le registre vide est voulu, mais la page en tirait
le message d'un locataire sans serveurs et les douze machines servies dans hotes n'etaient
dessinees nulle part. Une console de site dessine desormais SES machines, en lecture seule,
avec leur adresse, leur VMID, leurs roles et leur point de vie ; le panneau droit dit ce
qu'elle peut et renvoie aux Assistants.
C'est le defaut du 16 septembre par une autre porte : la premiere fois l'inventaire etait
vide et la page dessinait ce vide comme un plan vide ; cette fois il est plein et c'est la
vue qui regarde ailleurs.
Ce qui a trouve la cause n'est pas une lecture mais le BANC : en donnant pour la premiere
fois a test_rendu_gui la charge d'une console de site, il a leve sur charger(). Sans lui
j'aurais livre une vue juste par dessus un charger() qui leve.
Valide : node --check sur le bloc script, 7 tests de rendu dont deux neufs, make test a 0
echec, runbooks.py verifier a 0 ecart, P81 et P83 vertes. P02 reste en echec pour la raison
anterieure.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
serveur_ops clone ce que le plan declare et ne retire rien : le runner de
Chezlepro-locataire portait encore le clone de SITE-Chezlepro, la carte de son hebergeur,
longtemps apres que son plan ait cesse de la declarer.
Le retrait n'entre pas dans le role. Un role qui efface des dossiers a chaque passage est
une grenade degoupillee : une faute de frappe dans serveur_ops_depots suffirait a perdre du
travail local. C'est donc un geste separe, qui regarde par defaut et n'efface que sur
CONFIRMER=true. Trois choses ne sont jamais retirees, meme confirmees : ce qui n'est pas un
depot git, ce qui porte des modifications non validees, ce qui porte des commits qu'aucun
distant ne porte.
La garde a servi au premier essai : le releve a nomme SITE-Chezlepro et venv, et venv a ete
ecarte parce que ce n'est pas un depot git. Une version naive aurait efface l'environnement
Python du runner en se disant satisfaite.
Passe deux fois sur le runner reel : regarder (changed=0), puis confirmer (changed=1) avec
relecture. Le runner ne porte plus que Set-OPS-public et OPS-Chezlepro ; sa console rend
portee=tenant, materialiser=False, fabric=False — le pouvoir de LIRE la fabric est tombe
avec la carte, et c'est juste.
Valide : syntax-check du playbook, runbooks.py verifier a 0 ecart (la cible neuve est portee
par le runbook Filiation), make test a 0 echec. P02 reste en echec pour la raison anterieure.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le document des responsabilites attache chaque pouvoir a une voute : calculer n'en demande
aucune, configurer demande celle du tenant, materialiser celle du site. Le code lisait les
symlinks, c'est-a-dire les cartes. Le runner de Chezlepro-locataire montait la carte du
site sans en avoir jamais eu la voute : sa console se declarait poste et offrait 126 etapes
sur 126. Ces gestes seraient partis puis tombes sur un secret vide — un echec au milieu du
chemin, la ou un refus net aurait dit la verite avant de commencer.
contexte() derive desormais les pouvoirs des voutes presentes, et la portee decoule des
pouvoirs au lieu de les preceder. On ne prouve pas qu'une voute s'ouvre, le mot de passe se
tape a l'execution ; mais son absence est decisive et se mesure sans rien ouvrir. Lire une
carte reste permis : le pouvoir fabric suit toujours le symlink, consulter un miroir n'est
pas engendrer.
serveur_ops retire aussi le lien quand la fabric n'est plus declaree — il ne retirait rien,
et un runner gardait le pouvoir que son plan ne lui donnait plus. Il ne retire qu'un lien,
jamais un fichier : une vraie carte a cette place n'a pas ete ecrite par ce role, et il le
dit plutot que de detruire ce qui n'est pas le sien.
Valide : syntax-check et ansible-lint sur le role (profil production, 0/0), make test a 0
echec, P81 et P83 vertes. Six tests montent quatre faux disques et exigent la portee qui
leur revient, dont le defaut lui-meme : carte presente, voute absente, portee tenant.
Limite : P02 reste en echec pour la raison anterieure deja consignee.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mesure sur la console de TechnoLibre, portee tenant : 6 runbooks conduisibles sur 17, et
parmi les onze fermes, locataire-deployer et machine-une — c'est-a-dire le travail
quotidien d'un locataire. La cause : flotte-creer et creer-vm engendrent des VM et
exigent la fabric, et une portee declaree pour toute la sequence faisait basculer avec eux
des etapes voisines qui ne demandent que ce que le locataire possede deja.
Le runbook ne donne plus que le defaut ; l'etape qui exige davantage le declare. Le
locataire conduit sa sequence et bute precisement la ou il faut : sur la machine a
engendrer, pas sur le deploiement qui suit. La page ferme l'etape seule avec sa raison, et
la garde de la route lit la portee de l'etape visee par son index.
Un droit calcule sur l'ensemble se trompe toujours dans le meme sens : il refuse a
quelqu'un ce qu'il a le droit de faire, et le refus parait fonde puisqu'il nomme un vrai
manque. Il a fallu une console de locataire reelle pour le voir — sur le poste, qui porte
les deux liens, les dix-sept sequences s'affichaient conduisibles.
Valide : runbooks.py verifier a 0 ecart, make test a 0 echec (4 tests neufs, dont un qui
nomme le cas exact), P83 verte. P02 reste en echec pour la raison anterieure deja consignee.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
La console offrait des boutons sans sequence. Rien n'y apprenait que site-creer precede
forge-amorcer, que le premier passage de site-deployer-tout s'arrete sur une forge vide
sans que ce soit un echec, ni que rien n'est pret avant valider : cet ordre vivait en
prose dans des documents que la console ne porte pas.
La vue Assistants conduit 17 runbooks et 126 etapes. Les 132 cibles documentees y sont,
chacune portee par un assistant ou exemptee avec son motif — une exemption muette est
refusee. Le registre ne recopie pas le Makefile : il declare l'ordre, la nature, la portee
et le pourquoi, et le libelle de chaque etape est lu dans le Makefile au moment de servir.
P83 est ecrite en meme temps que la liste, pas apres, parce qu'une liste qui suit une
autre prend du retard. Onze tests lui presentent des registres faux, un par forme de
retard, et exigent qu'elle les refuse.
Le navigateur ne nomme pas une commande, il nomme une place : la route lance ce que le
registre declare a cet index-la, avec les seules variables declarees. L'index compte, le
premier jour d'un site jouant site-deployer-tout deux fois. Une etape qui ecrit attend que
la precedente ait reussi ; une mesure reste toujours offerte, parce que mesurer apres un
echec est exactement ce qu'on fait ensuite.
Valide : runbooks.py verifier a 0 ecart, make test a 0 echec, les 83 preuves rejouees, et
la console lancee pour de vrai — 17 runbooks servis, six requetes malformees refusees une
a une, une etape de mesure executee de bout en bout avec son journal.
Limite, anterieure a ce travail : P02 (test_ecriture_plan) echoue sur domaines.yml, a
l'identique sur une copie de HEAD. Ajouter ou retirer un domaine public depuis la vue
Domaines leverait a l'enregistrement. Non corrige ici.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Premiere execution du correctif de genome_pousser.yml, et premier declenchement :
f9a20b0 -> f958739 sur la forge, tache en changed, console du site repartie a 15h46m27
contre 15h16m45, sonde a 0. Les cinq autres depots, reconnus immobiles, n'ont rien
redemarre — la condition ne reagit qu'au moteur. make genome-etat rend failed=0 sur les six.
Les trois correctifs de la journee ont maintenant ete vus fonctionner sur la machine que
chacun concerne : le role chez les deux locataires, le playbook de poussee chez l'hebergeur.
Cette entree ne corrige qu'un paragraphe devenu faux.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le correctif de serveur_ops a eu sa preuve en conditions reelles : clone passe de 6367d85
a f9a20b0 chez les deux locataires, tache en changed, consoles reparties a 15h33m33 et
15h38m02 contre 15h16, sondes a 0. En la donnant, il a montre le cas qu'il ne couvre pas.
genome_pousser.yml fait avancer le clone du runner du SITE sans qu'aucun role ne passe :
c'est lui qui pousse, donc il recoit d'abord. Quand serveur_ops passera, le clone sera
deja a jour et la tache s'abstiendra a juste titre — l'hebergeur gardait le defaut corrige
chez ses locataires. Le playbook nomme deja la transition dans son verdict ; il en tire
maintenant la consequence et redemarre la console du site quand c'est le MOTEUR qui a
bouge. Un plan pousse ne coupe pas les pages ouvertes, et l'unite systemd est verifiee
avant de toucher au service.
Valide : --syntax-check contre l'inventaire du site et celui d'un locataire, ansible-lint
sur le playbook (profil production, 0 echec, 0 avertissement), condition de declenchement
eprouvee sur quatre cas dont le mode check.
Limite : le redemarrage de la console du site demande une poussee posterieure a ce commit,
il n'est donc pas encore observe. Son disque porte f9a20b0, sa console sert le code
charge a 15h16.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Les trois consoles portaient le moteur du jour et servaient celui du 16 septembre. Le
clone du genome ne notifiait rien et la tache de service demande state: started, qui ne
fait rien quand le service tourne deja ; inventory_gui.py lit son code au demarrage, et
seulement la. Le role retient desormais si le MOTEUR a avance — designe par
serveur_ops_depot_moteur, jamais un chemin recopie — et redemarre la console dans ce seul
cas : un plan qui avance ne coupe pas les pages ouvertes.
La sonde console-ops criait au vestibule ouvert sur les deux runners de locataire, sur
des consoles fermees. Elle frappait la boucle locale, seul endroit d'ou un 200 est le
resultat attendu en mode oidc, ou nginx est reduit a 127.0.0.1 pour qu'on ne contourne
pas la passerelle SSO. Elle connait maintenant son mode : en locale le verdict ne bouge
pas, en oidc la serrure mesuree est l'adresse d'ecoute. Le refus de la passerelle reste
l'affaire de la sonde passerelle de serveur_oauth2_proxy, sur le meme hote.
Valide : --syntax-check sur playbooks/groupes/serveur_ops.yml, ansible-lint sur le role
(profil production, 0 echec, 0 avertissement, 14 fichiers), le gabarit rendu dans ses deux
modes sans reste Jinja et bash -n propre, le filtre d'ecoute eprouve sur cinq formes
d'adresses, l'expression du when sur cinq cas dont le mode check. Le role est applique aux
trois runners, failed=0, et la sonde rejouee sur chacun rend 0.
Limite : le redemarrage automatique ne s'est pas declenche, les clones etant deja au
niveau de la forge — la tache s'est correctement abstenue. La preuve du declenchement
viendra au prochain genome pousse.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
promo/histoire.html raconte huit etapes du 24 juin au 17 septembre a partir des commits
accessibles depuis 05b85eb, avec l'archive recherchable des titres originaux et un
graphique d'activite tire du meme corpus. Le corpus est fige : les chiffres decrivent cet
instantane, pas l'etat courant du depot. Page autonome, sans police ni service distant,
lisible sans JavaScript ; ses styles sont isoles sous .history pour ne pas toucher les
quatre pages commerciales. La page Capacites y renvoie.
Le CHANGELOG consigne aussi la revision des dossiers de livraison et le comparatif SOC 2,
qui vivent hors de ce depot : aucun role, playbook ni reglage n'est modifie ici.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`pair-nouveau --locataire` refusait de proposer une adresse a un ecosysteme sans aucun pair,
soit exactement le premier. Le kit remis au client derive tout ce qu'il affiche.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
plan/acces.yml chez le locataire (cles publiques), reseau/port/instance derives de l'index.
La garde du devis refuse qu'un tunnel de locataire vise autre chose que son supernet : sans
elle, un ecosysteme s'ouvrirait un acces chez un voisin depuis son propre plan.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eprouve en production : les locataires repondaient, le site non — son SSH vient de `flotte`
et vivait du rebond par la frontiere. Et rien ne designait la frontiere elle-meme, si bien
que monter le tunnel faisait perdre le moyen de le corriger. Une regle par port : OPNsense
refuse deux ports dans un champ.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le runner detient la voute et les cles SSH : en faire la porte des humains reunirait deux
pouvoirs que le depot separe. Instance `admins` a cote du tunnel site-a-site, un pair par
personne et par appareil, cles publiques seules au plan. Le reseau du tunnel est un reseau
d'administration : pare-feux d'hote, contrat des locataires et regles de bordure en derivent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
os-node_exporter sur la patte de supervision, declare dans la carte du boitier : cible et
hote Icinga en derivent. Les flux vers la frontiere ne s'ouvrent plus a tous pour un role
qui n'est pas le socle.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Les hyperviseurs exposaient temperatures, ventilateurs, SMART et usure NVMe sans que rien
les regarde. scripts/materiel.py porte capteurs et seuils ; Grafana en tire le tableau
Materiel, Icinga un service materiel par hyperviseur. Premier verdict : le disque sda de
gandalf (OSD Ceph) a 56 secteurs en attente, stables.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Un flux externe porte port (la machine) et port_public (l'Internet). Le devis emet la
redirection et sa regle WAN, garde qu'elles aillent ensemble ; l'applicateur reconcilie
d_nat et encode les champs imbriques. DNS public : WAN:53 -> site-dnspub-01:1053 (dnsdist).
Plan lu : 4 objets a creer, rien d'autre ; pas encore applique.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ANY UDP tronque, AXFR/NOTIFY/UPDATE refuses depuis dehors, debit par /24 (rafale 300 ->
70 reponses, 230 tronquees). PowerDNS garde le 53 pour les primaires ; le frontal ecoute
1053, ou la frontiere redirigera. Sonde par le frontal.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Une zone publique ne portait que des A d'exposition ; basculer chezlepro.ca aurait coupe
son MX, son SPF et son DMARC. Les enregistrements se declarent au plan, valides et rendus ;
le serveur de noms porte le nom que le site declare (dns1.chezlepro.ca), parce que
ns1.chezlepro.ca existe deja en production. make dns-bascule-devis compare le plan au DNS
en service : 0 perdu sur les deux zones, deux prealables restants.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Applicateur de frontiere : ecrire n est pas charger, le chemin rien a faire charge
desormais. site-verifier compare enfin playbooks/site.yml, regenere avec le groupe.
Base TSIG dans un repertoire a pdns et pdnsutil en pdns (journal SQLite). Flux UDP 5300 :
le secondaire demande le SOA avant de transferer, garde dans P82. socket-dir de
pdns@public, et le failed_when qui taisait la notification est retire. Eprouve sur les
machines : 2 zones sur 2 tirees automatiquement, NOTIFY compte, zone interne refusee.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Role serveur_dns_public (secondaire public, transfert signe TSIG, aucune zone interne) ;
serveur_powerdns exerce enfin autorite primaire-cache dans une instance pdns@public a part,
pour que le site ne puisse jamais interroger la zone .internal. Relations derivees des plans
des locataires, mots de flux dns_public_site et primaires_dns_locataires. Eprouve avant
d ecrire : allow-axfr-ips et TSIG sont alternatifs, le primaire notifie aussi ses NS, le
serial fige aurait gele le secondaire. P82 refuse l exposition sans DNSSEC.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Un seul entonnoir pour les quatre gestes d hote (lancer), POUVOIR_PAR_MODE qui
rattache chaque mode a son pouvoir, et des boutons qui demeurent mais inertes,
avec leur raison en infobulle. Les panneaux de fabric sont marques lecture seule
chez un locataire : ils viennent d une copie locale qui avait deja diverge. P81
refuse en plus une page qui aurait perdu POUVOIR_PAR_MODE.
Deux fautes attrapees en route : le banc de rendu a vu un TypeError a l ouverture
(ma garde adoptait pour un contexte tout ce qu on lui donnait) la ou node --check
restait vert ; et une couleur illisible, vue sur une capture, pas dans le code.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Servie par le runner d un SITE, la console montrait zero serveur sans une erreur :
serveur_ops retire le lien instance sur un hebergeur, charger_yaml rend un
inventaire vide sur un fichier absent, et la page dessinait ce vide comme un plan
vide. La portee se DERIVE des deux symlinks (instance = je configure, underlay =
je materialise), jamais d un reglage declare. Une console de site sert desormais
son inventaire dynamique ; POUVOIR_REQUIS exige un pouvoir pour chaque route POST
et le refus dit pourquoi ; la page nomme la console. P81 refuse une portee sans
source d inventaire, un site sans machines, et toute route qui echapperait a la
table.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Qui peut, doit ; qui ne peut pas, ne peut pas etre tenu. Vingt lignes derivees des
trois portees du moteur (calculer, configurer, materialiser), chacune citant son
mecanisme. Deux coupures qui ne se devinaient pas : la verification des sauvegardes
suit la CLE (l hebergeur heberge des octets qu il ne peut pas ouvrir), et l acces de
secours par sudo est dit plutot que tu, avec sa date de fin. Le tableau est canonique
dans le depot ; les chartes remises le LISENT entre ses ancres.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Livrer se terminait par une phrase — tes cles te seront remises separement — et
rien n ecrivait la suite. Temps 1 l identite (sa cle de voute, sa voute, sa racine
d AC), temps 2 la machine a echeance (sa cle entre, la notre sort, voute re-cletee,
secrets tournes). scripts/remise.py refuse une destination interne, un paquet sans
racine d AC, et tout ce qui n est pas l ecosysteme monte. Le registre remise.yml
declare enfin le responsable designe (D-18). P80 refuse un registre incomplet, un
second temps echu, un second temps declare fait sans revocation au plan, et un
secret dans un fichier versionne.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sept replis des deux derniers jours, un temoin chacun, lu hors de la derivation
qu'il juge : jumeaux d'amorcage, patte de zone, edge d'exposition, certificat
bouchon, rechargement, sortie vers l'Internet, regles d'hote par instance.
Eprouvee par reinjection de chaque faute ; a trouve deux flux-genere perimes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
genese 401 (vestibule, pas d annuaire), chezlepro et technolibre 302 vers leur
Keycloak. Pile identique partout : le GUI et son vestibule en boucle locale,
seule la passerelle publiee.
La regle edge -> ops-01:4180 a manque deux fois pour la meme raison : make flux
ecrit pour l INSTANCE MONTEE, et je l ai lance avec Chezlepro monte. Chez un
locataire ce flux ne traverse pas la frontiere — le SDN de Proxmox tient les
passerelles de zone — donc c est le pare-feu d hote qui le porte. Au site,
c etait la frontiere.
Deux de mes mesures ont menti : un tls=1 qui venait d une AC de 0 octet (le ssh
qui devait la lire avait echoue sans que je regarde son code), et les cles
d hote de TechnoLibre changees a sa reconstruction — je n ai pas touche au
known_hosts de l exploitant.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Les deux locataires declarent leur console derriere oauth2-proxy. En oidc le
vestibule n ecoute que la boucle locale : le gabarit annoncait cette protection
en s en remettant au pare-feu, qui ouvrait le port depuis l edge — la console
etait joignable sans passer par la passerelle.
COLLISION REELLE : serveur_oauth2_proxy est mono-instance par machine, et la
table des noms publics etait indexee par GROUPE. La passerelle de la vigie se
croyait la console ; son URL de retour OIDC aurait vise l autre machine. Une
application nomme un COUPLE (machine, role). P67 ne le voyait pas parce qu elle
indexait comme la derivation qu elle garde — une garde qui reproduit le
raisonnement qu elle verifie ne verifie rien.
ET J AI ECRASE group_vars/serveur_ops.yml sans le regarder : 68 lignes
detruites, deux preuves tombees, et une explication fausse construite dessus. Le
git diff qui m avait rassure portait un glob developpe par le shell parent : il
n a rien matche et n a rien dit. Une commande qui ne trouve rien et une commande
qui trouve que rien n a change rendent le meme silence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
console.genese.internal : 401 sans justificatif, la console avec. Le site est le
premier ecosysteme a servir son GUI par un nom, en TLS verifie.
Le vestibule reste, et c est le contraire d une contradiction avec la veille :
Icinga Web 2 a une page de connexion, donc on lui a retire le sien ; le GUI de
Set-OPS sert sa page a qui la demande, jeton inclus, donc le vestibule EST sa
seule serrure. Verifie sur la machine : le GUI n ecoute que 127.0.0.1:8765, seul
le 8090 du vestibule est publie.
Controle dans les deux sens — une serrure ne se prouve qu en la forcant et en
l ouvrant. Et la sonde console-ops exige un REFUS sur une requete anonyme, parce
qu un 200 y serait la pire des reponses.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
serveur_icingaweb2 appelle resoudre_base deux fois — moteur puis comptes — et le
second appel ecrase les faits du premier. Les gabarits lisaient donc la seconde
base partout : la console cherchait icingadb_schema dans la base des comptes et
rendait une trace PHP a chaque page, pendant que les 66 tables du moteur etaient
intactes a cote. Celui qui appelle un role partage deux fois doit NOMMER ses
resultats avant de le rappeler.
Et le cadre de migration veut une instance de base quoi qu il arrive :
config_backend db + config_resource icingaweb_db. L erreur des preferences
n apparaissait qu A LA CONNEXION — un journal muet ne prouvait rien tant que
personne n avait ouvert de session, d ou un controle qui en ouvre une vraie.
J ai attribue a tort la fin des erreurs a un rechargement manuel : les horloges
disent que le handler du role avait deja redemarre php-fpm sept minutes plus
tot. Mes fenetres de mesure enjambaient le correctif.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
L exploitant : Icinga Web 2 permet nativement de gerer des comptes ; ce genre
d intervention n est pertinente que pour integrer Icinga a Keycloak chez les
tenants.
Le mode locale posait un auth_basic nginx devant le backend external. Ca
marchait, et ca reinventait une page de connexion devant une application qui en
a une — en privant l exploitant de la gestion des comptes dans l interface. Un
vestibule n a de sens que devant une application qui ne sait pas
s authentifier ; le GUI de Set-OPS est dans ce cas, Icinga Web 2 non.
Mode db : backend natif, groupes natifs, base a elle (les tables du moteur sont
reecrites par ses migrations). Le moteur pose UN compte d amorcage et ne
l ecrase jamais. D-66 redevient applicable sans annuaire, les groupes vivant en
base.
Deux pieges du renommage : une garde ecrite en negation a cesse de garder, et le
bloc de la base pose apres le rendu des .ini a produit un echec CENSURE par
no_log.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
expositions n etait resolu nulle part — ni par le pare-feu d hote, qui ne filtre
pas l egress, ni par le devis de frontiere. Il n avait jamais eu besoin de
l etre : chez un locataire le trafic edge vers amont ne traverse pas le boitier.
Au site il le traverse. Une declaration peut dormir des mois avant que la
premiere fabric ne la reveille.
Une regle par amont, avec son port. Jamais une regle large : ouvrir l edge sur
tout le site annulerait ce qu une zone de publication separee cherche a obtenir.
La meme faute qu hier, avalee de la meme facon : U au lieu de underlay_mod, et
un except Exception large a transforme le NameError en note plausible. Resserre
a OSError/ValueError — une faute de frappe doit faire du bruit.
Le schema de proxy_pass suit maintenant le port, et l amont TLS est VERIFIE
contre l AC interne : relayer en TLS sans verifier ne fait que deplacer la
confiance.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Le certificat bouchon de Debian sur les trois noms. serveur_nginx l a pour
defaut, avec un commentaire d avant la PKI ; un locataire le remplace en
group_vars, l inventaire du site est dynamique et n en a pas. Les autres replis
rendaient un service muet — celui-la rend du TLS qui RESSEMBLE a du TLS : le
cadenas s affiche et rien n est prouve.
site_inventaire construisait sa propre liste d expositions, avec edge = le
groupe de l application. Vrai tant que le site n avait pas d edge. client_pki
retient un FQDN si son edge est un groupe de cet hote : aucun ne correspondait,
et le certificat ne portait que le nom de la machine. La boucle est remplacee
par un appel a expositions_des_applications.
Et la cicatrice de site-forge-01 — un cert renouvele n atteint personne tant que
son consommateur n est pas recharge — a ete refaite sur la machine suivante.
Les 6 noms sont maintenant servis et verifies contre l AC du site.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Les quatre defauts ont la MEME forme : un repli qui rend un succes au lieu d un
refus.
1. Le gabarit dore porte l adresse du cache d avant le renumerotage, et
site_inventaire derivait dns_amorcage sans deriver son jumeau
artefacts_amorcage. Le site fournissait cette valeur a ses locataires sans se
la donner a lui-meme.
2. opnsense_if_zones ignorait la zone neuve, et _if_de retombe sur l ancienne
patte PLATE : 20 regles posees sur vlan030, correctes et jamais rencontrees.
Le fichier documentait deja le meme incident un mois plus tot.
3. serveur_nginx chargeait domaines.yml sans condition — un SITE ne publie rien
a l Internet et n a pas ce registre. Il releve maintenant ce qui existe.
4. Sans registre de domaines, l edge d une exposition retombe sur le GROUPE DE
L APPLICATION, jamais serveur_nginx : le vhost genere faisait 43 octets et le
deploiement rendait vert. Une derivation qui ne trouve rien ne se distingue
pas d une derivation qui n a rien a trouver.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Le site servait trois applications web sans jamais les publier : observatoire,
vigie et console ne se joignaient que par adresse:port, en clair, depuis le plan
d administration.
Zone site-publication (VLAN 37) a elle seule. Les autres zones separent ce qui
agit de ce qui est agi ; celle-ci separe ce qui est adresse de l exterieur de ce
qui ne doit jamais l etre. Un edge est la machine qu on attaque en premier : elle
ne partage pas son voisinage.
site-edge-01 : 2 vCPU, 2 Go, 20 Go, sans client_backup — un relais ne porte aucun
etat. Elle ne s expose pas elle-meme : les expose des AUTRES applications
deviennent ses vhosts et les SAN de son certificat.
P23 a refuse une passerelle fantome. appliquer_opnsense pose des regles et des
routes, pas des interfaces : declarer la patte 10.37.37.1 rend le geste manuel
visible et verifiable, et le harnais le relit a chaque passage.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Le GUI n a aucune authentification : GET / sert la page a qui la demande, jeton
ecrit dedans, et POST /api exige ce jeton que la page vient de donner. Le jeton
garde contre le CSRF, pas contre un visiteur — la seule serrure est
--hote 127.0.0.1. Ce qu il offre a qui entre : deployer, creer, raser, editer le
plan. La fabric entiere.
Le service reste donc sur la boucle locale. Ce qui est publie est un nginx local
qui authentifie d abord : oidc par defaut (oauth2-proxy, donc un groupe
d annuaire qu on revoque sans deploiement), locale en repli pour un ecosysteme
sans annuaire. L authentification est posee au niveau du server, pas d un
location.
La sonde console-ops mesure une SERRURE : une requete anonyme doit etre REFUSEE.
Un 200 y est la pire des reponses, et il ne fait echouer personne.
P54 a attrape une contrainte ratee : serveur_ops est insemine par le SITE, qui
ne detient pas la voute du locataire. Le role ne nomme donc aucune voute — il
declare un parametre, et la couche qui detient le secret le remplit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Icinga Web 2 gagne un troisieme mode, locale : nginx authentifie en HTTP Basic
et pose REMOTE_USER, l application le croit. Un SITE n a ni annuaire ni Keycloak
— ce sont des services d ecosysteme. Ni backend LDAP ni backend de groupes : un
backend qui vise une ressource inexistante fait echouer chaque ouverture de
session. L habilitation nomme alors une personne, entorse a D-66 ecrite plutot
que contournee.
Deux pieges en chemin : resoudre_annuaire etait appele sans condition et tombait
sur NoneType has no len (default sans son second argument ne remplace pas None),
et le flux du role ne nommait que l edge — le site n en a pas, donc personne ne
pouvait entrer. serveur_grafana portait deja la reponse.
LE DEFAUT DU DEVIS : une sortie vers un role ABSENT de l ecosysteme retombait
sur !SETOPS_INTERNES, la forme de vers l Internet. La frontiere aurait autorise
la console a parler LDAPS a n importe quelle machine du monde, pour joindre un
annuaire qui n existe pas. C est une source vide ouvre le port, cote
destination. Trois regles du meme defaut etaient DEJA posees pour postfix.
La frontiere n est pas ecrite : elle porte la production, et le devis attend un
mot.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
La supervision du SITE etait morte depuis 11:10 et rien ne le disait. icingadb
refuse par pg_hba — hostssl impose cote serveur, connexion en clair cote client.
icinga2 tournait, redis tournait, les sondes poussaient, et rien n atteignait la
base : les verdicts se calculaient dans le vide.
La cause est une seconde liste tenue a la main. tls_force allume hostssl ; chaque
consommateur avait SON interrupteur a allumer dans les group_vars. Chezlepro
avait les trois, le site avait le premier. serveur_forgejo disait pire que rien :
sslmode disable ecrit en dur, le contraire de ce que le serveur imposait.
resoudre_base expose resoudre_base_db_tls_force, lu dans les hostvars de la
machine qui PORTE la base. Les trois interrupteurs en derivent. Un serveur qui
ne declare rien ne force rien : on ne casse pas un ecosysteme qui n a pas
bascule.
P78 refuse une valeur ecrite chez un consommateur, et nomme les deux roles sans
reglage TLS plutot que de rendre un vert muet sur eux.
Apres : icingadb active, TLSv1.3 vu par PostgreSQL, 16 hotes et 88 services en
base. Les cinq sondes des marqueurs du site, INCONNU faute de deploiement,
rapportent leur phrase.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Le plan du site expose observatoire.genese.internal ; serveur_grafana devinait
grafana.<domaine>. Grafana fabriquait son root_url, ses liens d alerte et son
URL de retour OIDC avec un nom que rien ne sert.
C est mot pour mot le defaut du 2026-09-10, quatre jours plus tard, de l autre
cote : instancier derive <groupe>_hostname depuis ce jour-la et P67 le garde,
mais tous deux ne connaissent que l instance montee — donc un locataire.
L inventaire du site n en derivait aucun. Quatre devinettes sur cinq tombaient
juste par convention, et c est ce qui rendait le defaut invisible.
site_inventaire.py derive les cinq noms du plan. P67 lit maintenant les deux
inventaires — celui du site est dynamique, donc elle l EXECUTE au lieu de lire
sa source. Eprouvee dans les deux sens : 10 services sur 2 inventaires.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Le gabarit de voute reclamait cette cle pour serveur_postgresql ; la voute reelle
du site ne l avait pas. Le gabarit disait quoi mettre, personne ne l avait mis.
40 caracteres alphanumeriques : le mot de passe entre dans une URI de connexion
PostgreSQL, et un @ ou un / y couperait l URI en deux — l echec dirait mauvais
mot de passe au lieu d URI mal formee.
Gardes passees : copie de surete, dechiffrement vers un FICHIER jamais vers un
tube, relecture du YAML, en-tete verifie apres, empreinte comparee, 15 cles
relues, clair passe au shred. Le premier rechiffrement produisait du 1.2
etiquete la ou la voute portait du 1.1 — refait sans etiquette, parce que le
runner du site ouvre avec un unique fichier-cle.
Compte setops_metriques : ni superuser, ni createdb, ni createrole, membre de
pg_monitor et rien d autre.
Les huit panneaux des deux tableaux derives repondent, mesures sur le site.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Le tableau des panneaux vivait DANS la condition de l exportateur. Le premier
role a declarer des panneaux sans exportateur — client_metrique, dont le job
node est universel — affichait « aucun exportateur declare » et cachait ses
quatre panneaux.
Une fiche qui tait ce qu un role declare est pire qu une fiche absente : elle
affirme que rien n existe.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
La moitie qui manquait. Les roles declaraient leurs panneaux, Prometheus en
derivait ses cibles, les expressions repondaient, et rien ne les assemblait.
serveur_grafana lit les memes meta/metriques.yml que serveur_prometheus et en
assemble un tableau par role — la raison du panneau devient sa description dans
Grafana. Moisson des tableaux orphelins, prefixe setops-role- pour ne jamais
toucher un tableau ecrit a la main, JSON valide avant d etre pose (Grafana ne
tombe pas sur un tableau illisible : il le saute en silence).
client_metrique declare quatre panneaux sans exportateur — le cas symetrique.
Celui qui compte : la memoire disponible, depuis que le ballon est actif.
Eprouve sur le site : les deux tableaux charges dans le stockage unifie, un
temoin orphelin retire, les quatre panneaux de flotte a 10 series chacun.
Un panneau etait faux — /var/lib/lxcfs rapporte toujours zero octet libre et un
min() en meurt. Corrige en liste blanche : un montage inconnu manque au graphe,
ce qui se voit, au lieu de l ecraser.
P77 garde la table des unites : une unite inventee retombe sur short, lisible et
fausse. 76 OK.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
La cible lisait $$remote — une variable de shell que rien ne definit — au lieu
de $(WIKI_REMOTE). L echappatoire que le message d erreur proposait lui-meme
n existait pas.
WIKI_BRANCHE, deux cibles plus bas, etait ecrit correctement depuis le debut.
Une option qui se lit autrement que sa voisine est l endroit ou regarder.
Wiki publie sur eregion : 95 pages, les huit fiches neuves portent leur sonde —
verifie en clonant la forge, pas en lisant le temoin.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Les 33 roles serveur_* declarent maintenant une sonde. Les huit qui manquaient
sont ceux dont la verite ne ressemble pas a « ce service repond-il ».
Quatre marqueurs du site : ce que tasks/main.yml verifie UNE FOIS au deploiement
cesse d etre vrai sans que rien ne tombe. La racine du cache se retrouve chainee,
la forge du genome repond en n ayant plus rien dedans, un locataire n est plus
admis a resoudre, l isolation d un depot glisse.
serveur_ops_site ne sert rien : il detient un pouvoir. La sonde verifie que la
carte est la, que la voute du site est chiffree et que sa cle est en 0600 — sans
lire le contenu d aucun des trois.
serveur_icingaweb2 surveille la vitrine de la supervision elle-meme : si la
console meurt, tout reste vert et l exploitant est aveugle.
DEFAUT 1 — quatre gabarits qu Ansible aurait refuse de rendre. Jinja lit le
{# de ${#tableau[@]} comme un debut de commentaire. Le depot connaissait le
remede et l appliquait la ou quelqu un s etait fait prendre, nulle part ailleurs.
P76 rend desormais chaque gabarit de role, avec les delimiteurs qu Ansible en
tirerait — pas une recherche de motif.
DEFAUT 2 — la doctrine promettait 54 greffons et citait check_pgsql. La flotte a
monitoring-plugins-basic : 53, sans check_pgsql ni check_dns ni check_ldap. Le
paquet qui les porte traine samba et snmp sur chaque machine. Un greffon absent
sort en 127, qui n est pas un code Nagios.
21 controles negatifs sur les machines reelles du site. ansible-lint production
0/91, harnais 75 OK.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Trois plans de locataire et cinq modeles perdent leur forge ou leur cache
d artefacts. Une machine de moins par ecosysteme neuf : origine passe de cinq
a quatre, et tout ecosysteme neuf en descend.
Retirer un service, ce sont cinq points d attache — le service, sa machine, sa
base, son client SSO, sa configuration de role. En oublier un laisse un
inventaire qui se genere et un deploiement qui echoue plus tard.
Preuve statique apres coup : 74 OK, 0 echec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Decision : seuls les SITES portent la forge, le cache APT et les artefacts. Meme
geste que le retrait de serveur_artefacts d un plan de locataire, un cran plus
loin — le site fournit tout ce dont un tenant a besoin pour venir au monde.
La generalisation de forge_amorcer a un locataire est revenue en arriere : elle
implementait le modele ecarte, et la garder en ferait un piege.
ma_forge ne derive plus MA forge mais la forge qui porte MON genome. Le signal
est deja au plan : serveur_ops_forge_externe dit je lis mon genome ailleurs. Qui
le declare consulte, il ne republie pas.
Reste vrai : une forge de locataire peut exister pour LE CODE DE SES GENS —
c est l offre Atelier. Ce n est pas l endroit ou vit le moteur.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
make wiki-publier a refuse : le wiki vise par le temoin — la forge du SITE —
n a aucun commit. Le wiki vivant est sur eregion, 26 pages, branche main. Le
temoin affirmait depuis le 12 avoir publie sur une forge dont le depot wiki n a
pas survecu a sa reconstruction.
C est ce que P60 annonce d elle-meme : un temoin dit ce qui est PARTI, jamais ce
qui est ARRIVE. La preuve etait verte et la documentation n existait nulle part
a l adresse qu elle nommait.
Le garde-fou a tenu : publier sur un wiki vide aurait invente un nom de branche.
95 pages en ligne, dont les 68 fiches et leur index.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Generees depuis ce que chaque role declare, avec un schema mermaid et la raison
de chaque ligne. Une section vide est une information : l index recompte ce que
la flotte ne declare pas — 36 sans flux, 40 sans sonde, 67 sans metrique.
La charte du wiki disait de ne pas recopier le depot, pour eviter la derive. Le
motif ne vaut pas pour une page qui relit sa source ; l exception est nommee
plutot que prise en silence.
La navigation exigeait une citation DIRECTE alors que son motif parle
d atteignabilite. L exigence litterale interdisait toute page d index — la garde
forcait a degrader ce qu elle protegeait. Elle suit maintenant les liens de
proche en proche, et son motif reconnait le souligne : un motif trop etroit ne
rend pas une garde prudente, il la rend aveugle.
Et le compte du wiki serait passe de 27 a 96 : une fiche generee n est pas une
unite d apprentissage.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Declaration, flux, installation, 657 series servies, job derive par Prometheus,
cible up, et les trois panneaux interroges pour de vrai : 11 connexions, cache a
0,9982, 84 Mo de bases.
Le crochet cibles_supplementaires n est plus vide pour la premiere fois.
Au passage, la voute a rappele sa ligne : vault.yml est gitignore, aucun secret
ne transite par la forge. Le runner avait saute l exportateur sans rien dire
(changed=0) parce que sa voute datait. Le geste d armement est le seul transport
de secret du systeme, et il se refait a chaque changement.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Aucune metrique de SERVICE n etait collectee — seulement du systeme. Le crochet
serveur_prometheus_cibles_supplementaires existait, documente, et personne ne le
remplissait.
Le pendant de meta/supervision.yml et son contraire : une sonde rend un verdict
avec un TTL, un exportateur expose une serie. Est-ce casse, contre depuis quand
et vers ou.
Le critere des panneaux : une serie a sa place si elle PRECEDE un verdict ou si
elle n en aura JAMAIS. Le taux de succes du cache n en aura jamais — quand les
donnees depassent shared_buffers, rien ne casse et tout devient lent.
Compte en lecture seule (pg_monitor), et flux en clair avec sa dette inscrite.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
playbooks/site.yml ordonne les couches pour n importe quelle instance. Mais
deployer-tout ne vise que l inventaire d un locataire, et le site n avait que
site-appliquer GROUPE=<un seul>.
Un hebergeur qu on ne peut remonter qu en enchainant onze groupes de memoire
n est pas reconstructible : il est reparable par quelqu un qui se souvient.
Et quatre gardes que --check rendait folles, toutes de la meme famille : une
garde qui compare contre ce qu une tache du meme play vient de produire n a rien
a dire tant que rien n a ete ecrit. Sept machines en echec sur un site sain, en
suivant le conseil du Makefile lui-meme.
Apres correction : 7/7, 0 echec, de 174 a 309 taches par machine.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Depot sain code 0 avec 4 depots et 374G libres. Chemin non inscriptible code 2.
Chemin inexistant code 2. Zero temoin residuel dans le vrai depot.
Pour y arriver il a fallu que le runner du site puisse entrer chez lui — ce
qu il ne savait pas faire. Trois causes empilees, dont une que j ai ecrite en
corrigeant les deux autres.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
edition, filtrage, passerelle : vert code 0 sur le sain, rouge code 2 avec une
chaine introuvable. Services intacts apres l essai.
Une sonde qu on n a jamais vue echouer n est pas une sonde, c est une habitude.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Etat sain vert aux deux passages, Redis arrete rouge, seuil impossible rouge.
Sur data-sql-01 de TechnoLibre, service remis en etat apres l essai.
Une sonde qu on n a jamais vue echouer n est pas une sonde, c est une habitude.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
L entree du 2026-09-13 affirmait aucun maxmemory configure. Faux : le grep
visait /etc/redis/redis.conf alors que le role ecrit setops.conf. Interroge la
ou la verite vit, redis repond maxmemory 268435456 et allkeys-lru.
La conclusion ne change pas — redis reste hors de la table des planchers — mais
sa raison change : il est borne a 256 Mo, il ne peut pas prendre la machine.
Un fichier de configuration n est pas la configuration ; c est une de ses
sources.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Un runner tire ce qu on pousse, il ne le recoit pas. Trois fois ce soir un
genome perime a menace de rebatir un etat depasse — et aucun des deux runners
n aurait echoue : un deploiement depuis un genome perime REUSSIT. Il applique
fidelement un etat qui n a plus cours, et se presente en vert.
En retard : refus. En avance ou diverge : note et on continue. Forge
injoignable : note et on continue — une forge en panne ne doit pas immobiliser
une exploitation, le silence serait la faute.
FORCE=1 passe outre. Eprouvee dans les trois sens.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Le controle rapportait CONFORME sur un locataire dont le plan d administration
pointait les bouts de WAN d un AUTRE site. nftables_admin_ssh et
passerelle_sortie n etaient compares par personne.
Quatorze machines debout, le runner insemine, et l exploitant bloque a la porte
sans qu aucune garde n ait rien eu a dire.
nftables_admin_ssh est une liste : la comparaison normalise, parce que l ordre
d une liste de sources ne porte aucun sens.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
instancier le derivait, le playbook savait le poser, et la table qui les relie
ne transmettait rien. Quatorze machines allaient naitre avec le ballooning
desactive sans qu une seule etape echoue : variable vide, extra-var non passee,
garde when: qui saute. Trois silences en file.
P75 lit la cible creer-vm, releve chaque $SETOPS_X qu elle consomme et exige
que la table qui les emet le declare. Eprouvee dans les deux sens.
74 OK, 0 echec, 1 saute.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
flux-genere/ ecrivait sans jamais retirer. Un hote sorti du plan y laissait son
ruleset complet, indiscernable des vivants. Le dossier cessait d'etre une image
du plan pour devenir le cumul de tous les plans successifs.
P53 voyait l'orphelin — un ruleset perime n'a pas de refus audible — mais
designait le fichier, pas la cause.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
61 Go declares a 21 machines, 12 reellement utilises. balloon valait 0 partout,
ce qui ne desactive pas le ballooning : cela RETIRE le peripherique de la ligne
de commande QEMU. Le moniteur repond "No balloon device has been activated".
Le moteur derive desormais un plancher par machine sur les deux chemins de
creation, et le playbook de clonage le pose a cote de memory.
La table des planchers a ete corrigee deux fois par la mesure : shared_buffers
vaut 128 Mo et non une part de la RAM, une JVM tient 605 Mo, Redis 16 Mo. Ces
machines tiennent du cache de pages, pas un jeu de donnees.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Le plan du site disait 9006 (modeleSetOPS-minimal), l underlay 99998 — que le plan
nomme lui-meme `precedent`. Le Makefile derive VMID_MODELE du PLAN : les locataires
clonaient 9006. `site_machines` lisait l autre : les machines du SITE clonaient 99998.
POURQUOI CA NE S EST JAMAIS VU. Les deux VMID designent un gabarit valide. Les deux
clonent, les deux demarrent, rien n echoue. La flotte etait issue de deux souches, et
aucun message ne pouvait le dire puisqu aucune operation n avait echoue.
`site_machines` lit desormais underlay.gabarit(), la meme source que tout le monde. Le
motif de la seconde declaration est preserve : cette source lit le PLAN DU SITE, jamais
celui du tenant actif, donc elle ne depend d aucun symlink `instance`.
materialisation.vmid_modele retire des deux cartes. `precedent:` reste au plan — il dit
d ou l on vient et n est jamais clone.
P74 refuse toute redeclaration. Eprouvee dans les deux sens.
SITE-Technolibre visait 99998, repris de la carte de Chezlepro au lieu de son plan.
Corrige avant son premier clonage.
make prouver : 73 OK, 0 echec, 1 saute.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
`--support-chiffre` ecrit un tar clair quand le support est deja chiffre au repos.
Ajoute cote EXPORT le 12 septembre, et pas cote RESTAURATION : `restaurer_cles.py`,
qui est ce qui rend la cle USB autonome, ne savait lire que du GPG.
Constate en EPROUVANT l export, pas en le supposant reussi. Et le message etait le
pire possible :
gpg: aucune donnee OpenPGP valable n a ete trouvee.
ECHEC du dechiffrement. Phrase de passe erronee, ou archive abimee.
Il accusait une phrase de passe qu on n avait jamais posee, sur une archive saine. Il
envoyait chercher la faute la ou elle n est pas — au moment ou l on restaure, c est-a
-dire au moment ou l on sait le moins.
`tarfile.is_tarfile` reconnait la forme. Pas de drapeau a passer : ce serait une chose
de plus a savoir le jour ou tout a brule.
Verifie sur la cle reelle : l archive du 13 se liste, dix fichiers, chacun avec sa
destination. Le garde-fou a par ailleurs refuse d ecraser celle du 12 — « on n ecrase
pas une sauvegarde de cles : elle est peut-etre la seule » — donc la nouvelle est
datee et l ancienne reste.
make prouver : 72 OK, 0 echec, 1 saute.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Un locataire ECRIT les adresses des services de son site — resolveur, cache, forge,
depot de sauvegarde, plan d administration, sortie. Une copie se perime, et deux
l avaient fait en deux jours avec la meme forme : `serveur_ops_forge_amont` visait
10.0.33.11 quand la forge sert en 10.37.33.11, et `ac-racine-site.crt` portait la
racine d avant la reconstruction du site. Rien ne les relisait.
`make site-intrants` lit le plan du site et rend le contrat — sept valeurs, toutes
derivees. `make site-intrants-verifier` les confronte a ce que le locataire declare,
et P73 en fait une preuve. Elle a trouve le defaut de la forge des sa premiere
execution.
Le contrat se DERIVE du plan du site, pas d une liste tenue a part : ajouter un
service prete au site l ajoute au contrat, sans qu on ait a y penser.
P69 RESTREINTE AU COUPLE MONTE. Elle balayait tous les depots OPS-* et les comparait
au site monte. Elle avait raison tant qu un seul site existait : une adresse en
10.x.3z ne pouvait designer que lui. Deux sites decoupent leurs zones de la meme
facon — c est le but, un locataire doit pouvoir habiter l un ou l autre sans se
renumeroter. Le troisieme octet a cesse de distinguer « mon site » d « un autre
site » : 10.31.34.11, juste pour un locataire de TechnoLibre, etait declare faux
parce que Chezlepro etait monte.
Un locataire n appartient a aucun site — il en habite un, choisi par le symlink au
deploiement. La seule paire jugeable est celle qui est montee. Meme portee que P73.
Une marche payee : la premiere version de site_intrants recopiait la resolution
d instance au lieu de la partager. P41 a mordu — neuf modules avaient deja porte
chacun leur copie, et cinq defauts en etaient sortis en cinq jours.
make prouver : 72 OK, 0 echec, 1 saute. ansible-lint : 0 failure.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Keycloak, Dovecot, Postfix et Icinga Web 2 se liaient TOUS avec cn=admin, le compte
d administration de la base. C est le rootDN : slapd lui fait contourner toutes les
ACL. Un seul secret, quatre services, tous les droits sur l arbre — pour ce qui est,
trois fois sur quatre, une simple lecture.
Et les droits livres par Debian etaient intacts : `to * by * read`. Sur ldap://, sans
s authentifier, une machine du reseau enumerait tous les comptes et toutes les
adresses. Des comptes a droits mesures n auraient rien valu tant que cette ligne
restait : on aurait ferme la porte en laissant la fenetre.
L indice etait deja dans le depot. `validatePasswordPolicy` existe parce que slapd
n applique pas ses controles de qualite au rootDN : la consequence etait compensee,
la cause intacte.
- ou=services, un compte par consommateur, secret propre en voute
- sept regles d acces posees EN ENTIER (state: exact) : l ordre est la regle, et
inserer c est parier sur ce que le paquet aura mis avant nous
- amorcage_acces garde le compte d administration, NOMME comme l exception : il ne
consomme pas l annuaire, il le provisionne depuis la socket locale
- la sonde passe de -x a -Y EXTERNAL : elle lisait en anonyme et aurait annonce un
annuaire VIDE sur un annuaire parfaitement sain
- la rotation du compte d administration devient possible (elle n etait posee qu a
l installation, par debconf : la voute et slapd divergeaient en silence)
Quatre marches payees en chemin :
1. un cinquieme appelant oublie, dont l echec etait masque par no_log — la garde
refuse desormais SANS no_log : elle nomme la cle absente, jamais son contenu
2. la federation Keycloak ne reecrivait son bindDn que si l URL ou le mode changeaient
— nouveau secret, ancien nom, error code 49
3. la rotation placee APRES les taches qui se lient en administrateur
4. ansible-vault et son tube : sortie non bloquante = echec silencieux, la voute
paraissait tournee et etait identique a l octet
P72 exige que tout role incluant resoudre_annuaire NOMME son compte, et qu aucun sauf
amorcage_acces ne nomme admin. Eprouvee dans les deux sens.
Verifie sur l infrastructure : chaque compte lit ce qu il doit, aucun ne voit les
autres, la lecture anonyme rend 0 entree, et les quatre services repondent (doveadm
user, postmap -q, decouverte OIDC 200, portier SSO 200).
vault_openldap_admin et vault_ldap_bind_postfix renouveles : les deux avaient transite
en clair par une session d exploitation. Les anciennes valeurs rendent Invalid
credentials (49).
make prouver : 71 OK, 0 echec, 1 saute. ansible-lint : 0 failure, profil production.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
`Chezlepro-17` contenait VINGT ET UNE VM : les quatorze du locataire ET les sept du
genome. `OPS-Chezlepro` et `OPS-Technolibre`, crees a la main, etaient vides.
La cause : `site-creer` appelle `cloner-vm`, qui derive son pool par `--pool-actif`,
c est-a-dire le pool du TENANT lie. Les machines du site heritaient du locataire
courant. Range a la main, ca se serait defait au prochain `site-creer` — sans un mot,
parce que la VM est bien creee, bien nommee, bien adressee. Seule son appartenance
est fausse, et rien ne la regarde.
- `--pool-site` rend le nom invariable du pool du genome. Option DISTINCTE, pas un
drapeau sur la premiere : une fonction qui repond aux deux questions finit par se
tromper d appelant.
- `cloner-vm` accepte une surcharge POOL= ; `site-creer` la nomme. Substitution au
niveau MAKE, pas shell : POOL arrive du sur-make comme variable make, et $${POOL}
ne l aurait jamais vue.
- P71 exige que `site-creer` nomme son pool. Eprouvee dans les deux sens : passe sur
le Makefile sain, tire des qu on retire l argument.
Applique au cluster : Site-OPS 9 VM (7 du site + 2 gabarits), OPS-Chezlepro 14,
OPS-Patient0 5. Chezlepro-17, Patient0-29 et Set-OPS supprimes une fois vides. Les
pools anterieurs a Set-OPS et les quinze VM hors pool n ont pas ete touches.
make prouver : 70 OK, 0 echec, 1 saute.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Le cache du site couvrait apt ; quatre artefacts arrivaient autrement, parce qu ils
ne vivent dans aucun depot apt. Le controleur les tire puis les pousse par SSH.
Mesure du 2026-09-12 : le cache du runner du site est ABSENT. Un second locataire
monte depuis lui sortait chercher 570 Mo sur codeberg.org, github.com et
download.nextcloud.com, alors que le meme ecosysteme ne demandait plus un seul
paquet a Debian. Le poste du mainteneur les a depuis toujours : personne ne l avait vu.
Pas de relais transparent, et la mesure tranche : github.com redirige vers une URL
signee valable une heure, differente a chaque requete. Un cache qui la prend pour
cle ne fait jamais mouche. Le relais marcherait pour deux amonts sur quatre.
Donc un vrai depot, dans le service qui existe deja. LocalDirs d apt-cacher-ng publie
un repertoire du disque sous un prefixe, eprouve AVANT d ecrire le role. Aucun service,
aucun port, aucun certificat, aucun flux nouveaux : l ingress 3142 pair flotte couvre
exactement ce chemin.
Les versions ne sont pas recopiees : le role lit les defauts des quatre consommateurs.
Les quatre roles recoivent une tache AJOUTEE, placee avant leur stat de cache — si le
depot sert, le stat le voit et la tache amont se saute d elle-meme. Aucune tache
existante n a change.
P70 exige que tout dest ecrit sous un cache_local figure au depot. Une liste qui suit
une autre prend du retard ; celle-ci est nee avec sa garde.
Deux marches payees en chemin :
- failed_when: false REECRIT le verdict, donc la premiere garde de signature ne
gardait rien. Elles mesurent le fichier desormais.
- file: state=directory cree les parents en 0750 : apt-cacher-ng, qui ne tourne pas
en root, rendait 403 sur chaque fichier. Un chemin se traverse en entier.
Verifie sur l infrastructure : 6/6 artefacts servis (200/206) depuis le runner du site
ET depuis une machine du locataire a travers la frontiere ; les 6 empreintes SHA-256
sont identiques a celles qui ont construit Chezlepro ; second passage changed=0.
make prouver : 69 OK, 0 echec, 1 saute. ansible-lint : 0 failure, profil production.
Inclut aussi force: true sur cinq telechargements de cles : une reprise conditionnelle
ne reprend rien (304 Not Modified, size 0, attempts 5).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
LE NOM D UN POOL EST CELUI DE SON DEPOT. Chezlepro-17 devient OPS-Chezlepro :
le seed se lisait dans le nom, ce qui obligeait a connaitre le codage — et
surtout le nom CHANGEAIT si l index changeait, ce que la renumerotation du
site a montre le jour meme.
Site-OPS ne derive de rien, et c est le point : les machines du genome ne
dependent d aucun index, elles sont l infrastructure SUR laquelle les index
vivent. Sans ce bloc elles restaient hors de tout pool.
P69 — l amorcage d un tenant designe-t-il le site REEL ? dns_amorcage et
artefacts_amorcage sont ecrits a la main, volontairement : au moment ou ils
servent la machine ne resout aucun nom. Mais ils designent des machines DU
SITE, et n ont pas suivi son renumerotage. La reconstruction du locataire
s est arretee sur Failed to update apt cache, a quinze couches de sa cause.
La preuve ne juge que les valeurs qui PRETENDENT designer le site : viser
9.9.9.9 est un choix, pas un oubli.
LES CLES SORTENT DU POSTE, EN CLAIR, ET C EST RAISONNE. Support perdu : LUKS
s en charge. Poste compromis : la seconde couche n aide pas, les originaux
sont dans ~/.config sur ce meme poste. Elle coutait une phrase de passe
stockee nulle part — le seul point que la procedure ne couvre pas. Option
--support-chiffre explicite ; le defaut reste GPG, parce qu un support non
chiffre est le cas le plus frequent.
Et ma note qui disait les cles sorties depuis le 5 septembre etait fausse :
le support ne portait que le depot hors site du 1er.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Tour 1 8 passages ~2 h 30 16 defauts
Tour 2 3 passages 53 min 2 defauts
Tour 3 2 passages 37 min 0
LE TOUR 2 EST CELUI QUI COMPTE LE PLUS. J avais annonce deux passages ; il en
fallait trois, parce que les deux blocages connus sont EN SERIE : on ne peut
pas amorcer une forge qui ne tourne pas, et elle ne tourne qu apres la
convergence de la cle. Un runbook ecrit d apres un recit de depannage
contenait une erreur qu aucune relecture n aurait montree — il fallait le
SUIVRE pour la voir.
DEUX MURS DE PLUS, invisibles au tour 1. site-creer rend la main avant que
les machines repondent (3 min 20 mesurees). Et les cles d hote changent a
chaque reconstruction : accept-new couvre la premiere rencontre, jamais un
changement.
LE CYCLE DE LA CLE EST DENOUE. Aucun ordre de couches n y pouvait rien — les
certificats doivent venir tot. C est la propriete du geste qui a change de
main : serveur_forgejo revendique la cle au moment ou il cree le groupe.
client_pki garde la sienne et la repose a chaque passage, parce que step
reecrit la cle a chaque renouvellement. Gain : un passage entier et 300
secondes d attente perdue.
forge-amorcer purge desormais l entree perimee de l hote que GIT va
contacter, lu dans git remote get-url — pas celle de l API, qui peut etre un
tunnel. Et il rend les quatre premieres lignes de stderr : n afficher que la
derniere m a coute un aller-retour, git terminant toujours par un message
generique.
Le runbook porte les six etapes du tour 3 avec leurs durees reelles et les
dix-huit murs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
SITE-Chezlepro n avait jamais ete rase. La limite qu on repetait partout —
l infrastructure d accueil n a jamais ete reconstruite depuis zero — se
lisait comme de la prudence. C etait seize defauts que rien d autre n aurait
pu reveler.
Un locataire naît dans un monde deja peuple : le site lui fournit paquets,
noms, genome, heure et depot. Un site n a personne au-dessus, sauf sa
frontiere. Onze des seize murs viennent de la.
DEUX CAPACITES QUI N EXISTAIENT PAS. make site-raser — rien ne detruisait les
machines du site, donc la limite etait un trou d outillage. make
forge-amorcer — la forge naît vide et le runner y clone ; l amorcage part du
poste, seul endroit qui detienne alors le genome.
TROIS GARDES QUI VERIFIAIENT LA FORME. La plus couteuse des familles : elles
donnent l apparence d une verification. Le resolveur comparait des adresses
au lieu de mesurer si la resolution aboutit, et protegeait ainsi l etat
casse. L administration etait reconnue a son port. Un flux a deux paires
n obtenait qu une branche.
UN ECART DE SECURITE. Le PostgreSQL du site servait le certificat auto-signe
de Debian, sans reseaux autorises ni hostssl — invisible tant qu aucun client
n exigeait la verification. Le defaut n a pas casse la construction : la
construction a revele le defaut.
UN ACCES ACCIDENTEL. Celui de l exploitant tenait au chevauchement d
adressage que le renumerotage a supprime. Separer les index n a pas cause le
probleme, il a retire le hasard qui le masquait.
La sequence du premier jour est ecrite : runbooks §9, avec les seize murs et
ce que chacun enseigne.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Decision de l exploitant : sites et locataires se partagent la classe A,
chacun avec son propre index. L exception du guide — un site derive du meme
index que son tenant — disparait.
Ce qu elle cachait : le plan d administration du site vit dans 10.17.0.0/24,
a l interieur du supernet du locataire OPS-Chezlepro. Pas dangereux, mais
10.17.0.0/16 designait deux choses. Et les zones du site ne derivaient de
rien — le site etait la seule partie du systeme sans seed.
La seconde liste nait avec cette decision : un site et un locataire peuvent
desormais reclamer le meme nombre, et make instances ne voyait que les depots
OPS-*. La decouverte lit maintenant SITE-*/underlay.yml et son champ index.
Un site sans index declare reste hors du compte.
SITE-Technolibre : squelette du deuxieme site pour la visite du 14. Un seul
noeud Proxmox en version 9, meme forme que Chezlepro, adresse depuis l index
31. COLLECTE.md liste les 35 valeurs a relever.
Reste a l exploitant : OPS-Chezlepro passe a 37, ce qui libere 17 pour le
site qui l utilise deja.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Decision de l exploitant, et elle corrige un mauvais jugement de ma part :
j avais decrit la situation correctement — la seule operation de la flotte
qui exige un humain — puis propose un minuteur maison plutot que le mecanisme
que Debian fournit exactement pour ca.
Le desarmement d aout avait un motif reel (48 minutes de verrou dpkg apres un
rattrapage) mais une contrepartie ecrite sans etre mesuree. Ce qui rend la
coexistence tenable existe maintenant : _attendre-hote attend apt-daily et le
verrou, lock_timeout est pose partout, unattended-upgrades ne traite que
l origine -security, et Automatic-Reboot reste false.
Rearmer ne se deduit pas de ne plus desarmer : passer le drapeau a false
saute la tache, il ne demasque rien. Une tache de rearmement explicite est
donc posee le jour meme ou la decision s inverse.
ET LA PREMIERE VERSION A REJOUE LA COURSE. state: started sur les trois
unites lance le rattrapage en plein deploiement : dix machines sur vingt et
une, avec l erreur meme qui avait motive le masquage. Le travail quotidien ne
passe pas par ce service — le timer appelle apt.systemd.daily directement. On
ARME sans declencher : les minuteurs demarres, le service seulement active.
21 machines, minuteurs armes, prochain passage demain vers 06h, zero unite en
echec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Mesure sur les quatorze : aucune sortie TCP vers une adresse publique, apt
par le cache, noms autoritaires en local, unattended-upgrades masked. Et
quatre pairs NTP publics par machine. Le role chrony posait le fuseau et
installait le demon sans jamais toucher a ses sources : le defaut de Debian
tenait depuis le premier jour, herite et jamais choisi.
L autorite est la frontiere, par decision de l exploitant. Elle etait deja
stratum 2 et ecoutait en 123 ; il ne manquait que le passage. 9 anciennes
regles port 123 vers !SETOPS_INTERNES retirees, 9 regles nommees vers
SETOPS_FRONTIERE posees : le changement resserre autant qu il centralise.
Deux chemins parce que la topologie en a deux. Un tenant n atteint pas la
frontiere par sa passerelle de zone — tenue par le SDN — mais par le lien de
transit. Une machine du site a la frontiere pour passerelle directe. Les deux
valeurs sont derivees de l underlay, via reseau_transit() plutot que d un
prefixe d adresse qui aurait menti chez le prochain hebergeur.
La patte face aux tenants manquait a opnsense_if_zones, pour la meme raison
que grappe-controle la veille.
Sonde horloge ecrite en meme temps : synchronisee ET contre la source
DECLAREE. Une machine peut etre parfaitement a l heure contre quatre serveurs
publics — c est exactement l etat d avant.
14 tenant + 7 site, toutes disciplinees, sources publiques = 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Renommer une exposition touche cinq choses. Quatre suivent au deploiement ;
la cinquieme est celle que le navigateur regarde. serveur_nginx pose le vhost
et laisse le SAN en arriere — c est client_pki qui reemet, et rien ne le
reclame. Mesure deux fois le 2026-09-10.
Le controle compare trois listes : les expositions du plan, les noms du
certificat servi, et le code que rend le vhost. Dans les deux sens : un nom
reste dans le SAN apres avoir quitte le plan continue d etre authentifie.
Piege trouve en l ecrivant : client_pki met toujours le FQDN et le nom court
de la machine dans le SAN. Les compter comme vestiges faisait crier le
controle a chaque execution — et un controle qui crie toujours ne se lit plus.
Deux formes de terminaison, une seule question : le locataire termine sur un
edge, le site sur la machine elle-meme. Le porteur se derive de l une ou de
l autre.
Ce n est pas une preuve : rien de statique ne peut lire un certificat servi.
Les quatre controles a la demande n etaient nommes nulle part comme famille ;
ils ont maintenant leur section dans les runbooks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
auditd tournait, onze regles etaient armees, et rien de tout cela ne servait
a grand-chose. Quatre manques, mesures avant d etre combles.
1. Rien ne sortait. Alloy ne contenait aucune reference a l audit et les cinq
greffons etaient inactifs. Il lit maintenant audit.log et le pousse vers Loki
— sans toucher une permission, alloy etant deja dans le groupe adm. On ecarte
le greffon syslog : journald limite le debit, et une rafale d evenements est
exactement le moment qui compte.
2. Aucune sonde. Elle mesure la COLLECTE, pas l armement : le nombre de
regles est precisement le chiffre qui restait bon pendant la panne du
2026-08-30. Il part en perfdata, jamais en verdict.
3. Retention non declaree. Mesuree a 4,6 Mo/jour au repos ; portee de 40 a
128 Mo. Depuis (1), le local n est plus l archive mais un tampon.
4. Les regles ignoraient la cle privee de l hote. -w /etc/step/ partout, et
-w /etc/step-ca/ sur la seule autorite : auditctl refuse un watch vers un
chemin absent et fait echouer le chargement entier.
Verifie sur l autorite seule d abord, puis 14/14 : regles armees, auditd
actif, sonde a 0, et les quatorze hotes presents dans Loki sous job=audit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Quatrieme reconstruction depuis zero, 32 min 14 s, 14/14. Elle avait un but
precis : trois roles dependent desormais d une variable que le generateur
pose. A froid, si instancier ne la posait pas, le defaut du role reprendrait
la main en silence — juste pour forge et cloud, faux pour observatoire.
Le certificat ne a froid porte observatoire et vigie, aucun ancien nom, et les
deux retours SSO derivent juste sans reprise.
Un seul echec, sans rapport : sur une machine des quatorze, get_url a rendu
0 octet SANS ERREUR — le cache a servi un 200 au corps vide. Le defaut s est
lu deux cents lignes plus loin, dans un apt qui accusait la signature. La
garde posee hier ne mordait pas : retirer une ressource vide ne vaut qu au
passage suivant, quand le fichier existe deja.
Les cinq roles qui telechargent une cle la mesurent maintenant dans la meme
execution. P68 garde le motif. infra-mail-01 redeployee, make valider a
0 echec sur 14 machines.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
icinga.<tenant>.internal devient vigie.<tenant>.internal, sur les trois
locataires a la fois. Le mot avait ete ecarte pour Grafana precisement parce
qu il connote la guette du danger : c est le metier d Icinga.
Quatrieme recopie du meme FQDN a tomber : serveur_oauth2_proxy_redirect_url
etait posee a la main dans les group_vars de chaque instance. Elle derive
maintenant de serveur_oauth2_proxy_hostname. Le repli reste vide et non
fabrique : l assertion doit refuser un deploiement sans exposition, pas
inventer un nom que personne ne resout.
Deploye et VERIFIE sur Chezlepro : le SSO renvoie sur vigie, le certificat
servi porte observatoire et vigie et plus aucun ancien nom. Deployer nginx
pose le vhost mais laisse le SAN en arriere — c est client_pki qui reemet.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Le renommage deploye, nginx servait observatoire, le certificat le portait,
les deux zones le publiaient — et Grafana fabriquait toujours son URL de
retour OIDC avec l ancien nom.
Quatre roles portaient en defaut une devinette du nom sous lequel ils sont
servis. Tant que le plan suit la meme convention, la devinette tombe juste et
rien ne revele qu il y a deux sources. Keycloak avait deja son remede, dans le
role — donc trois roles sans remede.
instancier derive desormais <groupe>_hostname de l exposition unique declaree
par le plan. Six services en heritent. P67 garde la derivation. Les quatre
instances sont regenerees, 67 preuves vertes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
grafana.chezlepro.internal et tableaux.genese.internal nommaient le meme
service de deux facons. Les deux deviennent observatoire.
Un nom de produit dans une URL se grave aussi dans les SAN du certificat et
dans les URI de redirection du SSO : remplacer Grafana obligerait alors a
renommer le service. Le nom dit desormais la fonction.
Le renommage a revele que les URI des clients Keycloak repetent a la main les
FQDN declares dans expose:. Rien ne les reliait. P66 garde ce lien, ecrite en
meme temps que le premier renommage.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Doctrine posee par l exploitant : des lors que le site a son Loki, la
journalisation de la frontiere et des hyperviseurs doit y etre dirigee.
CE QUI ETAIT CASSE. La destination syslog d OPNsense pointait
10.17.20.11:3100 - une adresse de TENANT, sur le port de Loki, en UDP, ce
que Loki ne sait pas lire. La VM a ete rasee ; une cible morte a arrete
TOUTE la journalisation pendant dix jours. La destination a ete eteinte
pour reparer et jamais remplacee. Deux fautes en une : plus de journaux, et
une cible chez un locataire, ce que D-87 refuse dans l autre sens.
L intention etait juste - bonnes facilites, info et au-dessus. On l a
REPRISE telle quelle et change uniquement la destination : ces choix
avaient ete faits, ce n etait pas a nous de les redecider.
UN TRADUCTEUR, parce que Loki ne parle pas syslog : loki.source.syslog dans
l Alloy qui tourne DEJA sur le collecteur. Port 1514 et non 514, donc
ecoute sans privilege - un collecteur qui aurait besoin des droits du
systeme pour entendre un equipement serait un mauvais echange.
UNE REGLE DE RELABEL SANS GARDE N IGNORE PAS : ELLE EFFACE. Trois quarts d
heure sur un symptome absurde - la configuration deposee portait
host = "bifrost-1", visible dans le fichier, et le flux arrivait sans
etiquette. Sans regex, la regle correspond TOUJOURS, meme quand sa source n
existe pas, et pose host = "". Loki jette une etiquette vide, et celle de l
ecouteur disparaissait avec elle.
Et la verification finale a corrige une seconde erreur, la mienne :
label/host/values rendait une liste en CACHE. La requete directe rendait
bien un flux. Un index qui ne montre pas une chose ne prouve pas qu elle n
existe pas.
LA GARDE, qui manquait depuis l incident. journaux-frontiere demande a LOKI
ce qu il a RECU, pas a la frontiere ce qu elle croit avoir envoye : la
destination est le seul juge, et un emetteur qui parle a un trou noir se
porte tres bien. La fenetre est DERIVEE du debit observe - environ 1500
lignes par minute - pas choisie.
Trois etats eprouves sur une copie : frontiere muette rc=2, Loki
injoignable rc=3, debit normal rc=0. Le 3 compte autant que le 2 : « je ne
peux rien affirmer » n est pas « c est casse ».
Mesure : 46 681 lignes recues en 30 min, site a 68 services tous OK.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Les journaux de la fabric, et le defaut de classe que leur mise en place a
revele. 10 hotes dans Loki (7 VM du site + 3 hyperviseurs), site a 67
services tous OK contre 51 avant.
METRIQUES TIREES, JOURNAUX POUSSES. Un scrape part du collecteur et doit
REVENIR : il exige un chemin symetrique, que la route par defaut gelee
interdit. Un push part de la source et n attend qu un accuse.
Trois trous dans les generateurs. Le devis de la frontiere ne connaissait
fabric qu en DESTINATION - un flux entrant tombait dans « rien d autre n
entre » sans rien dire. La regle etait posee sur la patte de la destination
alors que D-61 raisonne en ARRIVEE, et opt7 manquait a la table des zones.
Et le plus grave : fabric etait un mot RECONNU mais NON RESOLU. Source
vide, donc regle sans saddr - tcp dport 3100 accept, ouvert a tous. Un mot
reconnu mais non resolu est pire qu un mot inconnu : celui-ci serait refuse
a la validation, celui-la produit une porte grande ouverte qui a l air d un
flux precis.
LA CLASSE ENTIERE EST REFERMEE. Le defaut n etait pas propre a fabric :
toute paire nommant un ensemble et ne resolvant rien ouvrait le port.
Trouve en lisant les fichiers generes, l API de supervision d un tenant
etait ouverte a tous parce que pair: serveur_backup ne resout rien - cet
ecosysteme depose chez le site. expositions et externe, eux, veulent bien
dire tout le monde : c est une intention. Ailleurs, pas de source, pas de
regle, et le generateur le DIT.
Trois regles se referment, chacune verifiee AVANT d appliquer. Deux etaient
sans effet ; la troisieme portait Grafana, qui ecoute bien sur 3000. Sa
declaration disait pair: edge - juste chez un tenant, faux au site qui n a
pas d edge. Ajout de admin : ce qui etait accidentel devient explicite.
Et la mesure a montre autre chose : Grafana etait DEJA injoignable depuis
le poste, la frontiere ne laissant pas passer le 3000. Le site a une
console deployee et sans chemin d acces. Ce n est pas corrige ici, mais
c est dit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
La supervision du site voyait ses sept VM et rien d autre. Au depart, depuis
site-mon-01, les trois hyperviseurs, les neuf pattes de la frontiere et sa
PROPRE passerelle par defaut rendaient tous 100 pourcent de perte au ping.
16 hotes UP sur 16 dont 9 pattes de frontiere en controle ACTIF
11 cibles Prometheus dont 3 hyperviseurs, job fabric separe
LE PARTAGE. Les hyperviseurs portent node_exporter - D-48 l autorise - et
exposent 1005 unites systemd avec leur etat, soit ce que la sonde sante
mesurait, plus la charge et le disque. Ils n entrent PAS dans le socle :
leur appliquer serveur_durci reecrirait le pare-feu, le SSH et les sysctl
de la machine qui tient tout le reste. La frontiere, elle, n accueille
aucun agent : controle actif, une entree par PATTE, parce qu une interface
eteinte coupe une zone pendant que les autres vont bien.
ON TIRE, ON NE POUSSE PAS. J avais propose du passif et il avait ete
valide ; la mesure a dit non. Un hyperviseur envoie vers un routeur qui ne
connait pas les reseaux du site, et sa route par defaut est GELEE (D-57).
Le porteur de sante y expirait en 20 s.
LE VRAI DEFAUT ETAIT UNE LISTE QUI N A PAS SUIVI. Le mecanisme de routage
existait deja sur vmbr0, avec un commentaire du 2026-08-26 tenant
exactement le raisonnement qu on venait de refaire. Sa liste s arretait a
10.0.34.0/24 quand le site en declare six : les zones sauvegarde et
supervision sont nees, les routes n ont pas suivi. Le symptome ne
ressemblait pas a une route manquante - il ressemblait a un pare-feu, puis
a un probleme de reseau chez l exploitant.
make routes-fabric-etat compare desormais TROIS choses : zones declarees,
routes declarees dans /etc/network/interfaces, routes vivantes dans le
noyau. Le cas le plus traitre est vivante mais non declaree : tout
fonctionne, la supervision est verte, et la panne attend la prochaine
maintenance. Eprouvee dans les deux sens.
Deux defauts trouves en construisant. bifrost-2 est un nom RESERVE, pas un
boitier - l underlay le disait en prose, illisible par le moteur ; il porte
desormais etat: reserve. Et un service passif n existe que pour un hote qui
peut POUSSER : l appartenance a un groupe sert deux choses qui ne
coincident pas toujours, a qui l on deploie et de qui l on attend un
rapport.
Les commutateurs restent dehors, choix de l exploitant, coherent avec D-48.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Question de l exploitant : le modele vit sur vishnu, les clones sur asgard,
qu arriverait-il si vishnu tombait ? Mesuree, la reponse se coupe en deux.
LES DONNEES SURVIVENT. Le pool CephNVMe est en size=3 / min_size=2 avec des
OSD sur les trois hotes, et les images du gabarit y sont repliquees.
L image reste lisible avec un noeud en moins, et les quatorze VM d un
ecosysteme tournent ailleurs sans s apercevoir de rien.
LA REPRODUCTION, NON. La configuration du gabarit porte le nom du noeud
dans son chemin - /etc/pve/nodes/vishnu/qemu-server/9006.conf - et le
clonage appelle nodes/vishnu/... Noeud eteint, aucune VM nouvelle ne peut
naitre. Or la reproduction est ce que ce depot existe pour garantir.
La decision est d ASSUMER la dependance et de la rendre COURTE, pas de la
supprimer : depuis la migration du gabarit sur stockage partage ce matin,
la remise en route est un deplacement de fichier de configuration, sans
mouvement de donnees. Un benefice qu on n avait pas cherche : la migration
sur Ceph a raccourci une panne qu on n avait pas encore nommee.
Documentee en trois endroits, parce qu un seul ne suffit pas : D-88 pour
nommer la dependance, le runbook section 7 pour la manoeuvre et l ordre
des gestes, et le bloc gabarit du plan du site - c est la que l exploitant
lit noeud: vishnu.
Ce qui n est PAS fait et qui est dit : rien ne MESURE cette dependance.
gabarit_etat compare le declare au reel, il ne demande pas si le noeud du
gabarit heberge autre chose que le gabarit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
LA GARDE FICHIER ENTIER, en deux corrections. Un telechargement
interrompu laisse un fichier de zero octet QUI EXISTE, et toutes les gardes
demandaient seulement s il etait la. infra-mail-01 a garde une cle
smallstep de 0 octet apres l epreuve hors ligne.
La premiere correction n a pas suffi. Ajouter le controle de taille faisait
bien s executer la tache - et le fichier faisait toujours 0 octet au
passage suivant. get_url sur une destination existante emet une requete
CONDITIONNELLE : l amont repond non modifie, le module rend ok, la ruine
reste. Le play etait vert et ne reparait rien. Il faut effacer avant de
redemander.
Controle negatif : 0 -> 1022 octets, 0 erreur apt. Cinq roles.
LA SONDE CORRECTIFS, 23e. Set-OPS desarme unattended-upgrades et applique
les correctifs au deploiement - choix defendable, le verrou dpkg a fait
decrocher une machine d une reconstruction entiere le matin meme. Mais rien
ne disait QUAND le geste etait du : une flotte pouvait deriver des mois en
restant verte.
Elle mesure les paquets de securite en attente ET depuis quand. Elle ne
lance pas apt-get update - une sonde qui rafraichit l index toutes les
quinze minutes deviendrait la cause de la panne qu elle surveille. Et le
seuil de 72 h est un choix d exploitation, pas une derivation : le
mecanisme qui applique les correctifs est un geste humain.
P64 REFUSAIT UNE DECLARATION CORRECTE. serveur_debian et serveur_durci sont
des roles de declaration pure, sans une tache ; le travail est fait par les
roles que leur playbook applique. La preuve exigeait declaration et depot
dans le meme role - vrai des vingt-deux premieres sondes, faux des qu une
sonde appartient au socle. Une garde qui force a contourner ce qu elle
protege est un defaut. Elle suit desormais le playbook du groupe.
Mesure : 21/21 machines vertes, 65 preuves, 23 sondes, 0 echec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
get_url IGNORE la configuration d apt : le mandataire pose dans
/etc/apt/apt.conf.d/ ne vaut que pour apt. Les six cles de signature
sortaient donc TOUJOURS en direct, malgre tout le travail sur le remap. Un
trou reste ouvert derriere une porte qu on croyait fermee.
Et ce n etait pas theorique. Depuis collab-01 :
en direct grafana 200 collabora TIMEOUT
via le cache collabora 200
La route directe vers Collabora ne passe pas depuis cette zone. Trois cles
sur quatre avaient reussi PAR CHANCE, parce que leurs fournisseurs etaient
joignables. Le meme geste corrige les deux : plus rien ne sort, et la
machine qui n avait pas de route en trouve une.
POURQUOI SEULE UNE NAISSANCE POUVAIT LE MONTRER. Mes deploiements de
convergence rendaient failed=0 parce que les cles etaient DEJA sur disque
et que la tache etait sautee. Le defaut existait depuis le premier commit
du remap, invisible a tout deploiement sur une flotte existante. C est l
argument de la reconstruction depuis zero, applique a moi-meme.
Troisieme reconstruction : 32 minutes, un seul echec - celui-ci. Clonage
3 min 52, zero fatal dans le journal, 963 Mo servis par le cache contre
183 tires de l Internet, soit 81 pourcent servis localement.
Et la derive s est effacee toute seule : apt-cacher-ng tournait encore sur
forge-01 que plus aucun plan ne declarait. Je proposais de l arreter a la
main ; la reconstruction l a fait. Ce qui n est pas au plan n existe pas
apres une naissance.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Deux mouvements d une seule doctrine : le site fournit tout ce dont un
tenant a besoin pour venir au monde.
1. LES DEPOTS TIERS. Grafana, Icinga, Smallstep et Collabora ne publient
qu en HTTPS ; apt-cacher-ng ne relaie pas un tunnel, et le socle pose donc
Acquire::https::Proxy DIRECT. Chaque machine sortait elle-meme sur
Internet. Le cache declare desormais un Remap par fournisseur, et chaque
role demande en {{ ..._depot_schema }}:// - http des qu un cache est
declare, https sinon. Le TLS n est rompu nulle part : il est TERMINE au
cache, qui est notre machine, et l integrite vient des signatures.
avant : 4 fournisseurs en HTTPS direct, 14 machines sortant seules
apres : 0 source en HTTPS direct, 0 erreur apt sur 14 machines
Trois lecons. Le remap appartient au cache qui SORT : pose sur un cache
chaine, il tente le HTTPS a travers son amont et rend 503. apt_repository
AJOUTE au lieu de remplacer, donc l ancienne ligne https sortait toujours.
Et la liste des fournisseurs ne se devine pas - j en avais trois, l audit
en a revele un quatrieme.
2. LE CACHE DU TENANT. Sa ligne portait son propre retrait depuis toujours
- service MUTUALISABLE, un ecosysteme au premier age peut pointer sur celui
de son hote. Retiree. Ce qu on perd, dit franchement : plus de trafic
inter-zone et plus de charge sur site-cache-01, contre un service de moins
a poser, superviser et reproduire.
3. UN ROLE QU ON RETIRE DOIT DEFAIRE CE QU IL A FAIT. Le retrait a montre
que rien ne nettoie derriere. Le fichier apt visait un cache eteint en
ecrasant le plancher qui fonctionnait - le defaut deja paye a quinze
machines. Et les sondes du cache restaient, le porteur poussant pour des
services qu Icinga ne definit plus (404). Le socle retire le premier,
client_sante derive les sondes attendues et retire les orphelines.
P65 refuse tout role visant un depot relaye en https ecrit en dur. Sa
limite est dite : elle empeche une regression sur ce qui est connu, elle ne
decouvre pas l inconnu.
Mesure : Icinga 87 OK sur 96, prouver 65 OK, lint 0 defaut.
Reste, et c est dit : apt-cacher-ng tourne toujours sur forge-01 que plus
aucun plan ne declare.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Seconde reconstruction complete de Chezlepro dans la journee, pour
EPROUVER les quatre correctifs livres entre les deux. Rien de nouveau
n a ete construit : c est une mesure.
gabarit sur CephNVMe clonage 4 min 30 contre ~30 min
placement declare {asgard: 14} - les quatorze au bon endroit
hosts_statiques conditionne changed au 1er passage, skipping au 2e
monitoring-plugins au role ping4 14/14 OK sur une mon-01 nee neuve
Le troisieme est le plus instructif : les DEUX branches sont exercees dans
la meme execution. infra-pki-01 recoit le gabarit maitre de cloud-init au
premier passage, puis la tache est sautee au second, le durcissement
l ayant retire. Aucune preuve statique ne pouvait montrer cela - il fallait
une naissance.
Le facteur mesure est 6,6 et non 45 : un clone isole prend 8 s, mais quatre
clones se disputent le pool et le redimensionnement du disque s ajoute. On
retient la mesure en conditions reelles, celle qu on paie.
Des trois echecs du matin il ne reste rien. Le verrou dpkg ne s est pas
reproduit - c etait une course, et rien ne dit qu elle ne reviendra pas.
Et le cache apt N ETAIT PAS un defaut : les deux seuls fatal de cette
execution sont suivis de ...ignoring, ce sont les sondes de
client_artefacts qui laissent la machine servie par le plancher du SITE.
C est la filiation en train de fonctionner. Le matin, j avais compte ces
deux lignes comme des echecs sans lire la suivante.
Icinga : 89 OK, 9 UNKNOWN sur 98, aucun WARNING, aucun CRITICAL. Les neuf
sont tous des sauvegarde dont le minuteur nocturne n a pas encore visite
une flotte nee il y a vingt minutes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Le role pose /etc/cloud/templates/hosts.debian.tmpl - le gabarit maitre
dont cloud-init regenere /etc/hosts au demarrage. Or D-85 fait retirer
cloud-init par serveur_durci, et le repertoire part avec lui.
L echec n avait aucun sens : ce gabarit ne sert qu a survivre a une
reecriture qui n a plus lieu. Plus de cloud-init, plus de reecriture, le
plancher tient tout seul - c est le resultat recherche par D-85.
CE QUE CA A COUTE. _amorcer-socle monte infra-pki-01 et infra-dns-01 en
entier d abord, durcissement compris. La tache echouait au second passage,
l hote sortait du play, et TOUT ce qui suivait n etait jamais pose - dont
icinga-ca.crt. Leur porteur de sante tournait ensuite normalement et chaque
rapport echouait sur curl: (77), en silence. Un echec bruyant au bon
endroit avait produit une panne muette ailleurs.
Et sauter la tache seule aurait deplace l echec d un cran : la garde qui
suit compare le nombre d entrees du plancher a celui du gabarit, donc 21
contre 0. Elle accuserait une divergence la ou il ne reste qu un fichier.
Une garde qui survit a ce qu elle gardait ne mesure plus rien : elle
invente. Les trois taches suivent desormais la meme condition.
Verifie sur les deux machines memes qui echouaient : failed=0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Quatorze machines detruites, quatorze refaites. 1 h 08, 0 injoignable.
D-86 TIENT, et la mesure le dit : 30 resultats de controle recus a
12:20:41 alors que la reconstruction ne s est terminee qu a 12:35:29.
Trente services rapportaient leur etat pendant que Keycloak, Forgejo et
Nextcloud montaient encore.
Sa limite, dite franchement : D-86 affirme que le DNS peut rester en
couche 6 grace au plancher /etc/hosts. Or _amorcer-socle monte
infra-dns-01 EN ENTIER d abord. Le DNS etait debout, le plancher n a rien
eu a porter, et la partie la plus audacieuse de la decision reste non
testee.
LE PLACEMENT DES VM N ETAIT DECLARE NULLE PART. Les quatorze vivaient sur
asgard depuis toujours, mais SETOPS_NOEUD valait le vide : ce placement
n existait que dans l etat d execution de Proxmox. Sans cible, le clone
reste sur le noeud du gabarit - vishnu, qui a 14 Go libres et heberge
eregion et site-forge-01. Le defaut avait survecu a la reconstruction du
2026-09-02 parce que les VM existaient deja et que le clone les sautait.
Il faut un from-zero VRAI pour voir ce genre de chose.
LE CLONAGE ETAIT 45 FOIS TROP LENT, et pas a cause du reseau : source et
destination etaient sur le meme stockage. C est le LVM epais qui interdit
a Proxmox tout clone autre que complet. Gabarit deplace sur CephNVMe,
mesure 480 s -> 8 s. On garde les clones complets : le clone lie descend
a 1 s mais enchaine chaque VM a l image de base pour toujours.
Un champ stockage: entre au gabarit, branche en quatre points - declare,
expose, consomme par le Makefile, garde par gabarit_etat. Declarer sans
consommer, c est decorer.
ICINGA NE POUVAIT PAS FAIRE SES PROPRES CONTROLES : icinga2 n apporte
aucun greffon, et la supervision etant passive, le manque etait masque.
Quatorze ping4 muets d une seule cause. monitoring-plugins-basic entre au
role. Le site l avait deja - pose A LA MAIN, jamais declare : troisieme
occurrence du jour d un etat qui ne survivrait pas a une reconstruction.
Trois defauts laisses ouverts : le cache apt attendu pendant l amorcage,
la regression D-85 sur /etc/cloud - qui a fait decrocher deux hotes de la
tache deposant icinga-ca.crt, rendant leurs sondes muettes en silence - et
auditd sans regles dans le gabarit.
Mesure finale : Icinga 93 OK sur 98, site 51/51, Prometheus 15/15,
prouver 64 OK, lint 0 defaut. Les quatre non-OK restants sont des
sauvegarde dont le minuteur nocturne n a pas encore visite une flotte nee
il y a deux heures.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
Application de ce que l entree precedente avait prepare : 49 regles creees,
5 retirees. Cibles Prometheus 2/8 -> 8/8, hotes dans Loki 1/7 -> 7/7.
Puis correction de ce que l application a revele. Cinq defauts, tous de la
meme famille : un reglage qui ne suit pas l interrupteur dont il depend.
- la sonde de Loki interrogeait en HTTPS un Loki servant en clair ;
- la sonde de la forge visait http:// sur un port 443 chiffre, puis
validait un certificat emis pour le FQDN en interrogeant 127.0.0.1 ;
- la sonde du runner comparait six depots a UNE branche quand le plan en
declare une par depot. Elle contredisait la declaration qu elle etait
censee verifier : elle n accusait pas la machine, elle s accusait
elle-meme.
Le tenant restait juste dans les cinq cas. C est le site, qui deploie ces
roles autrement, qui les a tous reveles d un coup.
La sonde des journaux, elle, avait deux defauts a la naissance. Elle criait
une perte deja reparee, faute de dire sur QUELLE fenetre - un ecart sans sa
fenetre n est pas une mesure, c est un nombre. Et elle alertait sur la
cicatrice plutot que sur la plaie : le compteur d Alloy est cumulatif, donc
six machines restaient orange pour toujours. Ce qui alerte est desormais la
CROISSANCE. En echange, un cas muet leve maintenant : zero envoi et zero
rejet n est pas la sante, c est un agent qui ne fait rien.
Enfin, le runner ne pouvait plus cloner le genome. Defaut PREEXISTANT,
revele par le redeploiement et non cause par lui - le diff des regles
generees le montre. generer_nftables(site=True) lisait le plan du TENANT :
derive se resolvait donc a 3000, le port que Forgejo ecoute derriere un
edge, alors que le plan du site dit 443 et explique pourquoi. La forge
ouvrait un port que personne n ecoute et laissait 443 ferme a toute la
flotte.
Mesure finale : Icinga 51/51, Prometheus 8/8, Loki 7/7, prouver 64 OK,
lint 0 defaut sur 82 fichiers. Controles negatifs sur des COPIES des
sondes : les quatre rendent CRITICAL.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
D-87 disait que l hebergeur n a pas le droit de voir les journaux de ses
locataires. La decision avait une face cachee : a force de refuser de voir
ceux des autres, le site s etait prive des siens. Ses sept machines
n expediaient nulle part.
Il prend donc sa propre pile : prometheus, loki et grafana sur site-mon-01,
sans aucun lien avec ceux d un tenant. L exemption qui bloquait portait sa
propre condition de levee, ecrite cinq jours plus tot dans le plan.
Grafana au site n a pas de SSO, et le role l ignorait : il reclamait l IdP
avant de regarder s il en voulait un. L interrupteur existait, il n etait
pas honore. Le role refuse desormais SSO eteint ET formulaire local eteint
- la combinaison deploie un Grafana en sante ou personne ne peut entrer -
et le reglage du formulaire sort du if du SSO, ou il disparaissait en
laissant le defaut amont decider en silence.
Deux manques se cachaient l un l autre dans le devis de la frontiere, et
Prometheus voyait 1 cible sur 7 :
- le devis derivait les groupes d une machine du site de applications.yml
seul, et ne voyait donc aucune integration universelle - alors que
client_metrique ouvre un port d ecoute ;
- une sortie vers un role du site visait !SETOPS_INTERNES, qui exclut
precisement la machine nommee. Le devis autorisait a expedier les
journaux du site a n importe quel Loki du monde, et a nul autre endroit
qu a celui-la. Neuf flux dans ce cas.
Et deux declarations justes ne font qu une regle : appliquer_opnsense pose
tout en direction: in (D-61).
Les deux agents se supervisent enfin eux-memes. La sonde des journaux ne
demande pas si Alloy tourne, elle lit ce qu il a du JETER. Elle a fait ses
preuves le jour meme : Alloy actif, /-/ready a 200, et cinquante lignes
perdues sur six machines.
Mesure : metriques 7/7 vert, journaux 1/7 - les six autres attendent la
regle de frontiere, et le disent. prouver 64 OK, ansible-lint 0 defaut.
Reste a la main de l exploitant : make frontiere-appliquer CONFIRMER=true,
et le secret vault_grafana_admin a deposer dans underlay.vault.yml.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q