From 5880b22d5ae9a719d09149328b67d10ab0bbacd7 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Thu, 10 Sep 2026 04:05:28 -0400 Subject: [PATCH] D-87 : ce que l hebergeur n a pas le droit de VOIR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Question posee : quels roles ne pas embarquer dans le site ? La table de mutualisation existait et repondait presque — mais une de ses lignes CONTREDISAIT ce qui tourne. Elle disait « observabilite | oui | l hebergeur surveille ses locataires ». Or chaque ecosysteme a son propre Icinga, et celui du site ne voit que ses sept machines. L implementation avait raison, la doctrine avait tort. Et cette case autorisait ce que la ligne du dessous interdit. LES JOURNAUX CONTIENNENT DU CONTENU — un mot de passe dans un message d erreur, une donnee metier dans une trace, qui a fait quoi et quand. Un hebergeur qui ingere les journaux de son locataire en sait PLUS que s il detenait son annuaire : l annuaire dit qui existe, les journaux disent ce qu ils font. Decoupee en trois : disponibilite oui (une VM tombee est un fait de la fabric), metriques oui avec reserve (elles disent quand et combien, ce qui suffit a lire l activite d une organisation), journaux NON. ET LA LIGNE PKI EST TRANCHEE : NON. Une AC intermediaire signee par l hote lui donnerait le pouvoir d emettre des certificats valides pour les noms du locataire — donc de se presenter comme n importe lequel de ses services, devant les propres machines du locataire, qui les accepteraient puisque c est ce que la chaine de confiance leur demande. Meme pouvoir que l annuaire, sous une forme moins visible : aucune trace cote locataire. Une PKI par ecosysteme, jamais derivee de l hote. LE REVERS, MESURE ET ASSUME : le site n a ni client_journal ni client_metrique, aucun loki ni prometheus. A refuser de voir ceux des locataires, il s est prive des siens. Le remede n est pas d assouplir la regle mais de lui donner sa propre pile. Verifie par ailleurs : rien d intime n est au site aujourd hui. La frontiere etait tenue en pratique avant d etre ecrite au net. make prouver : CONFORME, 64 OK, 0 echec, 0 saute. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q --- CHANGELOG.md | 58 +++++++++++++++++++++++++++++++ docs/carte-set-ops.md | 2 +- docs/decisions-architecture.md | 1 + docs/filiation-emancipation.md | 62 +++++++++++++++++++++++++++++++--- 4 files changed, 118 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16e93df..42facbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,63 @@ # CHANGELOG — Set-OPS +## 2026-09-10 (4) — Ce que l'hebergeur n'a pas le droit de VOIR (D-87) + +Question posee : *« quels roles ne dois-je pas embarquer dans le site ? »* + +La table de mutualisation de `filiation-emancipation.md` existait deja et repondait presque. +Mais mise a l'epreuve, **une de ses lignes contredisait ce qui tourne**. + +### La ligne qui se contredisait + + | observabilite | oui | l'hebergeur surveille ses locataires | + +Or chaque ecosysteme a son propre Icinga, et celui du site ne voit que ses **sept** +machines (mesure). L'implementation avait raison, la doctrine avait tort. + +Et surtout : cette case autorisait ce que la ligne du dessous interdit. **Les journaux +contiennent du CONTENU** — un mot de passe dans un message d'erreur, une donnee metier dans +une trace, qui a fait quoi et quand. Un hebergeur qui ingere les journaux de son locataire +en sait **plus** que s'il detenait son annuaire : *l'annuaire dit qui existe, les journaux +disent ce qu'ils font.* + +Decoupee en trois : + + disponibilite (est-ce debout ?) oui une VM tombee est un fait de la fabric + metriques (charge, disque) oui, reserve disent quand et combien, pas quoi + journaux NON contiennent le contenu + +### Et la ligne PKI, « a trancher », est tranchee : non + +Elle notait qu'*une AC intermediaire signee par l'hote est possible*. Elle l'est +techniquement — et c'est precisement ce qu'il ne faut pas faire. + +Une intermediaire signee par l'hote lui donne le pouvoir d'emettre des certificats +**valides pour les noms du locataire**. Il peut alors se presenter comme n'importe lequel +de ses services, devant les propres machines du locataire — qui les accepteront, puisque +c'est exactement ce que la chaine de confiance leur demande de faire. + +Meme pouvoir que l'annuaire, sous une forme **moins visible** : rien dans la configuration +du locataire, aucune trace de son cote, et la verification passe. + +**Une PKI par ecosysteme, jamais derivee de l'hote.** C'est deja ce qui tourne ; la ligne +cesse de laisser la porte entrouverte. + +### Le revers, mesure et assume + +Le site ne porte **ni `client_journal` ni `client_metrique`**, et aucun `loki` ni +`prometheus`. Ses sept machines n'expedient rien nulle part : **l'hebergeur ne peut pas +lire ses propres journaux**. + +C'est la consequence directe de la frontiere — a refuser de voir ceux des locataires, il +s'est prive des siens. Le remede n'est pas d'assouplir la regle, c'est de lui donner **sa +propre pile**, sans aucun lien avec celle d'un tenant. + +### Ce que la mesure a confirme par ailleurs + +Rien d'intime n'est au site aujourd'hui. `openldap`, `keycloak`, `oauth2_proxy`, `loki`, +`nextcloud`, `collabora`, `dovecot`, `rspamd`, `web_frontal`, `web_dorsal` : tous +**tenant seulement**. La frontiere etait tenue en pratique avant d'etre ecrite au net. + ## 2026-09-10 (3) — Les cinq sondes qui manquaient le plus **20 sondes sur 19 roles. 23 services distincts, 70 instances, 67 au vert.** diff --git a/docs/carte-set-ops.md b/docs/carte-set-ops.md index 165755e..98ff451 100644 --- a/docs/carte-set-ops.md +++ b/docs/carte-set-ops.md @@ -28,7 +28,7 @@ README de rôles). Cette page comble ces deux trous. | documents | 40 | `docs/*.md` | | pièces d'audit | 41 | `docs/audit/*` | | unités de wiki | 27 | `wiki/*.md` | -| décisions en vigueur | 83 | lignes `\| **D-nn** \|` de `decisions-architecture.md` | +| décisions en vigueur | 84 | lignes `\| **D-nn** \|` de `decisions-architecture.md` | | décisions renversées | 3 | lignes `\| **D-nn** —` du même document | ## 1. À lire d'abord (dans l'ordre) diff --git a/docs/decisions-architecture.md b/docs/decisions-architecture.md index 041ebed..7361d49 100644 --- a/docs/decisions-architecture.md +++ b/docs/decisions-architecture.md @@ -60,6 +60,7 @@ sont les seules vérifiables. | **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**, 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-86** | **La supervision se déploie juste après la PKI, pas à la fin** | L'observabilité (`prometheus`, `loki`, `grafana`) et le **moteur** de supervision (`icinga`) passent en couche 4, immédiatement après `client_pki` ; les agents qui les nourrissent (`client_metrique`, `client_journal`, `client_sante`) en couche 5. **Le raisonnement** : ce qui se déploie ensuite l'est *sous l'œil* de la supervision — une unité qui casse se voit à la minute, pas à la fin. Une **reconstruction depuis zéro** est précisément le moment où l'on a le plus besoin de voir, et c'était le seul moment où l'on ne voyait rien. **Déplacer les serveurs sans les agents n'aurait rien changé** : ce sont les agents qui rapportent, et ils étaient en dernière couche. **Ce que ça a coûté en dépendances** : `serveur_postgresql` monte aussi (il n'exige rien lui-même, et `icinga` l'exige). **Ce qui reste tard, à dessein** : `icingaweb2` et `oauth2_proxy` réclament LDAP et Keycloak — c'est la CONSOLE, pas la mesure. L'interface humaine peut attendre. **Limite dite franchement** : les *notifications* dépendent de `client_smtp`, encore en dernière couche — pendant une reconstruction, l'état est mesuré et consultable, mais rien ne part par courriel avant la fin. **CE QUI REND CE DÉPLACEMENT POSSIBLE**, et qui n'est pas un détail : le DNS (`powerdns`, `resolveur`) reste en couche 6, donc *après* la supervision. Or `icinga` joint sa base par un **nom** (`data-sql-01.chezlepro.internal`), et `client_sante` pousse vers un **nom**. Ça tient parce que le **plancher `/etc/hosts`**, posé dès la couche 1 par `hosts_statiques`, porte déjà les 34 entrées de l'écosystème — vérifié. C'est exactement ce pour quoi il existe : *« il ne s'installe pas, il rend installable »*. Sans lui, cette décision serait impossible. **P08** valide l'ordre : aucune arête en arrière | `docs/couches-deploiement.yml`, `catalogue-services.md` §Ordre | **P08** | +| **D-87** | **Ce que l'hébergeur n'a pas le droit de VOIR** — l'observabilité découpée, la PKI tranchée | La question *« quels rôles ne dois-je pas embarquer dans le site ? »* a mis à l'épreuve la table de mutualisation de `filiation-emancipation.md`, et **une ligne contredisait ce qui tourne**. Elle disait « observabilité \| oui \| l'hébergeur surveille ses locataires » — or chaque écosystème a son propre Icinga, et celui du site ne voit que ses sept machines (mesuré). Surtout, elle autorisait en une case ce que la ligne du dessous interdit : **les journaux contiennent du contenu** — un mot de passe dans un message d'erreur, une donnée métier dans une trace. Un hébergeur qui ingère les journaux de son locataire en sait **plus** que s'il détenait son annuaire ; l'annuaire dit qui existe, les journaux disent ce qu'ils font. **Découpée en trois** : *disponibilité* oui (une VM tombée est un fait de la fabric), *métriques* oui avec réserve (elles disent quand et combien, ce qui suffit à lire l'activité d'une organisation), *journaux* **non**. **Et la ligne PKI, « à trancher », est tranchée : non.** Une AC intermédiaire signée par l'hôte lui donnerait le pouvoir d'émettre des certificats valides pour les noms du locataire, donc de se présenter comme n'importe lequel de ses services — devant les propres machines du locataire, qui les accepteraient, puisque c'est ce que la chaîne de confiance leur demande. Même pouvoir que l'annuaire, sous une forme **moins visible** : aucune trace côté locataire. Une PKI par écosystème, jamais dérivée de l'hôte. **Le revers, mesuré et assumé** : le site n'a NI `client_journal` NI `client_metrique`, aucun `loki` ni `prometheus` — à refuser de voir ceux des locataires, il s'est privé des siens. Le remède n'est pas d'assouplir la règle, c'est de lui donner sa propre pile | `filiation-emancipation.md` §mutualisable | — | | **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` | — | diff --git a/docs/filiation-emancipation.md b/docs/filiation-emancipation.md index 2e94280..036b43d 100644 --- a/docs/filiation-emancipation.md +++ b/docs/filiation-emancipation.md @@ -54,18 +54,72 @@ soi dès le premier jour. ## Ce qui est mutualisable, et ce qui ne l'est pas +> **Le critère, à deux tranchants.** Un rôle appartient au SITE s'il sert la **relation** +> avec les locataires, ou les machines du site elles-mêmes. Il appartient au TENANT s'il +> sert des **utilisateurs** ou des **applications**. À l'usage, ça se décide sur deux +> questions plus dures : +> +> 1. **Ce que le site ne doit pas pouvoir VOIR** — sinon l'hébergement n'est plus +> souverain, quelles que soient les intentions. +> 2. **Ce que le tenant doit pouvoir EMPORTER** — sinon l'émancipation est un mot. + | service | mutualisable | remarque | |---|---|---| | forge (génome) | oui | `serveur_ops_forge_externe` | | source d'artefacts | oui | `client_artefacts` se désactive seul si aucune n'existe | -| sauvegarde | oui | `client_backup_cible` pointe déjà hors de l'écosystème | -| observabilité | oui | l'hébergeur surveille ses locataires | -| relais courriel | oui | | +| sauvegarde | oui | `client_backup_cible` pointe déjà hors de l'écosystème ; le site héberge du **chiffré côté client** et ne peut rien en juger | +| **disponibilité** (est-ce debout ?) | oui | c'est sa fabric : il doit savoir qu'une VM est tombée | +| **métriques** (charge, disque) | oui, avec réserve | révèlent des **rythmes d'activité**, pas du contenu | +| **journaux** | **non** | voir ci-dessous — plus intime que l'annuaire | +| relais courriel | oui | l'enveloppe transite ; le contenu appartient au locataire | | DNS | partiellement | un sous-domaine délégué, pas la zone entière | -| **PKI** | à trancher | une AC intermédiaire signée par l'hôte est possible, mais l'AC **définit l'identité** de l'écosystème | +| **PKI** | **non** (tranché le 2026-09-10) | voir ci-dessous | | **identité** (LDAP/SSO) | le plus intime | mutualiser l'annuaire, c'est confier ses gens | | **la voûte** | **jamais** | les secrets ne se mutualisent pas, à aucun âge | +### Pourquoi « observabilité » a été découpée en trois + +La ligne disait : *« observabilité | oui | l'hébergeur surveille ses locataires »*. Elle +était trop grossière, et elle **contredisait ce qui tourne** : chaque écosystème a son +propre Icinga, et celui du site ne voit que ses sept machines (mesuré le 2026-09-10). + +Surtout, elle autorisait en une case ce que la ligne du dessous interdit. **Les journaux +contiennent du contenu** — un mot de passe dans un message d'erreur, une donnée métier dans +une trace, qui a fait quoi et quand. Un hébergeur qui ingère les journaux de son locataire +en sait **plus** que s'il détenait son annuaire : l'annuaire dit qui existe, les journaux +disent ce qu'ils font. + +La disponibilité, elle, est légitime : une VM tombée est un fait de la **fabric**, que +l'hébergeur porte. Les métriques sont entre les deux — elles ne disent pas *quoi*, mais +elles disent *quand* et *combien*, ce qui suffit à lire l'activité d'une organisation. + +### Pourquoi la ligne PKI est tranchée : **non** + +Elle disait « à trancher », en notant qu'*une AC intermédiaire signée par l'hôte est +possible*. Elle l'est techniquement — et c'est précisément ce qu'il ne faut pas faire. + +Une intermédiaire signée par l'hôte lui donne le pouvoir d'**émettre des certificats +valides pour les noms du locataire**. Il peut alors se présenter comme n'importe lequel de +ses services, y compris devant les propres machines du locataire, qui les accepteront sans +sourciller — c'est exactement ce que la chaîne de confiance leur demande de faire. + +C'est le même pouvoir que l'annuaire, sous une forme **moins visible** : rien n'apparaît +dans la configuration du locataire, aucune trace côté locataire, et la vérification passe. + +**Une PKI par écosystème, jamais dérivée de l'hôte.** C'est déjà ce qui tourne ; la ligne +ne fait que cesser de laisser la porte entrouverte. + +### Le revers : le site n'a pas d'observabilité du tout + +Mesure du 2026-09-10 : le site ne porte **ni `client_journal` ni `client_metrique`**, et +aucun `loki` ni `prometheus`. Ses sept machines n'expédient rien nulle part — l'hébergeur +ne peut pas lire ses propres journaux. + +C'est la conséquence directe de la frontière : à refuser de voir ceux des locataires, il +s'est privé des siens. Le remède n'est pas d'assouplir la règle, c'est de lui donner **sa +propre pile** — un `loki` et un `prometheus` du site, pour les machines du site, sans +aucun lien avec ceux d'un tenant. + ## L'insémination — le premier lien, et le seul que le SITE ait le droit d'avoir Entre tenants, le zéro-confiance est le défaut : la frontière refuse tout ce qui n'est pas