Bascule par make forge-cles, mesuree ETANCHE. Reconstruction complete de Technolibre : depot apporte en colis a l'insemination, tire en SSH apres l'armement, flotte remontee, temoins d'etat intacts sur les 9 machines qui en portent. 36 minutes depuis la reprise. 95 preuves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
149 lines
9.4 KiB
Markdown
149 lines
9.4 KiB
Markdown
# Dépôts privés sur la forge du site — conception du chantier
|
|
|
|
> **Pour qui :** le mainteneur qui décide de ce chantier puis le conduit, et quiconque se demande
|
|
> pourquoi un runner ne lit que ses propres dépôts.
|
|
|
|
Préparé le 2026-10-11. Décisions D1 à D3 prises le même jour par Daniel : les trois recommandations.
|
|
|
|
## 1. Le constat
|
|
|
|
Sur la forge du site, l'organisation `genome` porte cinq dépôts, tous **publics** :
|
|
|
|
| Dépôt | Contenu | Qui en a besoin |
|
|
|---|---|---|
|
|
| `set-ops-public` | le moteur | tous les runners |
|
|
| `set-ops-modeles` | les modèles génériques | le runner du site |
|
|
| `site-chezlepro` | la carte de la fabric, le plan du site | le runner du site |
|
|
| `ops-chezlepro` | le plan, l'inventaire et la face de Chezlepro | son runner, le runner du site |
|
|
| `ops-technolibre` | le plan, l'inventaire et la face de Technolibre | son runner, le runner du site |
|
|
|
|
Mesuré le 2026-10-11 : depuis le runner de Technolibre, `git ls-remote` sans identifiant lit la
|
|
tête de `ops-chezlepro` (`b4fbd85`) et de `site-chezlepro` (`51dae24`). Chaque locataire peut donc
|
|
lire le plan de l'autre, et la carte du site. **Aucun n'en a besoin** : chaque runner de locataire
|
|
ne clone que le moteur et son propre dépôt ; ce que le site lui donne arrive par la fiche déposée
|
|
dans son dépôt.
|
|
|
|
D'où ça vient : le 2026-09-12, à la première reconstruction du site, les dépôts créés privés ont
|
|
cassé le clonage anonyme des runners. Ils sont passés publics, avec l'argument que seuls ceux
|
|
qui ont franchi la frontière joignent la forge (`scripts/forge_amorcer.py`). Les autres locataires
|
|
en font partie.
|
|
|
|
## 2. La cible
|
|
|
|
- **Publics** : `set-ops-public` et `set-ops-modeles`. Ils sont génériques, identiques pour tous.
|
|
- **Privés** : `site-chezlepro` et chaque `ops-<locataire>`.
|
|
- **Le runner du site** lit et pousse tous les dépôts avec sa clé, déjà enregistrée comme clé de
|
|
déploiement en écriture par `genome_pousser.yml`. Mesuré le 2026-10-11 : il lit les cinq dépôts
|
|
en SSH, avec une vérification stricte de la clé d'hôte. Rien à créer pour lui.
|
|
- **Le runner d'un locataire** lit son seul dépôt, avec une clé de déploiement **en lecture
|
|
seule** : la clé publique de son runner, déjà déclarée au plan (`ssh_baseline_cles_admin`) et
|
|
dont la privée lui est remise à l'armement depuis sa voûte (`vault_runner_cle_ssh`).
|
|
- **Aucun secret ne change de main.** Le locataire publie la clé publique de son runner dans sa
|
|
face réseau ; le site l'enregistre sur le dépôt de ce locataire, avec ses propres
|
|
identifiants d'administration de la forge (`vault_forgejo_admin`, déjà dans sa voûte).
|
|
|
|
### Éprouvé le 2026-10-11 (étape 1)
|
|
|
|
Clés de lecture enregistrées par `make forge-cles`, flux posé sur `site-forge-01` et à la
|
|
frontière. Depuis chaque runner, `git ls-remote` en SSH, clé d'hôte de la forge épinglée (lue
|
|
sur sa machine par l'accès d'administration) :
|
|
|
|
| Depuis | son dépôt | l'autre locataire | `site-chezlepro` | `set-ops-public` |
|
|
|---|---|---|---|---|
|
|
| runner de Technolibre | lu (`0172dd8`) | refusé | refusé | refusé |
|
|
| runner de Chezlepro | lu (`74d5567`) | refusé | refusé | refusé |
|
|
|
|
Le refus vient de la forge (« Deploy Key … is not authorized to read »), **alors que les dépôts
|
|
sont encore publics** : une clé de déploiement ne vaut que pour le dépôt qui l'a enregistrée.
|
|
Conséquence : le moteur, public, continue de se cloner en HTTPS sans identifiant ; seuls les
|
|
dépôts privés passent par SSH.
|
|
|
|
## 3. Le nœud : l'insémination
|
|
|
|
Le site amorce le runner d'un locataire **avant** que celui-ci ait reçu sa clé stable (elle
|
|
arrive à l'armement, geste humain, après). Pendant l'insémination, le rôle `serveur_ops` clone
|
|
pourtant le dépôt du locataire : avec un dépôt privé, ce clonage échoue. Même chose au premier
|
|
déploiement du runner du site, dont la clé est neuve.
|
|
|
|
**Remède proposé : le colis.** Quand un runner ne peut pas encore lire un dépôt privé, le
|
|
contrôleur qui joue `serveur_ops` (le runner du site pendant l'insémination, le poste
|
|
ailleurs) lui apporte ce dépôt en `git bundle`. Le mécanisme existe déjà : `genome_colis.py` porte
|
|
le génome du poste au runner du site. Le runner clone le colis, puis pointe `origin` vers l'URL
|
|
SSH de la forge. Ses tirages suivants passent par sa clé, une fois armé.
|
|
|
|
## 4. Les décisions à prendre
|
|
|
|
**D1 — Comment le runner d'un locataire lit-il son dépôt ?**
|
|
- *Clé de déploiement en SSH (recommandé).* Le runner continue de tirer lui-même ; il garde son
|
|
autonomie (émancipation, `make` lancé sur le runner, garde `verifier_genome_a_jour`). Coût : un
|
|
flux nouveau, du runner de chaque locataire vers la forge du site, en SSH.
|
|
- *Colis seulement.* Aucun flux nouveau, aucune clé de déploiement pour les locataires : le
|
|
contrôleur apporte toujours le dépôt. Mais le runner ne tire plus son dépôt lui-même, et sa
|
|
garde de génome n'a plus de forge à laquelle se comparer.
|
|
|
|
**D2 — Sur quelle écoute SSH ?**
|
|
- *Le `sshd` de la machine, port 22 (recommandé pour commencer).* Le runner du site et le poste
|
|
l'utilisent déjà pour pousser ; l'utilisateur `git` y est contraint par la forge. Le flux
|
|
n'ouvre que les adresses des runners de locataires, pas leurs supernets.
|
|
- *Le serveur SSH intégré de Forgejo, sur un port dédié.* Il n'expose pas le `sshd` de la
|
|
machine, mais sa cohabitation avec le `sshd` existant reste à éprouver avant de s'y fier.
|
|
|
|
**D3 — La preuve.** Ce chantier touche l'insémination : je propose de le prouver par une
|
|
reconstruction complète de Technolibre (raser, créer, inséminer, armer, monter), dépôts
|
|
privés, avant de reprendre le lot 3b.
|
|
|
|
## 5. Ce qui change dans le code
|
|
|
|
État au 2026-10-11 : tout ce tableau est écrit, sauf la bascule elle-même. La clé d'hôte de
|
|
la forge est déclarée dans le plan du site (`forge_ssh_cle_hote`), offerte par la fiche
|
|
(`serveur_ops_forge_cle_hote`) et copiée par chaque locataire. Le moteur reste cloné en HTTPS.
|
|
|
|
| Pièce | Changement |
|
|
|---|---|
|
|
| `serveur_ops_depots` | un drapeau `prive: true` sur les dépôts `instance`, `tenant` et `hebergeur` |
|
|
| `roles/serveur_ops` | URL SSH et clé du runner pour les dépôts privés ; colis du contrôleur quand le runner ne peut pas encore les lire ; clé d'hôte de la forge épinglée |
|
|
| `contexte.py` (face) | la face publie la clé publique de lecture du runner (`genome.cle_lecture`) |
|
|
| `contexte.py` (fiche) | la fiche du site publie la clé d'hôte SSH de sa forge, que le runner du locataire épingle |
|
|
| nouvelle cible `forge-cles` | le site enregistre, d'après les faces, la clé de lecture de chaque locataire sur son dépôt, et retire celles qui ne sont plus publiées |
|
|
| `forge_amorcer.py` | crée les dépôts privés comme privés |
|
|
| flux | `serveur_forge_site` : entrée SSH depuis les runners des locataires hébergés (paire nouvelle, résolue depuis les faces) ; `serveur_ops` : sortie correspondante |
|
|
| `genome_etat.yml` | lit la forge par SSH ou authentifié : l'API anonyme répondrait 404 pour un dépôt privé |
|
|
| `sonde-genome-servi` | ne compte plus que les dépôts publics (au moins le moteur) : c'est ce qu'un écosystème neuf clone sans rien détenir ; les privés sont suivis par `genome-etat`, `forge-cles` et les runners |
|
|
|
|
Inchangés : `sonde-genome-a-jour` (son repère ne compare que `set-ops-public`), le poste (il
|
|
pousse déjà en SSH), la console (`etat_forge` lit `origin`, qui deviendra l'URL SSH).
|
|
|
|
## 6. Les preuves à écrire
|
|
|
|
- **Hors ligne (`make prouver`)** : chaque dépôt `instance`, `tenant` ou `hebergeur` est déclaré
|
|
privé ; chaque face publie une clé de lecture, et cette clé est dans `ssh_baseline_cles_admin`.
|
|
- **Sur le terrain (`make forge-etancheite`)**, avec témoins :
|
|
- sans identifiant, un dépôt privé refuse et un dépôt public répond ;
|
|
- le runner d'un locataire lit son dépôt et **ne lit pas** celui de l'autre ;
|
|
- les clés de déploiement de chaque dépôt sont exactement : runner du site en écriture, runner
|
|
du locataire en lecture.
|
|
- **Par reconstruction** : D3.
|
|
|
|
## 7. L'ordre de bascule
|
|
|
|
**Fait le 2026-10-11, étapes 1 à 5.** Bascule par `make forge-cles CONFIRMER=true`, mesurée
|
|
ETANCHE par `make forge-etancheite`. Preuve par reconstruction de Technolibre (§D3) : le runner
|
|
neuf a reçu son dépôt en colis à l'insémination (il n'avait pas encore de clé), l'a tiré en SSH
|
|
une fois armé, et la flotte est remontée avec ses témoins d'état intacts. La reconstruction a
|
|
d'abord révélé un dossier SSH manquant sur une machine neuve (corrigé, `3fc16c8`).
|
|
|
|
Chaque étape se vérifie avant la suivante, et la bascule se défait d'un appel par dépôt
|
|
(repasser public).
|
|
|
|
1. **Éprouver** sur la forge du site, sans rien basculer : enregistrer la clé de lecture du
|
|
runner de Technolibre sur `ops-technolibre`, ouvrir le flux pour ce seul runner, et mesurer
|
|
qu'il lit son dépôt en SSH.
|
|
2. **Construire** le code et les preuves (§5, §6) ; `make verifier`.
|
|
3. **Déployer sans basculer** : flux et frontière (`make frontiere-appliquer CONFIRMER=true`,
|
|
lancé par Daniel), clés de déploiement, remotes SSH sur les trois runners. Les dépôts sont
|
|
encore publics : chaque runner doit déjà tirer en SSH.
|
|
4. **Basculer** `site-chezlepro`, `ops-chezlepro` et `ops-technolibre` en privé. Mesurer avec
|
|
`make forge-etancheite`, puis la veille des trois consoles.
|
|
5. **Prouver** par la reconstruction de Technolibre (D3).
|
|
6. Reprendre le lot 3b : les demandes vivent alors dans le dépôt de chaque locataire, lisibles
|
|
par lui et par le site seulement.
|