journal : l insemination aboutit — un runner de tenant, ne d un runner de site
Some checks are pending
verifier / verifier (push) Waiting to run

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
This commit is contained in:
Daniel Allaire 2026-08-28 16:21:39 -04:00
parent 58ce3dfea4
commit 89c911ef05
2 changed files with 69 additions and 6 deletions

View file

@ -1,5 +1,69 @@
# CHANGELOG — Set-OPS
## 2026-08-28 — L'insémination aboutit : un runner de tenant, né d'un runner de site
**52 preuves.** `ops-01` existe, configurée de bout en bout **par le runner du SITE**, qui
n'a détenu aucun secret de Chezlepro :
```
/opt/setops Set-OPS-public OPS-Chezlepro SITE-Chezlepro venv
symlinks (D-80) instance -> OPS-Chezlepro underlay.yml -> SITE-Chezlepro/…
moteur au commit courant
sa paire SSH setops@ops-01.chezlepro.internal
voûte / clé AUCUNE
```
**Il s'arrête exactement là où il n'a pas la clé.** Ce n'est pas une règle qu'on lui
impose, c'est un fait : la voûte de Chezlepro ne vit dans aucun dépôt, et son mot de passe
n'est sur aucune de ses machines. L'armer reste le geste d'un humain, depuis **son** poste,
par **son** chemin — le site ne peut pas le faire à sa place, même s'il le voulait.
### Trois murs, et chacun a nommé une pièce manquante du terrain
Le socle bloquait sur `apt`, puis `serveur_ops` sur `pip`, puis sur le clonage du génome.
Trois échecs, trois couches du terrain que le SITE doit préparer et qui n'étaient pas
déclarées.
**`apt`** → la source d'artefacts d'amorçage. Le DNS sortant d'un tenant est fermé par
conception ; un mandataire résout ce que le client ne peut pas résoudre. Aucun flux à
ouvrir : le cache du site acceptait déjà les supernets des tenants.
**`pip`** → la roue hors-ligne, dernière dépendance qui sortait par elle-même. Les
collections suivaient l'idiome du dépôt depuis longtemps — *le contrôleur télécharge, la
cible n'ouvre rien* — `pip` non. `--no-index` **est** le point : sans lui, la réussite
dépendrait un jour d'un flux que ce tenant n'a pas le droit d'avoir, et une lignée
autonome deviendrait une lignée qui **a l'air** autonome.
**Le génome** → le marqueur `serveur_forge_site`, qui manquait. Le site rendait deux
services à ses locataires, les paquets et le génome ; seul le premier était déclaré. Une
dépendance écrite chez le consommateur, sans flux chez le fournisseur — invisible, parce
que la garde de matrice ne vérifie que les paires rôle→rôle.
### Les clés SSH suivent la même règle que les voûtes
Chaque runner a son jeu de clés ; sa publique vit dans l'`authorized_keys` des machines de
**son** tenant, et d'aucun autre. Le runner du SITE n'entre que sur `ops-01`, par le flux
d'insémination. *Le pouvoir d'entrer se borne au périmètre du runner qui le détient*, comme
le pouvoir d'ouvrir se borne à sa voûte.
Le véhicule existait déjà — `ssh_baseline_cles_admin`, avec son `etat` par entrée, donc
révocable sur toute la flotte. Chezlepro n'en déclarait aucune parce que son runner
n'existait pas encore.
### Ce que la mesure a corrigé, deux fois
`ops-01` est **la seule VM de Chezlepro qui existe** — les quatorze autres ne sont sur
aucun hyperviseur. Mes sondes vers le résolveur, le cache et la PKI du tenant mesuraient
donc une **absence**, que j'ai d'abord lue comme un pare-feu. *Un port muet ressemble à un
refus.*
Et l'accès que je croyais avoir cassé en appliquant le pare-feu est-ouest : aucune machine
de Chezlepro n'était joignable depuis le poste par ce rebond. `ops-01` l'était parce
qu'elle n'avait **aucun** groupe de pare-feu. Je n'ai pas créé une panne, j'ai retiré une
exception.
make verifier : vert. make prouver : CONFORME, 52 OK, 0 echec, 0 saute.
## 2026-08-28 — Nourrir la première machine : le cache du site pendant la jeunesse
**52 preuves.** `ops-01` est la première machine de la reconstruction de Chezlepro, et le

View file

@ -7,7 +7,7 @@
> [`docs/audit/affirmations.md`](affirmations.md).
- **Instance** : `instance` — inventaire `instance/inventories/principal/hosts.yml`
- **Verdict** : ❌ NON CONFORME (51 OK · 1 echec · 0 saute)
- **Verdict** : ✅ CONFORME (52 OK · 0 echec · 0 saute)
## Preuves
@ -44,7 +44,7 @@
| P29 | Authentification : chaque role declare sa position | AFF-111 | ✅ OK | 30 role(s) serveur declares (interne-sans-auth 2, ldap-direct 2, sans-auth-humaine 19, socle-identite 2, web-sso 5) ; 2 lacune(s) nommee(s) : serveur_loki, serv |
| P30 | SDN EVPN : zones, VNets et sous-reseaux derives | AFF-112 | ✅ OK | CONFORME : SDN EVPN, 3 zone(s), 15 VNet(s), 15 sous-reseau(x), aucune collision. |
| P31 | Documentation : tout ce que le depot FAIT est nomme | — | ✅ OK | 52 scripts expliques et atteignables, 104 cibles make documentees, 62 roles avec README. |
| P32 | Intrants exiges par les roles : tous fournis | — | ✅ OK | CONFORME : 41 exigence(s) de role, toutes satisfaites (129 cle(s) declaree(s) par l'instance). |
| P32 | Intrants exiges par les roles : tous fournis | — | ✅ OK | CONFORME : 41 exigence(s) de role, toutes satisfaites (130 cle(s) declaree(s) par l'instance). |
| P33 | Aucune collision de port entre roles co-localises | — | ✅ OK | CONFORME : 33 revendication(s) de port, aucune collision entre roles co-localises (38 groupes). |
| P34 | Chaque document declare son lecteur | — | ✅ OK | 42 document(s) declarent leur lecteur (26 genere(s) exempte(s)). |
| P35 | Toute application exigeant une base en a une au plan | — | ✅ OK | 5 application(s) exigeant une base l'ont toutes (4 entree(s) au registre). |
@ -55,15 +55,14 @@
| P40 | Parente : l'ecosysteme sait de quoi il descend | — | ✅ OK | Parente coherente : 4 depot(s), tous retrouves, tous porteurs d'un remote. |
| P41 | Resolution d'instance : une seule, partagee | — | ✅ OK | Resolution unique : 48 script(s) passent par `inventory_rules`, 3 exemption(s) nommee(s). |
| P42 | L'edge porte les noms qu'il publie | — | ✅ OK | 4 edge(s) emettent un certificat portant les noms publies (OPS-Chezlepro-lab/principal, OPS-Chezlepro/principal, OPS-Technolibre/principal, OPS-Patient0/product |
| P43 | Frontiere : le devis voit les machines du site | — | ✅ OK | Devis de la frontiere : 5 machine(s) du plan retrouvees, 57 regle(s) du site. |
| P43 | Frontiere : le devis voit les machines du site | — | ✅ OK | Devis de la frontiere : 5 machine(s) du plan retrouvees, 60 regle(s) du site. |
| P44 | Integrations : le serveur avant ses clients | — | ✅ OK | 4 integration(s) appliquent leur serveur avant leurs clients. |
| P45 | Pare-feu Proxmox : arme sur les VNet SDN, jamais ailleurs | — | ✅ OK | Le pare-feu Proxmox ne s'arme que sur un VNet SDN (4 cas evalues, dont un qui doit rendre VRAI). |
| P46 | Plancher /etc/hosts : un seul role en decide | — | ✅ OK | Un seul maitre du plancher — roles/hosts_statiques/tasks/main.yml : manage_etc_hosts: false ; et le gabarit maitre est pose (roles/hosts_statiques/templates/hos |
| P47 | Zones inverses : couvrir l'occupe, et rien de plus | — | ✅ OK | Les zones inverses couvrent l'occupe et rien de plus (5 cas evalues, dont un site a quatre zones et un tenant a une). |
| P48 | La carte d'orientation designe ce qui existe, et compte juste | — | ❌ ECHEC | La carte d'orientation ne dit plus vrai :
- « README de roles » : la carte annonce 61, le depot en compte 62 |
| P48 | La carte d'orientation designe ce qui existe, et compte juste | — | ✅ OK | La carte designe 84 chemin(s) qui existent, et ses 7 chiffres correspondent a la mesure. |
| P49 | Registre des flux : la matrice d'audit est a jour | — | ✅ OK | Le registre des flux reproduit exactement ce que les `meta/flux.yml` declarent (113 lignes). |
| P50 | Silences : un refus muet est declare, place en dernier, et motive | — | ✅ OK | 2 silence(s) declare(s), tous en sequence > 1 (la plus haute des 122 regles `pass`), tous non consignes et tous motives. |
| P50 | Silences : un refus muet est declare, place en dernier, et motive | — | ✅ OK | 2 silence(s) declare(s), tous en sequence > 1 (la plus haute des 125 regles `pass`), tous non consignes et tous motives. |
| P51 | Collections : toutes declarees, toutes epinglees | — | ✅ OK | 3 collection(s) et 2 bibliotheque(s) Python declarees et epinglees : ansible.posix==1.6.2, community.general==10.3.0, community.postgresql==3.10.2 |
| P52 | Materialiser n'exige pas d'entrer dans le tenant | — | ✅ OK | `creer-vm` confirme par l'agent invite (API des hyperviseurs, deja utilisee pour creer), sans exiger d'entrer dans le tenant. |