Set-OPS-Public/docs/audit/reference-avant-reconstruction-2026-08-08.md
Daniel Allaire c7fe250520 idempotence de la flotte : zero changed, et le zero est verifie
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>
2026-08-09 15:00:43 -04:00

132 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# É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é.