D-85 : ce que le retrait de cloud-init NE ferme pas

La premiere redaction se lisait comme une emancipation. Elle n en est pas
une, et il valait mieux le dire que de laisser un lecteur presse en
conclure trop.

Retirer cloud-init n ote AUCUN pouvoir a l hebergeur. qemu-guest-agent est
au gabarit — il doit y etre (P56) — et l API Proxmox expose sur son dos,
sur toute VM vivante de la flotte, un pouvoir strictement plus grand que
le lecteur cloud-init. Releve le 2026-09-09 sur edge-mta-01, avec le jeton
du site : exec, exec-status, file-read, file-write, set-user-password,
shutdown.

Ce que D-85 ferme est donc precis et etroit : une reapplication
AUTOMATIQUE a chaque demarrage, depuis un support que le plan ne possede
pas et qu aucune preuve ne lit ; et le code de cloud-init lui-meme, un
interpreteur Python complet execute en root au boot avec ses ~29
dependances. La mainmise d un hyperviseur sur ses invites est une
propriete de la VIRTUALISATION, pas de cloud-init — elle appelle sa propre
decision, qui n est pas prise.

LE SEUIL EST NOMME. L alternative existe et sa piece est deja au gabarit :
poser adresse et cle par agent/file-write + agent/exec, sans reseau.
Aujourd hui ce serait reimplementer un standard, ce que positionnement.md
interdit, au moment le plus fragile et pour le pire mode de panne — une VM
injoignable. Le jour ou une premiere seconde ne pourra plus etre amorcee
par Proxmox (autre hyperviseur, metal nu, hebergeur sans API), ce chemin
devient LE chemin portable.

La nuance est portee partout ou l affirmation est faite : D-85, le README
et l entete du role, AGENTS.md, le wiki.

make prouver : CONFORME, 62 OK, 0 echec, 1 saute.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
This commit is contained in:
Daniel Allaire 2026-09-09 10:11:52 -04:00
parent a6457a161b
commit f89b097b26
6 changed files with 88 additions and 1 deletions

View file

@ -644,6 +644,15 @@ comptes, clés SSH, mots de passe et réseau. Sur une machine que le plan possè
produisait un va-et-vient à chaque déploiement. **Le gabarit, lui, le garde** — sans lui un
clone n'a ni adresse ni nom. **P63** garde les trois moitiés.
**Ce que ce retrait ne ferme pas.** Il n'ôte **aucun pouvoir à l'hébergeur** :
`qemu-guest-agent` est au gabarit (il doit y être — P56), et l'API Proxmox expose sur son
dos `exec`, `file-write`, `set-user-password`, `shutdown` — strictement plus que le lecteur
cloud-init. Ce qui est fermé est étroit et réel : une réapplication *automatique, à chaque
démarrage*, depuis un support que le plan ne possède pas, et un interpréteur Python
complet exécuté en root au boot. La mainmise de l'hyperviseur sur ses invités est une
propriété de la virtualisation, pas de cloud-init — elle appelle sa propre décision, non
prise.
---
## Nettoyage avant template

View file

@ -72,6 +72,45 @@ existe pour qui veut, en connaissance de cause.
`/etc/cloud/cloud-init.disabled` est lu par cloud-init lui-meme au demarrage et l'arrete
avant qu'il ne lise la moindre source de donnees.
### Ce que cette decision NE ferme PAS
Ajoute le meme jour, apres la question « cloud-init est-il vraiment une valeur ajoutee
ici ? ». La premiere redaction de D-85 se lisait comme une emancipation. Elle n'en est
pas une, et il valait mieux le dire que de laisser un lecteur presse en conclure trop.
**Retirer cloud-init n'ote AUCUN pouvoir a l'hebergeur.** `qemu-guest-agent` est au
gabarit — il doit y etre (P56 : c'est par lui que `creer-vm` confirme la materialisation
sans entrer chez le tenant). Releve du 2026-09-09 sur `edge-mta-01`, avec le jeton d'API
du site, les sous-chemins que l'API expose sur son dos :
exec · exec-status · file-read · file-write · set-user-password · shutdown · ...
C'est un pouvoir STRICTEMENT PLUS GRAND que le lecteur cloud-init, et il est deja la, sur
chaque VM vivante de la flotte.
Ce que D-85 ferme est donc precis et etroit :
1. une reapplication AUTOMATIQUE, a chaque demarrage, depuis un support que le plan ne
possede pas et qu'aucune preuve ne lit ;
2. le code de cloud-init lui-meme — un interpreteur Python complet execute en root au
demarrage, et ses ~29 dependances.
La mainmise d'un hyperviseur sur ses invites est une propriete de la VIRTUALISATION, pas
de cloud-init. Elle appelle sa propre decision, qui n'est pas prise.
### Le seuil ou le remplacer deviendrait juste
L'alternative existe et sa piece est deja au gabarit : ecrire l'adresse et la cle par
`agent/file-write` + `agent/exec` depuis l'hyperviseur, sans reseau. Aujourd'hui ce serait
REIMPLEMENTER UN STANDARD — ce que `positionnement.md` interdit — et echanger un mecanisme
eprouve contre du code maison au moment le plus fragile, dont le mode de panne est le
pire : une VM injoignable.
Le jour ou une premiere seconde ne pourra plus etre amorcee par Proxmox — autre
hyperviseur, metal nu, hebergeur sans API — ce chemin cesse d'etre une reimplementation et
devient LE CHEMIN PORTABLE. C'est l'axe emancipation que le depot suit deja. Le seuil est
nomme ici pour ne pas etre franchi sans le voir.
### Non deploye
Le code est ecrit, valide et prouve ; **il n'a pas ete applique a la flotte**. Retirer un

View file

@ -58,7 +58,7 @@ sont les seules vérifiables.
| **D-82** | **Patient 0 n'est le parent de personne.** Il est la **mise en œuvre de référence** du modèle `origine` — le plus petit écosystème complet — et un pair de la famille du génome, pas sa racine | trois faits l'ont retiré un par un : D-81 a donné l'autorité du génome à la forge du SITE (son dernier lecteur corrigé le 2026-08-26, Technolibre le 08-31) ; le dénominateur commun vit dans les modèles depuis le 08-24 ; et **l'ancêtre était locataire de son enfant** — index 29 sur la fabric de `SITE-Chezlepro`, qui descend de lui. Ce qu'il devait éliminer — le SPOF `eregion`, hors flotte — n'a PAS été éliminé mais **promu** : le poste y pousse, la forge du site en tire. Cette dette appartient désormais au SITE, et la nommer est le minimum : *un objectif qu'on abandonne sans le dire devient un objectif qu'on croit atteint* | `OPS-Patient0/README.md`, `docs/filiation-emancipation.md` | — |
| **D-83** | **Patient 0 a été retiré** — ses machines n'existent plus (constaté le 2026-09-06) | D-82 lui avait laissé une raison d'être : la mise en œuvre de référence du modèle `origine`, et un **témoin** de plus du génome. Le retrait solde la première et **abaisse la seconde de trois copies vivantes à deux** (`eregion`, la forge du site). Ce qu'il devait éliminer — le SPOF `eregion` — reste entier, et sans lui il n'y a plus de miroir indépendant pour l'absorber. **Son plan reste sur disque et la fédération lui réserve toujours l'index 29** : tant que ce n'est pas tranché, le site ouvre SSH, apt, DNS et HTTPS à `10.29.0.0/16` — un périmètre vide | `OPS-Patient0/`, `SITE-Chezlepro/flux-genere/` | **P21** (index), **P23** |
| **D-84** | **Le plan de contrôle reste gelé — c'est la CARTE DES SEUILS qui était fausse** | La question « et si on retirait le gel ? » a mis à l'épreuve les cinq seuils de `positionnement.md`, et deux ne tenaient pas. **RBAC** : couvert depuis que trois classes d'acteurs aux pouvoirs disjoints existent — poste, runner de site, runners de tenant — séparés **cryptographiquement** (une voûte, une clé, 2026-08-28) et non par une table de permissions qu'une faille applicative contournerait ; adopter AWX pour ce besoin serait **régresser**. **IPAM** : sans objet par construction — rien ne s'alloue, tout dérive du seed, et P20/P21/P23/P28/P33 tiennent déjà ce qu'un IPAM vérifierait *a posteriori*. Les deux lignes sont retirées du tableau : les garder aurait fait adopter un outil pour un besoin déjà rempli. **Et un seuil manquait** — l'**émancipation** : le GUI est mono-utilisateur (`127.0.0.1` + jeton), or la trajectoire mène à plusieurs humains aux portées disjointes, sur des machines qui ne sont pas les nôtres. Ce seuil n'appelle pas AWX, il appelle une décision non prise. *Un seuil qu'on ne nomme pas est un seuil qu'on franchit sans le voir.* Corollaire consigné : le gel porte sur les **fonctions**, jamais sur les **vues** — montrer à l'écran ce que le moteur sait déjà ne franchit aucun seuil | `positionnement.md` §3, §4, §5 | — |
| **D-85** | **cloud-init naît avec la VM et ne lui survit pas** | cloud-init n'est pas un logiciel d'installation : c'est une **source de vérité externe**. À chaque démarrage il relit le lecteur attaché par l'hyperviseur, qui peut redéfinir comptes, clés SSH autorisées, mots de passe et réseau. Sur une machine que le plan possède, c'est un **second maître** — que le plan ne décrit pas, que `make valider` ne mesure pas, et qui gagne parce qu'il parle en premier. Sa tâche est pourtant finie à la première seconde : c'est parce qu'il a **réussi** à poser l'adresse et les clés qu'Ansible a pu entrer. **La décision a trois moitiés, et elles se défont séparément** : le **gabarit** le garde (sans lui un clone ne naît pas — P56) ; le **socle** ne l'installe plus (le garder produisait un va-et-vient à chaque déploiement : le socle installe, le durcissement retire, deux `changed` par passage) ; le **durcissement** le retire (`cloud_init_retrait`). **Ce qui rend le retrait sûr est mesuré, pas supposé** (2026-09-09, `obs-01`) : `/etc/network/interfaces.d/50-cloud-init` n'appartient à aucun paquet — `dpkg -S` ne le trouve pas — et le `postrm` ne le nomme jamais, même en `purge`. L'adresse survit. Le rôle le **vérifie** malgré tout, avant et après : une VM qui perd ce fichier ne se plaint pas, elle repart sans adresse et plus personne ne peut entrer pour le constater | `roles/cloud_init_retrait/`, `serveur_durci.yml` | **P63** |
| **D-85** | **cloud-init naît avec la VM et ne lui survit pas** | cloud-init n'est pas un logiciel d'installation : c'est une **source de vérité externe**, qui se réveille à *chaque* démarrage et relit le lecteur attaché par l'hyperviseur — lequel peut redéfinir comptes, clés SSH autorisées, mots de passe et réseau. Sur une machine que le plan possède, c'est un **second maître** : le plan ne le décrit pas, `make valider` ne le mesure pas, et il parle en premier. Sa tâche est pourtant finie à la première seconde — c'est parce qu'il a **réussi** à poser l'adresse et les clés qu'Ansible a pu entrer. **Trois moitiés, qui se défont séparément** : le **gabarit** le garde (sans lui un clone ne naît pas — P56) ; le **socle** ne l'installe plus (le garder produisait un va-et-vient à chaque déploiement : le socle installe, le durcissement retire, deux `changed` par passage) ; le **durcissement** le retire (`cloud_init_retrait`, en dernier). **Ce qui rend le retrait sûr est mesuré, pas supposé** (2026-09-09, `obs-01`) : `/etc/network/interfaces.d/50-cloud-init` n'appartient à aucun paquet — `dpkg -S` ne le trouve pas — et le `postrm` ne le nomme jamais, même en `purge`. L'adresse survit. Le rôle le **vérifie** malgré tout, avant et après : une VM qui perd ce fichier ne se plaint pas, elle repart sans adresse et plus personne ne peut entrer pour le constater. **⚠ CE QUE CETTE DÉCISION NE FERME PAS — et il faut le dire, sinon elle se lit comme une émancipation qu'elle n'est pas.** Retirer cloud-init **n'ôte aucun pouvoir à l'hébergeur**. `qemu-guest-agent` est au gabarit (P56 : il doit y être — c'est par lui que `creer-vm` confirme la matérialisation sans entrer chez le tenant), et l'API Proxmox expose sur son dos, sur toute VM vivante de la flotte, un pouvoir **strictement plus grand** que le lecteur cloud-init : `exec`, `file-write`, `file-read`, `set-user-password`, `shutdown` (relevé le 2026-09-09 sur `edge-mta-01`, jeton d'API du site). Ce que D-85 ferme est donc **précis et étroit** : (a) une réapplication **automatique, à chaque démarrage**, depuis un support que le plan ne possède pas et qu'aucune preuve ne lit ; (b) le code de cloud-init lui-même — un interpréteur Python complet, exécuté en root au démarrage, et ses ~29 dépendances. Elle ne ferme **pas** la mainmise de l'hyperviseur sur ses invités : celle-là est une propriété de la virtualisation, pas de cloud-init, et elle appelle sa propre décision — non prise. **Le seuil où le remplacer deviendrait juste** : le jour où une première seconde ne peut plus être amorcée par Proxmox (autre hyperviseur, métal nu, hébergeur sans API), le chemin par l'agent invite cesse d'être une réimplémentation d'un standard — que `positionnement.md` interdit — et devient **le chemin portable**. Tant que ce seuil n'est pas atteint, écrire soi-même l'amorçage serait échanger un standard éprouvé contre du code maison au moment le plus fragile, dont le mode de panne est le pire : une VM injoignable | `roles/cloud_init_retrait/`, `serveur_durci.yml`, `positionnement.md` | **P63** |
| **D-81** | **La forge du SITE fait autorité pour le génome.** Toute autre copie — y compris celle d'où le moteur a été poussé jusqu'ici — est un **miroir**. Le poste de l'exploitant ne route pas jusqu'à elle : c'est le **runner du site** qui publie, par `make genome-pousser` | un écosystème se reproduit depuis la forge de son site : c'est de là qu'il clone son moteur, ses plans, ses modèles. Si l'autorité est ailleurs, cette forge devient un cache qu'on croit à jour — et le 2026-08-26 elle était **quatre commits en arrière** sans que rien ne le signale, dont le correctif qui désarme le pare-feu Proxmox. **Un écosystème qui se reproduit depuis une forge en retard reproduit ses défauts.** Le poste n'a de patte que sur l'administration, et on ne perce pas de chemin pour lui : le runner existe pour ce travail | `playbooks/maintenance/genome_pousser.yml`, `scripts/genome_colis.py`, `Makefile` §genome-pousser | — |
| **D-13** | Un **hébergeur** sert plusieurs **tenants** et a son tenant par défaut | Chezlepro est les deux à la fois, ce qui masquait la distinction | `frontiere-opnsense.md` §2 | — |
| **D-14** | `underlay.yml` appartient à l'**hébergeur**, monté par symlink | ce sont ses commutateurs, ses câbles ; le moteur est générique, un tenant n'en possède pas | `sdn-evpn.md`, `underlay.yml.example` | — |

View file

@ -16,6 +16,24 @@ d'aller plus loin si le fichier a disparu.
**Ce qui n'est pas retiré.** `cloud-guest-utils` (`growpart`) : aucun service, aucune
source de données, aucun pouvoir. Le retirer ne fermerait rien.
## Ce que ce rôle ne ferme PAS
Il **n'ôte aucun pouvoir à l'hébergeur**, et le croire serait la mauvaise leçon.
`qemu-guest-agent` est au gabarit — il doit y être (P56) — et l'API Proxmox expose sur son
dos, sur toute VM vivante, un pouvoir **strictement plus grand** que le lecteur
cloud-init : `exec`, `file-write`, `file-read`, `set-user-password`, `shutdown` (relevé le
2026-09-09 sur `edge-mta-01`).
Ce que ce rôle ferme est précis et étroit :
1. une réapplication **automatique, à chaque démarrage**, depuis un support que le plan ne
possède pas et qu'aucune preuve ne lit ;
2. le code de cloud-init lui-même — un interpréteur Python complet exécuté en root au
démarrage, et ses ~29 dépendances.
La mainmise de l'hyperviseur sur ses invités est une propriété de la virtualisation, pas de
cloud-init. Elle appelle sa propre décision, qui n'est pas prise. Cf. **D-85**.
**Le gabarit garde cloud-init** — il est le seul chemin vers la première seconde d'un
clone (P56). Le retrait n'intervient qu'après, sur la machine déployée. C'est pourquoi
`serveur_debian` ne l'applique plus : sinon le socle l'installerait et le durcissement le

View file

@ -9,6 +9,18 @@
# Sa tache est finie : il a donne a la VM son adresse, son nom et ses cles d'hote a la
# premiere seconde. C'est precisement parce qu'il a REUSSI qu'Ansible a pu entrer.
#
# CE QUE CE ROLE NE FERME PAS, et le croire serait la mauvaise lecon. Il n'ote AUCUN
# pouvoir a l'hebergeur. `qemu-guest-agent` est au gabarit — il doit y etre (P56) — et
# l'API Proxmox expose sur son dos, sur toute VM vivante, un pouvoir STRICTEMENT PLUS
# GRAND que le lecteur cloud-init : `exec`, `file-write`, `file-read`,
# `set-user-password`, `shutdown` (releve le 2026-09-09 sur `edge-mta-01`).
#
# Ce qui est ferme ici est etroit et reel : (a) une reapplication AUTOMATIQUE, a chaque
# demarrage, depuis un support que le plan ne possede pas et qu'aucune preuve ne lit ;
# (b) le code de cloud-init lui-meme, un interpreteur Python complet execute en root au
# demarrage. La mainmise de l'hyperviseur sur ses invites est une propriete de la
# virtualisation, pas de cloud-init : elle appelle sa propre decision (D-85).
#
# POURQUOI LE RETIRER NE COUPE PAS LE RESEAU (mesure du 2026-09-09 sur `obs-01`) :
#
# /etc/network/interfaces.d/50-cloud-init -> dpkg -S : aucun paquet ne le possede

View file

@ -49,6 +49,15 @@ Le durcissement (`serveur_durci`) le **retire** donc, une fois qu'il a réussi
parce qu'il a réussi qu'Ansible a pu entrer. Le gabarit, lui, le garde : sans lui, un clone
n'a ni adresse ni nom d'hôte.
*Ce que ça ne fait pas* : ça **ne reprend pas la main à l'hébergeur**. `qemu-guest-agent`
reste sur chaque VM — il doit y être, c'est par lui que la création confirme qu'une machine
existe — et l'API de l'hyperviseur expose sur son dos `exec`, `file-write`,
`set-user-password`, `shutdown` : strictement plus que le lecteur cloud-init. Ce qui est
fermé est plus étroit, et bien réel : une réapplication *automatique, à chaque démarrage*,
depuis un support que le plan ne possède pas, et un interpréteur Python complet lancé en
root au démarrage. Qu'un hyperviseur puisse tout faire chez ses invités est une propriété
de la virtualisation, pas de cloud-init.
*Pourquoi ça ne coupe pas le réseau* : l'adresse posée à la naissance vit dans
`/etc/network/interfaces.d/50-cloud-init`, un fichier qui **n'appartient à aucun paquet** —
`dpkg -S` ne le trouve pas, et le `postrm` ne le nomme jamais, même en `purge` (mesuré le