924 (rejeu depuis zero) -> 17 (2e passage) -> 0 (3e). Zero tache changed, zero echec sur les quatorze hotes. Le depot n'avait jamais fait ce test a l'echelle de la flotte. Verification du zero, parce qu'un zero peut signifier que les roles ne font plus rien : PLUS de taches se sont executees au passage a vide qu'au rejeu (2266 contre 2152). Elles ont toutes tourne et toutes trouve le systeme conforme. Un zero obtenu avec MOINS de taches aurait dit l'inverse. Ce que le test a rapporte : trois defauts, dont deux n'etaient pas des defauts d'idempotence mais des PANNES SILENCIEUSES — node_exporter mourait a chaque renouvellement de certificat sur les 14 hotes, et chaque deploiement invalidait les jetons OAuth2 de la forge. Le chiffre devient la ligne de base : un deploiement futur qui rapporte changed sur une flotte non modifiee signale desormais quelque chose. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
132 lines
6.4 KiB
Markdown
132 lines
6.4 KiB
Markdown
# État de référence — avant reconstruction from-zero
|
||
|
||
> Figé le 2026-08-08, écosystème **chezlepro** (index 17, 14 VM), avant destruction et
|
||
> rejeu complet du plan. **Ce document existe pour que « identique » soit prouvable
|
||
> plutôt que ressenti.** Toute divergence après reconstruction se lit contre lui.
|
||
|
||
## Les cinq devis, avant
|
||
```
|
||
identite CONFORME : le réel correspond au déclaré (1 compte(s) dans l'annuaire).
|
||
certificats CONFORME : aucun certificat servi n'est en fin de vie.
|
||
expositions CONFORME : toute exposition déclarée répond, des deux points de vue.
|
||
postgresql CONFORME : chiffrement imposé, et aucun réseau hors du supernet dérivé.
|
||
courriel CONFORME : la chaîne tient, de la résolution LDAP à la boîte.
|
||
```
|
||
|
||
## Ce que la flotte porte
|
||
```
|
||
backup-01 10.27.18.21 1 service(s) metier
|
||
collab-01 10.27.21.21 3 service(s) metier
|
||
data-sql-01 10.27.18.11 2 service(s) metier
|
||
edge-mta-01 10.27.16.21 2 service(s) metier
|
||
forge-01 10.27.21.11 1 service(s) metier
|
||
idm-01 10.27.17.11 3 service(s) metier
|
||
infra-dns-01 10.27.19.11 1 service(s) metier
|
||
infra-edge-01 10.27.16.11 2 service(s) metier
|
||
infra-mail-01 10.27.19.31 2 service(s) metier
|
||
infra-pki-01 10.27.19.21 2 service(s) metier
|
||
mon-01 10.27.20.21 6 service(s) metier
|
||
obs-01 10.27.20.11 2 service(s) metier
|
||
web-dorsal-01 10.27.21.41 2 service(s) metier
|
||
web-frontal-01 10.27.21.31 2 service(s) metier
|
||
```
|
||
|
||
## Ce qui sera perdu et devra être refait à la main
|
||
|
||
| Objet | Conséquence | Geste de reprise |
|
||
|---|---|---|
|
||
| **Clé racine de l'AC** (`/etc/step-ca/secrets/root_ca_key`) | la racine installée dans le navigateur devient inutile ; tous les certificats changent | `make ca-racine` + réinstaller, en comparant l'empreinte (§6.3) |
|
||
| **Mot de passe du compte `sysadmin`** | l'annuaire est recréé vide, puis amorcé | relever le jeton d'amorçage en voûte (§6.1) et le changer |
|
||
| **Contenu applicatif** (dépôts Forgejo, fichiers Nextcloud, courriels, tableaux Grafana) | non sauvegardé, non reconstructible par le code | aucun — assumé : c'est un POC |
|
||
|
||
> Ce qui **survit** : les deux voûtes et `~/.config/setops-vault-pass` vivent hors dépôt
|
||
> et hors cluster ; le code est sur `eregion.chezlepro.ca` (192.168.12.201), machine
|
||
> distincte du tenant. Rien de ce qui est nécessaire au rejeu n'est dans les 14 VM.
|
||
|
||
|
||
---
|
||
|
||
## Après reconstruction — 2026-08-09
|
||
|
||
Écosystème détruit (14 VM, disques compris) puis **rejoué depuis le plan seul**. Aucune
|
||
sauvegarde restaurée : ni LDAP, ni base, ni certificat, ni fichier.
|
||
|
||
```
|
||
identite CONFORME
|
||
certificats CONFORME
|
||
expositions CONFORME
|
||
postgresql CONFORME
|
||
courriel CONFORME
|
||
```
|
||
|
||
**Cinq sur cinq, identiques à la référence.** C'est la première fois que le dépôt peut dire
|
||
que le système reconstruit est celui que le plan décrit — au lieu de dire que le dépôt est
|
||
cohérent avec lui-même.
|
||
|
||
### Les six défauts que seul un rejeu depuis zéro pouvait montrer
|
||
|
||
| # | Défaut | Pourquoi il dormait |
|
||
|---|---|---|
|
||
| 1 | `amorcage_acces_courriel` jamais déclaré par le tenant | le compte existait déjà, le garde-fou n'avait jamais eu à se déclencher |
|
||
| 2 | rôles de realm créés **après** leur attachement aux groupes | un passage précédent les avait créés |
|
||
| 3 | claim de groupes posé **avant** les clients OIDC | les clients existaient déjà |
|
||
| 4 | écriture Keycloak annulée par le collecteur de transactions | la synchro LDAP complète ne se rejoue pas en exploitation |
|
||
| 5 | `grafana-cli` lancé avant que Grafana ait fini de démarrer | le service tournait depuis toujours |
|
||
| 6 | port d'Alloy (12345) en collision avec le SASL de Dovecot | Alloy tenait le port ; c'est **Dovecot** qui échouait, en silence |
|
||
|
||
Trois défauts d'ordre, deux courses de premier démarrage, un conflit de port. **Aucun
|
||
n'était visible à un redéploiement**, et aucun aux 31 preuves statiques — elles lisent le
|
||
dépôt, pas la machine.
|
||
|
||
Le sixième mérite d'être relu : le conflit existait depuis toujours, mais dans l'autre
|
||
sens. Alloy tenait `12345` et l'écoute SASL de Dovecot échouait sans que personne ne le
|
||
voie. La reconstruction a inversé l'ordre de démarrage et rendu visible un défaut qui
|
||
était là depuis le début.
|
||
|
||
### Ce qui a dû être refait à la main
|
||
|
||
- **La base de Grafana** : le premier démarrage, interrompu par le défaut nº 5, avait
|
||
laissé un schéma à moitié migré (`no such column: with_credentials`). Base mise de côté,
|
||
recréée par Grafana — 95 s pour lier son port, ce qui explique la course.
|
||
- **Rien d'autre.** Ni certificat, ni compte, ni zone DNS, ni base de données.
|
||
|
||
|
||
---
|
||
|
||
## Idempotence de la flotte — référence du 2026-08-09
|
||
|
||
Mesure faite après la seconde reconstruction, en rejouant `make deployer-tout` sur une
|
||
flotte intacte. Le dépôt n'avait jamais fait ce test à l'échelle de la flotte.
|
||
|
||
```
|
||
plays taches ok changed sautees
|
||
rejeu depuis zero 61 2152 924 443
|
||
2e passage 30 2249 17 ...
|
||
3e passage (apres) 30 2266 0 227
|
||
```
|
||
|
||
**Zéro tâche `changed`, zéro échec.**
|
||
|
||
Et ce zéro n'est pas du silence : **plus de tâches se sont exécutées au passage à vide
|
||
qu'au rejeu** (2266 contre 2152). Elles ont toutes tourné, et toutes trouvé le système
|
||
conforme. Un zéro obtenu avec moins de tâches aurait signifié l'inverse — des rôles qui ne
|
||
font plus leur travail.
|
||
|
||
### Ce que les 17 du deuxième passage cachaient
|
||
|
||
| Tâche | Ce que c'était vraiment |
|
||
|---|---|
|
||
| 13× `Activer et demarrer node_exporter` | **le service était mort** — tué par `SIGHUP` à chaque renouvellement de certificat |
|
||
| 2× Prometheus | liste de cibles non ordonnée (`intersect` rend un ensemble) |
|
||
| 2× Forgejo | **le dépôt faisait tourner le secret JWT du service** à chaque déploiement |
|
||
|
||
Deux des trois n'étaient pas des défauts d'idempotence : c'étaient des **pannes**, qu'un
|
||
compte de `changed` a rendues visibles. La collecte de métriques s'arrêtait toutes les
|
||
24 heures sur les quatorze hôtes, et les jetons OAuth2 de la forge étaient invalidés à
|
||
chaque passage. Ni l'une ni l'autre ne se signalait autrement.
|
||
|
||
### À quoi sert ce chiffre
|
||
|
||
Il devient la **ligne de base**. Un déploiement futur qui rapporte `changed` sur une flotte
|
||
non modifiée signale quelque chose : soit une dérive du système, soit un rôle qui a cessé
|
||
d'être idempotent. Tant que le fond était à 17, ce signal était noyé.
|