286 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| bd0e40753b |
memoire : ce que l hote a le droit de reprendre, et pourquoi il ne le pouvait pas
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 |
|||
| 94bfa224ff |
gabarit dore : une seule declaration, et les deux souches se rejoignent
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 |
|||
| a154893fc1 |
restauration : lire aussi l archive en clair, pas seulement la chiffree
`--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
|
|||
| 025776064a |
intrants du site : ce qu un locataire doit savoir pour l habiter, derive
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 |
|||
| b4e3520561 |
annuaire : un compte de service par consommateur, et la porte se ferme
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 |
|||
| db4223904d |
pools : le genome ne nait plus chez un locataire
`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
|
|||
| 5812e0c6ca |
depot de binaires : le site tient ce que les runners allaient chercher
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 |
|||
| 56d202a8bb |
pools nommes comme les depots, et les cles sortent du poste
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 |
|||
| b9b0d87db2 |
trois reconstructions : trouver, verifier, prouver — 37 min 24 au tour 3
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 |
|||
| bef0655112 |
le site reconstruit depuis zero : 7/7, 0 echec, et seize corrections
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 |
|||
| 0c55aafc40 |
le site prend l index 37, et la capacite de le raser existe enfin
SITE-Chezlepro passe de 10.0.31-36 (tapes a la main, derives de rien) et 10.17.0.0/24 (emprunte au supernet du locataire) a son PROPRE index : gestion en 10.37.0.0/24, zones en 10.37.31-36. OPS-Chezlepro garde 17. CE QUE L OPERATION A REVELE. Il n existait aucun moyen de raser le site : raser.py ne vise que l instance active, un locataire. Ce n est donc pas que personne n avait essaye de le reconstruire depuis zero — l outil n en offrait pas le moyen, et la limite se lisait partout sans que sa cause soit nommee. make site-raser reprend les quatre verrous de raser.py. TROIS FOIS LE MEME DEFAUT, attrape par l exploitant. La declaration decrit la CIBLE pendant que l outillage s en sert pour joindre l EXISTANT : renumeroter le rebond avant de bouger la patte a rendu le site injoignable. Regle posee : le renumerotage declaratif vient APRES la derniere operation qui a besoin de l ancienne infrastructure. nftables_admin_ssh etait une liste a la main qui devait suivre le plan d administration. Elle a pris du retard le jour meme. Le plan de frontiere n a propose AUCUNE creation ni suppression de regle — seulement douze contenus d alias. Les regles visent des alias par leur nom : un renumerotage complet se reduit a changer ce que les noms designent. Routes des trois hyperviseurs refaites, declarees ET vives, avec sauvegarde de /etc/network/interfaces. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q |
|||
| 5419ee2d71 |
un site prend son propre index, et la garde les compte enfin
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 |
|||
| 6786d15068 |
l heure vient de la frontiere : la derniere dependance vivante tombe
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 |
|||
| 989398f3cf |
expositions-etat : le certificat SERVI, pas celui du disque
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 |
|||
| 1b89e83b0c |
reconstruction a froid : les noms derives naissent justes, et une cle vide tombe
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 |
|||
| d1ae41cfdf |
nom public : il vient du plan, plus de la devinette du role
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 |
|||
| 2450c9ea65 |
observatoire : un seul nom pour la console, des deux cotes
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 |
|||
| c733d2df1c |
la frontiere journalise a nouveau, et une garde veille cette fois
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 |
|||
| 0778979b89 |
une source vide n est pas « tout le monde »
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 |
|||
| 5abf20102d |
le site surveille enfin sa fabric
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 |
|||
| a60b69f072 |
un fichier vide existe, et une sonde pour les correctifs
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 |
|||
| c6a7150c60 |
les depots tiers passent par le cache, et le tenant n a plus le sien
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
|
|||
| 4ef3a1d553 |
D-86 mis a l epreuve : Chezlepro rasee et refaite depuis zero
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 |
|||
| 84b5ecc71d |
frontiere posee, et cinq sondes qui disaient faux
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
|
|||
| f2c580235d |
observabilite : le site cesse de ne rien voir de lui-meme
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
|
|||
| 5b423cf954 |
correction : le PMTUD du site n etait pas casse, il etait non protege
J ai ecrit il y a une heure que la panne PMTUD « etait la, silencieuse, sur les sept machines de l hebergeur ». La mesure ne le soutient pas : site-mon-01 -> autre zone du site : MTU de chemin 1500 site-mon-01 -> Internet : MTU de chemin 1500 ops-01 (tenant, overlay EVPN) : MTU 1450, chemin vers Internet 1450 Le site est a 1500 de bout en bout. Aucun lien du chemin ne plafonne plus bas, donc aucun message « fragmentation necessaire » n avait lieu d etre emis, donc rien n etait casse entre zones du site. La contrainte a 1450 vit chez les TENANTS, sur l overlay — pas chez l hebergeur. Les six regles restent un vrai manque : elles couvrent le site parlant vers l EXTERIEUR, ou un correspondant distant peut plafonner plus bas, et elles seraient necessaires si une zone du site passait sur l overlay. Mais c etait une PROTECTION ABSENTE, pas une panne active. Decrire l un comme l autre est l exageration que ce depot ne doit pas contenir : une correction qu on ne mesure pas se raconte toujours plus grande qu elle n est. La correction est portee au CHANGELOG et dans le commentaire de devis_opnsense.py, la ou on la relira. Ce qui reste vrai et mesure : l Icinga du site tenait 6 de ses 7 machines pour mortes, et 7/7 apres. make prouver : CONFORME, 64 OK, 0 echec, 0 saute. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q |
|||
| 843d39e7aa |
frontiere : un type ICMP n est pas un port symbolique
LA CAUSE EXACTE. devis_opnsense traitait tout `port` non numerique comme SYMBOLIQUE, a resoudre par le plan. Vrai pour `derive`, le port d un service que seul le plan connait. FAUX pour l ICMP : echo-request et frag-needed sont des litteraux. Ils tombaient dans la branche « le plan ne resout pas » et aucune regle n etait emise. Une ligne de condition, et le silence de toute une flotte. CE QUE LA CORRECTION A REVELE EN PLUS. Huit regles a creer, zero a retirer — et SIX sont du PMTUD entre zones du site, absent pour la meme raison. Le depot dit de ces messages : bloques, la connexion s etablit, les petites requetes passent et les grosses reponses restent suspendues — la panne la plus couteuse a diagnostiquer. Elle etait la, silencieuse. CE QUE LA REGLE AUTORISE, EXACTEMENT. appliquer_opnsense n envoie destination_port que pour TCP et UDP : une regle ICMP ouvre le PROTOCOLE entre deux pairs, pas le seul type. Le type reste porte par la regle d HOTE, que resoudre_flux emet precisement. La frontiere dit qui peut parler a qui, l hote dit ce qu il accepte d entendre. Emettre un icmptype a la frontiere aurait demande de traduire frag-needed dans le vocabulaire de pf, au risque de casser le PMTUD pour gagner de la precision sur une barriere qui n est pas la derniere. MESURE APRES APPLICATION : ping site-mon-01 -> les six autres zones : 6/6 repondent hotes UP : 1/7 -> 7/7 | ping4 : 1/7 -> 7/7 | certificat 7/7 | sante 7/7 tenant inchange : 14/14 make prouver : CONFORME, 64 OK, 0 echec, 0 saute. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q |
|||
| a070c339ee |
icinga : l hote de supervision saturait par sa propre demonstration
« mon-01 tape dans l fond. » Il tapait : load 5,10 sur 4 coeurs, 8 processus check_disk a 70-99 % de CPU chacun, jusqu a 28 minutes de vie. check_disk 2.4.0-3+deb13u1 ne rend jamais la main sur cet hote (etat R). Icinga en relancait un a chaque intervalle pour le service `disk` de son hote de DEMONSTRATION, et aucun ne mourait. RETIRE : conf.d/hosts.conf, l hote NodeName livre par le paquet. Les apply Service s y accrochaient — disk, http, swap, apt, load, procs, users — et trois etaient rouges en permanence (swap sur une VM sans swap, http sur un port ou rien n ecoute, apt pour un paquet). On retire l HOTE et non les services : sans lui les apply ne s accrochent a rien, et on ne touche pas a un fichier que le paquet remplacera. Ca garde ping4, qui vise nos hotes et sert vraiment. avant : load 5,10 — 8 check_disk — 3 alarmes rouges permanentes apres : load 0,77 — 0 check_disk — certificat 14/14, sante 14/14, ping4 14/14 TROUVE EN VERIFIANT : l Icinga du SITE tenait 6 de ses 7 machines pour MORTES (1/7 UP, contre 14/14 au tenant). hostalive est un ping, le site est decoupe en zones, et l ICMP inter-zones n etait declare nulle part — 100 % de perte, mesure. Or Icinga SUPPRIME les notifications des services d un hote DOWN : une supervision qui croit tout mort n alerte plus de rien, tout en ayant l air de fonctionner. Le flux est declare des DEUX cotes, et le registre a refuse la premiere moitie seule — exactement sa raison d etre. CODES_ICMP apprend echo-request. Regles d hote posees sur les 21 machines. RESTE OUVERT : le generateur de la frontiere ne sait pas traduire un TYPE ICMP pour un pair INTERNE — il le note et n emet rien. Le site reste a 1/7. Corriger devis_opnsense.py est le prochain geste. make prouver : CONFORME, 64 OK, 0 echec, 0 saute. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q |
|||
| 90228cb55e |
supervision : la sonde se declare dans le role, comme le flux
LE CONSTAT. 39 roles declarent leurs flux, 32 leur empreinte, 32 leur authentification — tous derives. Et 19 groupes sur 19 declaraient une surveillance en prose que RIEN n executait ; Icinga en surveillait deux. La carte disait ce qui etait surveille, et personne ne surveillait. LE MECANISME. Un role declare ses sondes dans meta/supervision.yml et depose lui-meme son script dans /usr/local/lib/setops/sondes/. Le porteur client_sante les fait toutes tourner et pousse un resultat passif par sonde, sans savoir ce qu elles mesurent. serveur_icinga derive les objets Service ET le filtre de permission d API des memes declarations. Ajouter une sonde ne demande de toucher ni au porteur ni a Icinga. PREMIERE SONDE : client_pki/certificat. Heures restantes sur le certificat reellement pose, chaine verifiee, et empreinte SERVIE comparee au disque quand un service le consomme. 14/14 au tenant, 7/7 au site. QUATRE OBSTACLES, ET TROIS SONT LA MEME LECON. La sonde a rendu 14/14 en CRITIQUE sur une PKI saine : openssl verify -CAfile racine ne trouve pas l intermediaire qui signe nos certificats. step certificate verify, lui, repond VALIDE. Deployee au site, elle a rendu 5/7 : le seuil d avertissement (12 h) etait AU-DESSUS du point de renouvellement (8 h, le tiers restant). Elle criait avant que le mecanisme ne soit cense agir. Seuils ramenes a 6 h et 3 h. Un seuil se DERIVE du moment ou le mecanisme surveille agit. Une alarme toujours allumee ne vaut pas mieux qu une alarme jamais allumee : elle apprend a ne plus regarder. Une sonde se prouve DEUX FOIS, verte sur le sain et rouge sur le casse. Le filtre d API etait ecrit avant la lecture des declarations : les services auraient existe et Icinga aurait refuse leurs resultats. Et mon controle negatif a casse un service reel : substituer le certificat d hote a fait propager un cert sans sa clef vers node_exporter. Un controle negatif se fait sur une COPIE. P64 tient les deux bouts : declaree sans etre deposee, ou deposee sans etre declaree. Trois controles negatifs rejoues. make prouver : CONFORME, 64 OK, 0 echec, 0 saute. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q |
|||
| 53d7b4c4c2 |
durcissement : cloud-init nait avec la VM et ne lui survit pas
cloud-init n est pas un logiciel d installation : c est une SOURCE DE VERITE EXTERNE. Il se reveille a chaque demarrage et relit le lecteur attache par l hyperviseur, qui peut redefinir comptes, cles SSH, mots de passe et reseau. Sur une machine que le plan possede, c est un second maitre — que le plan ne decrit pas, que make valider ne mesure pas, et qui parle en premier. Sa tache est finie a la premiere seconde : c est parce qu il a REUSSI a poser l adresse et les cles qu Ansible a pu entrer. TROIS MOITIES, ET ELLES SE DEFONT SEPAREMENT. - le GABARIT le garde : sans lui un clone n a ni adresse ni nom ; - le SOCLE ne l installe plus : le garder produisait un va-et-vient a chaque deploiement, deux changed par passage, idempotence perdue ; - le DURCISSEMENT le retire (roles/cloud_init_retrait, en dernier). P63 garde les trois, plus le CONTENU du role : une coquille vide passerait les trois premiers controles sans rien fermer. Quatre controles negatifs rejoues. CE QUI REND LE RETRAIT SUR EST MESURE, PAS SUPPOSE (obs-01, 2026-09-09) : /etc/network/interfaces.d/50-cloud-init n appartient a aucun paquet — dpkg -S ne le trouve pas — et le postrm ne le nomme jamais, meme en purge. L adresse survit. Le role le verifie quand meme, avant et apres, et n accuse que si le retrait l a emporte : une VM qui perd ce fichier ne se plaint pas, elle repart sans adresse et plus personne ne peut entrer. DEUX CHOIX DITS FRANCHEMENT. cloud-guest-utils reste (growpart : ni service, ni port, ni source de donnees). Les ~29 paquets orphelins ne sont pas retires par defaut : autoremove deciderait a partir des drapeaux dpkg, et un durcissement ne doit pas pouvoir surprendre. NON DEPLOYE : le code est ecrit, valide et prouve ; il n a pas ete applique a la flotte. Essai a blanc sur obs-01 : cloud-init a retirer, configuration reseau intacte. make prouver : CONFORME, 62 OK, 0 echec, 1 saute (63 preuves). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q |
|||
| 2887b57f0c |
GUI : les six registres ont un formulaire genere, et la sauvegarde aussi
CHAMPS_ECRITS_A_LA_MAIN est vide. Serveurs et applications, les deux plus gros, sont passes au generateur — chargement, rendu et sauvegarde. L EPREUVE QUI COMPTE. Ouvrir chaque vue et enregistrer sans rien toucher doit renvoyer exactement le plan qu on vient de lire : 14 serveurs, 25 applications, 2 domaines, 4 bases, IDENTIQUE partout. C est ce qui separe un formulaire genere d un formulaire qui en a l air — un champ visible a l ecran et perdu en silence a l enregistrement serait le pire des deux mondes. test_rendu_gui.py le mesure a chaque make prouver. TROIS DEFAUTS TROUVES EN CHEMIN. Le formulaire annoncait des defauts INVENTES : 2048 Mo, 2 coeurs, 16G. Il n existe aucun defaut fixe — deriver_ressources calcule depuis les roles portes (1024 et 1 pour infra-pki-01, 5632 et 4 pour collab-01). Un repere faux fait croire qu on connait la valeur. Le schema nomme le champ derive, et l ecran montre la valeur reelle de cet hote. L option vide d un select dit desormais ce qu elle produira : « (defaut : asgard) ». Une SECONDE occurrence du defaut d hier dormait dans sourceDeValeurs : elle lisait encore data.nomenclature. Elle n avait jamais leve parce que la vue Serveurs, seule a emprunter cette source, avait un formulaire ecrit a la main. Elle a leve a la seconde ou le generateur l a prise. Le banc ne voit que les chemins vivants : verifier_gui.py fait donc aussi une verification STATIQUE, qui voit ce qui dort. La validation client s accrochait a data-v, pose a la main sur trois champs. Le formulaire genere l aurait perdu et la validation serait passee au vert sur ZERO champ. Le generateur marque chaque controle, et la sauvegarde refuse si elle n en inspecte aucun. DEUX CHAMPS GARDENT LEUR EDITEUR, et le schema le dit (x-editeur) : la matrice des integrations montre les universelles et les exemptions, et l editeur de liens contraint le role a meta/liens.yml. Le generateur s efface plutot que de remplacer un editeur qui en sait plus que lui. LIMITE : je n ai toujours pas ouvert ces pages dans un navigateur. make prouver : CONFORME, 61 OK, 0 echec, 1 saute. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q |
|||
| 935a64a1bf |
plan : sauvegarder n emportait plus quarante lignes de commentaire
En voulant generer deux formulaires de plus, j ai trouve pire que ce que
je cherchais.
CE QUI ETAIT DEJA LA. Les quatre ecrivains de registre ecrasaient le
fichier au safe_dump. Mesure sur les fichiers reels : domaines.yml 6->3,
applications.yml 27->5, serveurs.yml 18->3. Quarante lignes, detruites
par n importe quel clic sur Sauvegarder dans les vues Serveurs,
Applications ou Domaines. Parmi elles, celle qui explique pourquoi
backup-01 a ete retire, et celle qui dit dans quel ordre les deux roles
du runner s appliquent. C etait l incident du 2026-08-18, jamais corrige
pour les registres du plan. Les quatre passent par _ecrire_registre :
aller-retour a vide identique a l octet, sur les quatre fichiers.
TROIS ECARTS DE SCHEMA, trouves en confrontant le schema aux VALIDATEURS
et non aux seuls plans :
- edge designe un GROUPE, pas un hote. Le schema disait serveurs : un
formulaire genere aurait offert une valeur qu aucun hote ne reconnait,
donc aucun SAN, donc la panne du 2026-08-25 reintroduite ;
- exposition, entierement valide par le moteur, manquait au schema ;
- liens etait items: {type: object} — une liste d objets sans forme.
Et mail, offert par la vue Domaines depuis sa creation, decrit ici comme
un booleen, saisi la-bas comme du texte, lu par rien : retire.
P62 garde tout ca. Elle separe l entite du reste mecaniquement : un
validateur lit son entite par des variables LOCALES, les autres registres
par ses PARAMETRES. Controle negatif rejoue.
LES FORMULAIRES. Serveurs de BD et Domaines sont generes, chargement et
sauvegarde compris. Quatre registres sur six. Le generateur a appris la
liste d objets.
LIMITE : restent serveurs et applications, les deux plus gros ; et je n ai
toujours pas ouvert ces pages dans un navigateur.
make prouver : CONFORME, 61 OK, 0 echec, 1 saute (62 preuves).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
|
|||
| 88033f37b8 |
GUI : la vue Nomenclature, et deux fautes que mes bancs ne voyaient pas
Some checks are pending
verifier / verifier (push) Waiting to run
LA VUE. La nomenclature etait le seul registre que le GUI ne savait pas ecrire du tout : ajouter une fonction exigeait d ouvrir le YAML. Elle a sa vue, et son formulaire est GENERE depuis le schema. Deuxieme registre sur six. couverture_gui verifier passe : les 28 champs des plans reels sont editables. Elle n est pas un registre comme les autres : elle decrit la REGLE dont VMID, VLAN, adresse et passerelle se derivent. Chaque fonction montre ce qu elle derive et les VM qui la portent ; l index est montre mais pas editable, parce qu il est alloue par le site ; valider_nomenclature refuse de retirer une fonction encore portee, ou de designer une zone non declaree. DEUX FAUTES, ET POURQUOI MES BANCS NE LES VOYAIENT PAS. Le formulaire des bases, livre la veille, etait casse dans un navigateur. Il lisait data.schema, or il n existe aucun data global : c est une const locale de charger(). ReferenceError a l ouverture, et zone morte dans sauvegarderBases. Je l avais eprouve sous node EN LUI PASSANT data : le banc reproduisait la fonction, pas sa portee. D ou test_rendu_gui.py, qui charge le JS entier dans un DOM simule et dessine les douze vues, avec son controle negatif. Le schema decrivait reservations comme une table de zones ; le fichier reel est un bloc plat. P61 comparait des NOMS aplatis, donc ne voyait rien. Elle compare desormais aussi la FORME. ECRIRE SANS DEPLACER UN COMMENTAIRE. _fusion_chirurgicale remplace le bloc entier des qu une valeur change : quinze entrees compactes devenaient 42 lignes, et le commentaire du poste d exploitation se retrouvait en tete du bloc, ou il affirmait que collab etait le poste d exploitation. Un commentaire deplace n est pas laid, il est faux. _fusion_table edite les tables ligne a ligne ; le diff fait trois lignes. Au passage : sort_keys triait le schema, donc l ordre des cases a l ecran (reserve_max avant reserve_min) ; et _ecrire_index_nomenclature ecrivait encore par write_text, oubliee au passage des ecritures atomiques. LIMITE : deux registres sur six sont generes, et je n ai toujours pas ouvert cette page dans un navigateur. make prouver : CONFORME, 60 OK, 0 echec, 1 saute. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q |
|||
| 34b7ec3886 |
schema : le marqueur du champ requis, et l entree de CHANGELOG qui manquait
Some checks are pending
verifier / verifier (push) Waiting to run
Deux dettes des commits |
|||
| 03c628d5e1 |
GUI : le formulaire des bases est GENERE depuis le schema
Etape 3, sur un seul registre — `bases_donnees`, le plus simple et le seul ou observe et editable coincidaient deja. Les cinq autres gardent leurs formulaires ecrits a la main : on ne bascule pas six vues d un coup. CE QUI DISPARAIT DU JAVASCRIPT Huit `<label>` en dur, trois constructions de `<option>`, et la regle qui choisissait la source du consommateur selon la portee. Cette derniere ne vivait que dans le JS ; elle est desormais DECLAREE au schema (`x-source-selon`), donc lisible et gardee. Le formulaire rend exactement les memes huit champs qu avant — verifie en EXECUTANT le moteur sous node avec le schema et des donnees reelles, pas seulement en passant `node --check`. LA BOUCLE EST FERMEE DES DEUX COTES Le chemin de SAUVEGARDE enumerait lui aussi les sept champs en dur. Un champ ajoute au registre serait apparu au formulaire genere et aurait disparu SILENCIEUSEMENT a l enregistrement — le pire des deux mondes. Il derive maintenant du schema, valeurs par defaut comprises (`default`). LA SEPARATION FORME / COHERENCE, MONTREE portee=groupe + consommateur APPLICATION -> REFUSE par valider_bases portee=application + consommateur app -> ACCEPTE secret absent -> REFUSE Le schema a rempli la FORME (les defauts `groupe` et `principale` se sont poses), le validateur a attrape l INCOHERENCE. Aucune de ces trois regles ne s exprime en JSON Schema, et vouloir l y mettre creerait la seconde source de verite que ce depot refuse. CHAMPS_ECRITS_PAR_GUI COMMENCE A DISPARAITRE Renomme CHAMPS_ECRITS_A_LA_MAIN, et `bases_donnees` en est SORTIE : sa couverture se derive du schema. P19 lit desormais `champs_ecrits_par_gui()`, qui reunit les deux. Le jour ou la table sera vide, elle gardera un mecanisme au lieu d une liste. UNE GARDE A CORRIGER AU PASSAGE `declaration_derive()` verifiait que chaque champ declare apparait dans le SOURCE du GUI. Pour un registre genere il n y apparait plus — c est le but. Elle aurait crie sur precisement le progres qu elle devait constater. Les registres generes en sont exemptes : c est P61 qui tient la promesse pour eux. make prouver : CONFORME, 60 OK, 0 echec, 1 saute. P07 (node --check), P19 (couverture), P61 (schema) : verts. Reste : les cinq autres vues, et le trou de la nomenclature — que le passage au generateur fermera par construction, puisque le schema decrit deja `categorie` et `service`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q |
|||
| 0eaceb1048 |
schema du plan : la forme des registres devient derivee, et gardee
Etape 2 du chantier « l UI reflete fidelement la structure ». Le GUI porte CHAMPS_ECRITS_PAR_GUI, une liste tenue A LA MAIN de ce qu il sait ecrire, que P19 confronte au reel. C est une copie — gardee, donc honnete, mais une copie : quelqu un doit penser a l allonger. `make schema` produit docs/audit/schema-plan.json : six registres, 42 champs, leurs types, leurs enumerations et ce qui est requis. CE QUE LE SCHEMA EST, ET CE QU IL N EST PAS schema -> la FORME -> generera les champs du formulaire validateurs -> la COHERENCE -> refusent une saisie incoherente Un JSON Schema ne sait pas dire qu un `consommateur` designe une application inexistante, ni qu une integration universelle recopiee au plan est un defaut. Vouloir l y mettre creerait la seconde source de verite que tout ce depot refuse. Les valider_* restent l autorite. LES ENUMERATIONS SONT IMPORTEES, JAMAIS RECOPIEES ETATS_SERVEUR, PORTEES_BD et AUTORITES_DNS viennent des constantes que les validateurs appliquent. Une enumeration recopiee diverge — c est la lecon des neuf resolutions d instance que P41 garde depuis. CE QUE L ETAPE 1 AVAIT TROUVE, ET QUE P61 A CONFIRME Le recensement montrait `categorie` et `service` presents dans TOUS les plans et absents de CHAMPS_ECRITS_PAR_GUI, dont la ligne `nomenclature` est vide : le GUI ne sait pas les editer, l operateur doit ouvrir le YAML. P61 a refuse le premier schema pour cette raison exacte. Les trois tables imbriquees de la nomenclature sont donc DECRITES et non resumees en « object ». 31 champs observes dans l instance courante, 42 decrits par le schema. La difference n est pas du bavardage : observer une instance n est pas un schema. `noeud`, `stockage` et `coeurs` sont legitimes et simplement inutilises ici — un schema derive de l observation les INTERDIRAIT. P61, EPROUVEE DANS LES DEUX SENS fichier genere perime -> REFUSE champ du plan absent du schema -> REFUSE champ decrit mais inutilise au plan -> COMPTE, pas refuse Le troisieme point est delibere : refuser obligerait a retirer du schema un champ valide des que plus personne ne s en sert. Meme mesure que les lacunes nommees de P29. UN DEFAUT DE MON INSTRUMENT, PAYE EN ROUTE P61 comparait des noms a plat quand couverture_gui aplatit les tables imbriquees : elle criait sur un schema correct. L instrument mesurait autre chose que la cible. On aplatit desormais des deux cotes. make prouver : CONFORME, 60 OK, 0 echec, 1 saute. Prochaine etape : generer les formulaires depuis ce schema, et retirer CHAMPS_ECRITS_PAR_GUI. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q |
|||
| 6077b179af |
plan : l ecriture des registres devient atomique — tout, ou rien
Some checks are pending
verifier / verifier (push) Waiting to run
`path.open("w")` TRONQUE avant d ecrire : entre les deux, le fichier est vide.
Une exception dans yaml.safe_dump, un disque plein, un Ctrl-C, et
instance/plan/serveurs.yml reste mutile.
L asymetrie fait la gravite : hosts.yml se regenere d un
make instancier-appliquer, le PLAN ne se regenere de rien. C est la source
unique de verite. Git est le filet, mais encore faut-il savoir qu on est tombe.
TREIZE SITES, UNE SEULE FONCTION
Le defaut n etait pas dans le GUI seul : douze sites dans sept fichiers, dont
les miroirs CLI des MEMES registres. Corriger le GUI seul aurait recree la
divergence que P41 garde depuis les neuf resolutions d instance. La fonction
vit donc dans inventory_rules.py, que les sept importaient deja. Une source,
pas douze.
TROIS DETAILS QUI FONT LA DIFFERENCE ENTRE « CA MARCHE » ET « CA TIENT »
temporaire dans le MEME dossier os.replace n est atomique qu au sein d un
meme systeme de fichiers ; un /tmp sur une
autre partition casserait la garantie sans
rien dire
fsync AVANT le rename sinon le renommage peut atteindre le disque
avant le contenu : au retour d une coupure
brutale, un fichier neuf et VIDE — le defaut
qu on ferme, deplace d un cran
report des droits mkstemp cree en 0600, le plan est en 0664 et
doit rester lisible par le groupe sur les
runners
LE TEST PORTE SON PROPRE CONTROLE NEGATIF
scripts/tests/test_ecriture_atomique.py rejoue D ABORD l ancienne forme et
verifie qu elle DETRUIT. Sans ce controle, « le fichier est intact » ne
prouverait rien — il pourrait l etre parce que rien n a ete ecrit du tout. Une
garantie qu on n a jamais vue echouer n est pas une garantie, c est une
habitude.
Branche sur P02, dont le titre annoncait « inventory_host » alors qu il lance
maintenant trois tests. Corrige au passage.
LA VOUTE DU GUI : VERIFIEE, PAS DE DEFAUT
Le soupcon etait qu executer_flux pose ANSIBLE_VAULT_PASSWORD_FILE (un seul mot
de passe) alors que creer une VM ouvre DEUX voutes depuis « une voute, une cle ».
Eprouve contre deux voutes JETABLES a mots de passe distincts — jamais les
vraies. Les deux variables se CUMULENT : Ansible essaie tous les secrets, et un
PASSWORD_FILE errone n empeche rien. Confirme en sondant l environnement qu une
recette make recoit reellement : le mot de passe saisi ET les cinq cles
calculees par voutes.py.
Ce qui sauve ce chemin n est donc pas le mot de passe saisi, c est
l IDENTITY_LIST que make pose par-dessus. Chacun couvre ce que l autre ne
couvre pas — le PASSWORD_FILE sert le runner qui n a que sa cle, l IDENTITY_LIST
le poste qui les a toutes. Ecrit au-dessus du code, pour que personne ne
« simplifie » en retirant l un des deux.
make prouver : CONFORME, 59 OK, 0 echec, 1 saute.
make instancier : DIFF VIDE, quatre registres relus, droits 664 preserves.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
|
|||
| c9d31e9a60 |
preuves : trois gardes pour ce que ma lecture ne tiendra pas
Une revision de documentation vieillit comme le reste. Ce qui tient, c est ce
qu une machine verifie — et trois lacunes etaient nommees sans etre gardees.
P58 HABILITATIONS. autorisation.md posait la regle (un service nomme un
GROUPE, jamais une personne, D-66) et meta/acces.yml la portait ; rien ne
la verifiait. P29 gardait les POSITIONS d authentification, personne ne
gardait les DROITS.
Le controle qui porte la preuve est un croisement : une entree
porte_par: role-realm affirme que l habilitation voyage par un role de
realm projete depuis un groupe LDAP. P58 le confronte a serveur_keycloak.
Sans ca, un service annonce une habilitation que rien ne transporte, et l
ecran reste vide sans que personne sache pourquoi.
CE QU ELLE N EXIGE PAS, et c est le point le plus important : que les
groupes nommes existent dans l annuaire. Ce serait contredire le regime du
paragraphe 2 — le depot AMORCE un acces et se retire, les appartenances
appartiennent a une personne. dev et personnel n existent dans aucun code,
et ce n est pas un defaut.
P59 ENUMERATIONS ANNONCEES. Les deux ecarts trouves a la main pendant la
tournee — cinq portes annoncees devant une table de six, huit lignes
renvoyees vers une fiche qui en compte dix — etaient d une forme que P57
ne voit pas.
Ma premiere version a signale CINQ ecarts, et les cinq etaient du bruit :
dans « reprise dans les deux devis : », le nombre qualifie autre chose que
la liste. Cent pour cent de faux positifs — la preuve qui crie sur un cas
sain et qu on apprend a ignorer. Resserree aux deux formes ou le nombre ne
peut compter rien d autre. Etroite et vraie plutot que large et devineuse.
P60 WIKI PUBLIE. Le wiki est publie DEPUIS le depot ; rien ne mesurait l ecart,
et il s est creuse de VINGT-SEPT JOURS en silence. Deux unites jamais
publiees, vingt et une differentes : pour qui lit la forge plutot que le
depot, toute la revision n existait pas.
Le harnais est STATIQUE, zero appel reseau — cloner la forge romprait la
seule propriete qui fasse qu une preuve vaille hors de ce poste. La mesure
passe donc par un TEMOIN que make wiki-publier depose. Amorce avec la
valeur MESUREE : le wiki d eregion porte b6167f2, dont le message dit
source:
|
|||
| 5bc3bceac1 |
documentation : la tournee des 74 documents, parce qu un balayage ne lit pas
Some checks failed
verifier / verifier (push) Has been cancelled
La revision a commence par un balayage par motifs — chemins morts, cibles make absentes, comptes derives. Il a trouve une trentaine d ecarts et rate presque tout le reste : un motif ne voit que ce qui s exprime en motif. make hote-planifier en est l exemple. La cible EXISTE, donc le controle passait au vert. C est une cible depreciee qui refuse et sort en 2, recommandee par AGENTS.md, et qui contredit la REGLE D OR du meme fichier trois ecrans plus haut. Il fallait lire pour la voir. 74 documents lus un par un. 66 corriges, 8 exacts. CE QUI ETAIT FRANCHEMENT FAUX AGENTS.md, la source d autorite, annoncait la flotte pas encore executee contre des VM reelles. Elle a ete rasee et remontee depuis zero trois fois. ecosysteme-chezlepro.md, le document montre a un client, portait la meme phrase : il se sous-vendait gravement. courriel-conception.md s ouvrait sur aucun role n est encore ecrit, au-dessus de son propre paragraphe 1 qui les nomme. autorisation.md se terminait sur rien n est construit alors qu il rapporte des mesures datees du role en fonctionnement. hebergeur-exploitation.md disait rien n est fait d un depot qui existe. filiation-emancipation.md se contredisait a deux ecrans de distance. DES MODELES DECRITS D APRES UN MONDE ANTERIEUR Le resolveur : cinq documents decrivaient un Unbound par VM en opt-in, trois le donnaient en exemple d integration FACULTATIVE — il est universel depuis le 2026-08-24. L adressage de nomenclature-vm.md : reseau unique, VLAN 11-15, VMID a cinq chiffres. Le nommage SDN de sdn-evpn.md contre le code : c est le wiki qui avait raison. CE QUI CASSE AU PREMIER ESSAI Le nom du gabarit dore etait faux a quatre endroits, dont la procedure qui le FABRIQUE et le critere R2 de l epreuve d operateur independant. preparer-un-site-hebergeur.md avertissait qu une VM faite a la main serait detruite : raser derive du plan, il ne la detruira jamais — le risque est l inverse. Un mot de passe d essai en clair dans un depot public. DEUX PREUVES ETENDUES, ET UNE QUI SE TROMPAIT ELLE-MEME P57 couvre les groupes : elle a signale aussitot 29 groupes annonces au-dessus d un tableau qui en cite 40. P29 confronte le tableau de authentification.md aux declarations reelles : 12 annonces, 21 reels. Et P57 imposait un chiffre faux — 56 preuves alors que le depot en porte 57, la conditionnelle vivant hors de tout comptage. Un garde-fou qui fait respecter une erreur ajoute l assurance a l erreur. CE QUI RESTE, ET QU AUCUNE PREUVE NE TIENT Deux comptes trouves a la main. Et une lacune reelle : rien ne garde les meta/acces.yml — ni qu un service web-sso en porte un, ni que le groupe qu il nomme existe. P29 tient les positions d authentification, personne ne tient les habilitations. make prouver : CONFORME, 56 OK, 0 echec, 1 saute. 0 lien mort. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q |
|||
| dcbb57db69 |
cles : la cle USB se suffit a elle-meme, et la restauration est prouvee
Some checks are pending
verifier / verifier (push) Waiting to run
Le jour ou l on s en sert, le poste est mort — et cloner le depot demande la cle SSH qui est dans l archive qu on essaie d ouvrir. Une procedure rangee dans le depot serait inaccessible exactement quand elle sert. L export depose donc restaurer_cles.py et un LISEZ-MOI a cote de l archive. La cle ne demande plus que gpg, python3 et la phrase de passe. Le script remet chaque fichier a sa place selon son NOM (machine neuve, parfois autre compte), repose les droits a 0600 — ssh refuse une cle privee lisible par d autres, et son message ne dit pas qu il s agit d un droit — et refuse d ecraser une cle presente, en regardant AVANT d ecrire. Le LISEZ-MOI porte les trois commandes manuelles. Un outil peut avoir un defaut ; gpg et tar seront la. EPROUVE : export vers une cle, poste neuf vide, restauration depuis la cle SEULE, empreintes comparees — identiques 4 sur 4, droits 700/600, et le refus d ecraser tire. Le filet manuel passe au meme test separement, identiques 4 sur 4. make cles-restaurer refusera puisque les cles sont en place — et ce refus est la preuve que l archive s ouvre et que la phrase de passe est la bonne. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on |
|||
| 3eff217bd5 |
cles : un chmod refuse ne doit pas annuler une verification reussie
Some checks are pending
verifier / verifier (push) Waiting to run
Une cle USB est le plus souvent en FAT32 ou exFAT — pas de permissions Unix. Le chmod de la derniere ligne y echoue, et le script serait mort APRES avoir ecrit et verifie l archive : une trace d erreur sur un travail termine, au pire moment pour semer un doute. On le dit plutot que de le taire : sur un support sans droits, l archive est lisible par qui branche la cle. C est le chiffrement qui protege, pas le support. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on |
|||
| bebdb84212 |
cles : sortir du poste ce qui n existe qu au poste
Some checks are pending
verifier / verifier (push) Waiting to run
Le code est replique trois fois (eregion, forge du site, patient 0) et les voutes chiffrees y sont aussi — le coffre est solide. Les CLES qui l ouvrent vivaient dans neuf fichiers, 1644 octets, sans copie ailleurs. Poste seul : les mots de passe restic restent lisibles sur les machines vivantes, donc recuperable mais douloureux. Poste + une machine : l etat de cette machine devient illisible. Poste + site : terminal. make cles-recenser montre ce qui sortirait sans rien ecrire — nom, taille, empreinte, JAMAIS le contenu. make cles-exporter chiffre en AES256 puis REDECHIFFRE ce qu il vient d ecrire et compare les empreintes une a une : une sauvegarde de cles qu on n a pas rouverte n est pas une sauvegarde. A lancer par l exploitant lui-meme : gpg demande une phrase de passe, elle ne doit passer ni par un journal ni par le contexte d un assistant. Trois refus, eprouves en les faisant echouer : destination dans l infrastructure (un coffre dont la cle est dedans), archive existante (elle est peut-etre la seule), archive illisible (supprimee). Le premier essai du premier refus etait faux — le shell developpait HOME avant que je le remplace, l instrument mesurait ailleurs que la cible. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on |
|||
| 42becd0c02 |
paquets tiers : passer par le cache du controleur, plus par Internet
Some checks are pending
verifier / verifier (push) Waiting to run
Trois depots tiers etaient en HTTPS, et client_artefacts pose Acquire::https::Proxy DIRECT — sans quoi le cache du site refuse les tunnels et aucun depot tiers n est joignable. La ligne est juste ; sa consequence ne l avait pas ete vue : ces trois depots CONTOURNENT le cache, et chaque VM neuve allait les chercher sur Internet a sa naissance. step-cli et alloy sont poses par des integrations UNIVERSELLES. Sans lien, une machine neuve n obtenait ni son client d autorite ni ses metriques — elle n entrait dans aucun flux chiffre. Dernier obstacle a une reconstruction hors ligne, et il tenait dans un mot. make cacher-paquets tire les 21 deb aux versions epinglees, empreinte SHA256 verifiee depuis l index du depot. Le role partage paquets_tiers les depose et les installe EN UN SEUL appel a apt — il sait resoudre un ensemble de fichiers locaux qui se dependent, la ou paquet par paquet echouerait sur l ordre (Icinga en apporte dix-sept). Six roles branches ; chacun retombe sur le depot distant pour ce que le cache n a PAS fourni, et rien d autre. Eprouve pour de vrai : packages.smallstep.com renvoye vers 127.0.0.1, step-cli desinstalle, cache local efface. Le role rejoue installe 0.30.6-1 depuis le cache et la machine obtient ses certificats. Zero echec. Deux defauts de mon propre outil, trouves en le construisant : Smallstep sert son index NON COMPRESSE (404 sur .gz) donc step-cli n etait jamais mis en cache ; et un depot injoignable faisait continue AVANT d incrementer le total, si bien que le script rapportait 20 sur 20 alors qu il en manquait un. Une garde qui ne peut pas echouer ne garde rien — troisieme fois cette semaine. Corrige puis eprouve en le faisant echouer. Reste hors ligne : NTP externe, et l expedition des alertes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on |
|||
| cccb4e5b43 |
supervision : declarer a qui elle parle
Some checks are pending
verifier / verifier (push) Waiting to run
Icinga livre son exemple avec root@localhost — une adresse que personne ne lit. Une supervision qui voit tout et n en parle a personne a le meme effet qu aucune supervision, en plus couteux : elle rassure. serveur_icinga_destinataire cree un utilisateur dans le groupe auquel les notifications sont deja assignees (Icinga refuse deux objets de meme nom, on ne peut pas redefinir l exemple ; on en ajoute un autre, l exemple reste muet). Vide, aucun destinataire n est pose ET LE DEPLOIEMENT LE DIT — plutot que de laisser croire qu une alerte partira. Eprouve : message expedie par le relais du site, status=sent (250 2.0.0 Ok), livre directement a mx.chezlepro.ca sans intermediaire ni dependance envers un locataire. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on |
|||
| 4e12c3a802 |
supervision du site, et la panne qui dormait dans un mot
Some checks are pending
verifier / verifier (push) Waiting to run
Le site a son temoin : site-mon-01 (VLAN 36) porte PostgreSQL, Icinga et un relais. Le depot lui rapporte, et son premier verdict fut un vrai defaut — site-mon-01 n avait jamais depose son propre etat. Les trois sont au vert. serveur_backup_verification_locale repasse a true sur le depot : le drapeau ne dit plus on renonce mais verifie ce que tu peux ouvrir . La liste des noeuds attendus derive de l inventaire ou tourne le role, donc du site seul. serveur_postfix gagne un mode relais : un site n heberge aucune boite, il expedie. Directement par sa frontiere — emprunter le MTA d un locataire ferait dependre l hebergeur d un ecosysteme qu il peut outvivre. LA PANNE DE FOND : le modele de routes OPNsense lit enabled ; on lui envoyait disabled=0, un champ ignore. enabled restait a son defaut, ETEINT. Chaque route creee par Set-OPS depuis l origine l etait desactivee — invisible, parce qu une route eteinte EXISTE dans le modele et compte posee . Le rechargement lance pour activer la nouvelle patte a fait reprendre au noyau sa table depuis le modele : 14 routes sur 15 disparues, 11 machines de Chezlepro injoignables le lendemain de sa reconstruction, et le devis toujours vert. Trois corrections empilees : la cause (enabled), la cecite (le plan lit la table du NOYAU et signale absent ou eteint), l inaction (la reconfiguration ne se declenchait que sur un changement du modele). Aussi : un role du site peut enfin en appeler un autre a travers la frontiere — le devis traitait tout pair nomme comme l exterieur . Et nftables_admin_ssh se DERIVE de la carte : recopie a la main, il retardait d une zone, et m a verrouille dehors de la machine que je venais de creer. Reste ouvert : le destinataire des alertes est encore root@localhost. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on |
|||
| cf9abe74b6 |
sauvegarde : le site protege enfin son propre etat
Some checks are pending
verifier / verifier (push) Waiting to run
L hebergeur protegeait l etat de tous ses locataires et pas le sien. Deux choses qu il detient et que personne ne peut regenerer : la racine de son AC, et la forge du genome. Le reste est reconstructible par le code. Preuve faite, pas annoncee : sauvegarde reelle puis restic check et restitution. 13 fichiers pour l AC (root_ca_key et intermediate_ca_key compris), 835 pour la forge. Le site depose avec SON identite, sur le compte restic que serveur_backup lui cree, separe des comptes des locataires par les memes permissions. La cible est derivee du expose de l application qui porte serveur_backup_site : le nom du service, pas une adresse — client_backup_repo la grave dans le chemin de chaque instantane. P36 ne lisait que le plan de l instance montee, donc jamais celui du site — qui detient pourtant le plus. Elle lit desormais les deux. Verifiee en la faisant echouer : integration retiree, la preuve tire. Reste ouvert : personne ne verifie les sauvegardes du site. Le depot tourne avec verification_locale a false (pose pour les locataires, dont il ne peut pas ouvrir les depots) et le site n a pas de supervision. La sauvegarde existe et se restaure ; c est son SILENCE qui n alerte pas encore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on |
|||
| 53c5f41a1a |
durcissement : le site recoit enfin serveur_durci
Some checks are pending
verifier / verifier (push) Waiting to run
Les six machines du SITE — racine de l AC, forge, cache, resolveur, depot de sauvegarde, runner — ne recevaient que serveur_debian. Ni auditd, ni fail2ban, ni apparmor, ni sysctl, ni pare-feu. Le commentaire au-dessus de GROUPE_SOCLE affirmait pourtant le contraire, ce qui rendait l ecart invisible. Le pare-feu du site n avait aucune des trois pieces qui le rendent applicable : - aucune regle generee (resoudre_flux lit un hosts.yml ; le site a un inventaire dynamique) -> commande nftables-site, branchee sur make flux - le chemin du jeu de regles sortait du depot (inventory_dir vaut scripts/ pour un inventaire dynamique) -> host_var explicite - aucun nftables_admin_ssh : l exploitant administre PAR REBOND, la connexion arrive avec l adresse de la patte de frontiere DANS LA ZONE VISEE. Le generateur refuse desormais de produire des regles sans cet intrant. Defaut attrape en LISANT le jeu de regles avant de l appliquer : la regle DNS de site-dns-01 omettait 10.17.0.0/16. _supernets_voisins retire l instance montee — juste chez un tenant, faux du cote du site, ou ca retire le locataire qu on pilote. L appliquer aurait prive de DNS les quinze machines reconstruites la veille. MaxStartups du depot passe en host_var : dans le meta du role, il ne portait que dans son play, et le passage de serveur_durci le remettait au defaut sans rien dire. Un reglage qui depend de l ordre des plays revient en arriere. Verifie depuis un locataire a travers le nouveau pare-feu : cache, forge, depot (2 snapshots) et resolveur repondent ; l AC du site refuse, et c est correct. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on |
|||
| 0854b2a93c |
reconstruction : quatre defauts que seule une flotte rasee pouvait montrer
Some checks are pending
verifier / verifier (push) Waiting to run
Chezlepro detruite (15 VM, disques compris) et refaite depuis le gabarit minimal. 15/15 hotes, 0 echec ; make valider passe, test de restitution compris. Aucun defaut ne venait de la flotte ni du gabarit. 1. Un avertissement n est pas un echec. Proxmox rend WARNINGS: n pour une tache ABOUTIE ; la garde n acceptait que OK et declarait perdues cinq VM clonees a 100 pourcent. Le message parlait d etat stopped — celui de la TACHE, pas de la VM. 2. client_artefacts se contredisait : son commentaire disait de degrader, son code arretait. L autorite monte en premier, donc avant le cache du locataire : aucun ordre ne pouvait satisfaire la garde. 3. harden-below-nxdomain etendait le NXDOMAIN signe de la racine pour le TLD internal a toute la zone du site, sans jamais interroger l autoritatif. Declencheur : toute question sur un nom absent sous internal, y compris la zone d un autre locataire. Le cache contenait la bonne reponse ET un message negatif ; c est le negatif qui etait servi. aggressive-nsec: no avait semble marcher — c est le redemarrage qui vidait le cache, pas le reglage. 4. Un locataire doit savoir a qui demander la zone de son hebergeur, sans quoi il ne peut plus nommer son depot de sauvegarde. La derivation prenait dns_amorcage pour le resolveur du site : faux chez Technolibre, dont l amorcage est 9.9.9.9. P03 l a attrape avant tout deploiement. Au passage : instancier tentait encore le mot de passe unique d avant la separation des voutes ; comparer echouait en exit 4. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on |
|||
| 3ea0c95492 |
sauvegarde : l etat d un locataire quitte enfin sa propre flotte
Some checks are pending
verifier / verifier (push) Waiting to run
Chezlepro rangeait ses instantanes sur une VM DE SA PROPRE FLOTTE. Raser l ecosysteme pour le reconstruire, c etait raser le filet avec. Le site a son depot ; les neuf detenteurs d etat y deposent ; une restitution est sortie (annuaire LDAP lisible, hors flotte). Isolation par compte Unix, pas par convention : home 0700, cle exclusive, racine partagee a root en 0711 (traversable, non listable). Les deux refus constates. Le site heberge du chiffre : il ne peut ni lire ni ouvrir, d ou la verification deplacee chez le locataire qui detient la cle. Quatre defauts reveles par ce deuxieme usage : - la racine des depots ne peut etre le home de personne (StrictModes rendait Permission denied publickey pour un refus de CHEMIN) - la racine nie le TLD internal, et harden-below-nxdomain etendait ce non a toute la zone sans jamais interroger l autoritatif : aucun locataire ne pouvait nommer un service du site - le gabarit transporte des fichiers de durcissement perimes, et les machines du site ne recoivent jamais ssh_hardening - MaxStartups compte les connexions non authentifiees : un depot de site en voit la somme de ses locataires Constat non corrige : les machines du site ne sont pas durcies. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on |
|||
| 4abf875e5f |
gabarit : q35 n est pas un reglage, c est la raison de la procedure manuelle
Some checks are pending
verifier / verifier (push) Waiting to run
CONSTAT DE L EXPLOITANT, PAYE EN ANOMALIES : convertir une machine deja installee d `i440fx` a `q35` produit une serie de pannes dont chacune ressemble a autre chose qu a sa cause. Ce n est pas une correction, c est une transplantation. LE MECANISME, ECRIT POUR QU ON NE LE REDECOUVRE PAS : `i440fx` est un chipset PCI, `q35` est PCIe. La topologie des bus change, donc les NOMS D INTERFACES PREDICTIBLES changent avec le chemin PCI (enp0s3 -> enp1s0) et la machine perd le reseau ; les chemins de disques bougent ; l ordre d enumeration suit. C EST AUSSI POURQUOI SET-OPS N UTILISE PAS L IMAGE CLOUD OFFICIELLE DE DEBIAN : `genericcloud` est livree configuree pour `i440fx`. Une machine nait `q35`, ou elle ne le sera jamais proprement — et c est ce que l installation depuis l ISO garantit. Ces deux lignes de la procedure n etaient qu une ligne de tableau. Elles portent maintenant leur pourquoi, et le SITE les declare comme DONNEES (cle `gabarit`), plus seulement comme prose. `make gabarit-etat` compare le gabarit reel a ce que le site declare de lui. ON VERIFIE LA SOURCE, PAS CHAQUE COPIE. Ma premiere version gardait le CLONAGE : la propriete s herite, donc verifier chaque clone coute a chaque creation sans rien dire de plus que verifier le gabarit une fois. Retiree. TROIS FOIS J AI DEVINE LA FORME DE LA REPONSE AU LIEU DE LA REGARDER — regex_search a groupe qui rend None, proxmox_vm_info sans `config: current` qui ne rend que l etat. La garde a declare « ? » sur une VM parfaitement conforme : une garde qui crie toujours est pire qu aucune, on apprend a l ignorer. A la demande et non dans `make prouver` : ce controle exige le cluster, que le harnais ne suppose pas joignable. Meme nature que genome-etat et underlay-plan. Controle negatif verifie : declarer i440fx fait echouer, rc=1. make verifier : vert. make prouver : CONFORME, 56 OK, 0 echec. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on |