From c5fd3aa70bbea813d15d5d229fef5c5ac8d93414 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Sat, 8 Aug 2026 12:33:35 -0400 Subject: [PATCH] docs : tisser les devis dans les points d'entree, et corriger trois faits perimes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pas de refonte : 54 roles / 54 README, 34 documents, une carte, un registre de decisions. Le retard etait ailleurs — le travail du jour vivait dans son coin, les cinq devis n'existant que dans deux fichiers. Donc decouvrables seulement par qui connait le Makefile, ce qui contredit « exploitable sans IA ». Tisses dans les quatre points d'entree : ligne « Conformite du deploye » dans la carte, section « Ecrire, puis relire (D-68) » dans AGENTS.md, §6.0 du runbook (le premier reflexe), vue Reconstruction de la GUI. Le tissage a fait tomber trois affirmations perimees : - la carte annoncait 28 decisions, il y en a 66 en vigueur (D-01 -> D-69) ; - elle disait les acces « decides, non construits, ou=people et ou=groups restent vides » — mesure : un compte, un groupe, chaine exercee de bout en bout sur Icinga Web 2 le jour meme ; - la GUI parlait des « deux » devis d'infrastructure ; il y en a quatre. Formation et wiki differes : la reconstruction from-zero est le test de cette documentation, et enseigner une procedure que personne n'a executee serait enseigner une hypothese. Co-Authored-By: Claude Opus 5 --- AGENTS.md | 36 ++++++++++++++++++++++++++++++++++++ CHANGELOG.md | 33 +++++++++++++++++++++++++++++++++ docs/autorisation.md | 22 ++++++++++++++++++++++ docs/carte-set-ops.md | 8 +++++--- scripts/inventory_gui.py | 7 +++++-- 5 files changed, 101 insertions(+), 5 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 3b765e9..495032f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -177,6 +177,42 @@ Si `ansible-lint` n’est pas disponible, le signaler clairement. Ne pas invente --- +## Écrire, puis relire (D-68) + +`--syntax-check` et `ansible-lint` prouvent que le dépôt est cohérent **avec lui-même**. +C'est aussi ce que font les 30 preuves de `make prouver` : elles lisent le dépôt, sans le +moindre appel réseau. **Aucune ne demande au système déployé s'il ressemble à ce que le +dépôt annonce.** + +C'est dans cet angle que vivaient les défauts du 2026-08-08 : une politique de mot de +passe déclarée des deux côtés et appliquée d'aucun, une entrée LDAP figée à sa création, +le certificat de l'autorité expiré depuis huit heures, la livraison de courriel interne +différée en silence. Tous découverts en **relisant après avoir écrit**, aucun signalé par +un test. + +**La règle : écrire, puis relire et comparer — quelle que soit l'interface.** Choisir +celle dont le chemin de *lecture* parle le même langage que le chemin d'*écriture*. Ce +n'est **pas** « toujours préférer l'API » : la plupart de la flotte n'en a pas, et sur six +familles de défauts ce jour-là, deux seulement venaient d'un CLI — un module Ansible +(`ldap_entry`, qui crée sans jamais modifier) a commis la même faute. + +Cas connu à ne pas réapprendre : **`kcadm -s` sur une map** (`smtpServer`, `attributes`, +`config`) accepte la commande, **sort en succès et n'écrit rien**. Passer par l'API +d'administration pour ces objets, et relire (D-69). + +Les **devis de service** industrialisent cette relecture — voir `docs/devis-services.md` : + +```bash +make identite-plan make certificats-plan make expositions-plan +make postgresql-plan make courriel-plan +``` + +Ils ne modifient rien et sortent en code 1 s'il y a un écart. Après un changement qui +touche l'identité, les certificats, une exposition, la base ou le courriel, **lancer le +devis correspondant** : une tâche verte ne prouve pas que le service rend son service. + +--- + ## Règle pour les handlers Ansible Chaque rôle qui utilise `notify` doit contenir son handler dans le rôle lui-même. diff --git a/CHANGELOG.md b/CHANGELOG.md index c90c556..dc1c00c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,38 @@ # CHANGELOG — Set-OPS +## 2026-08-08 — Tisser le travail du jour dans les points d'entrée + +Question de l'exploitant : faut-il refondre la documentation ? **Non.** L'état mesuré ne le +justifie pas — 54 rôles, 54 README (couverture complète), 34 documents, une carte avec un +ordre de lecture, un registre de décisions. Une refonte ferait courir le vrai risque : +perdre le *pourquoi* accumulé, qui a pris des mois et ne se régénère pas. + +Ce qui était réellement en retard était petit et nommable : le travail du jour était +documenté **dans son coin**. Les cinq devis n'existaient que dans deux fichiers — leur +propre doc et le registre des décisions. Absents de la carte, d'`AGENTS.md`, du runbook du +sysadmin et de la GUI. Autrement dit : découvrables uniquement par qui connaît déjà le +Makefile — ce qui contredit « un sysadmin l'exploite sans IA ». + +Tissés dans les quatre points d'entrée : ligne « Conformité du déployé » dans la carte, +section « Écrire, puis relire (D-68) » dans `AGENTS.md`, **§6.0 du runbook** (le premier +réflexe avant de suivre quoi que ce soit), et la vue *Reconstruction* de la GUI — sa place +logique, puisque ce sont ces devis qui diront si un remontage a produit le système décrit. + +**Et le tissage a fait tomber trois affirmations périmées**, ce qui est sa vraie utilité : + +- la carte annonçait **28 décisions** ; il y en a **66 en vigueur** (D-01 → D-69, 3 + renversées) ; +- elle disait des accès et habilitations « **décidé, non construit** : `ou=people` et + `ou=groups` existent et restent vides ». Mesuré : un compte, un groupe, et la chaîne + LDAP → Keycloak → groupe → service exercée de bout en bout sur Icinga Web 2 le jour même ; +- la GUI parlait des « **deux** devis » d'infrastructure ; il y en a quatre depuis l'arrivée + du SDN EVPN et du pare-feu est-ouest. + +**Ce qui n'est pas fait, et pourquoi.** La formation et le wiki attendent — leur audience et +leur condition de vérité sont différentes. Un runbook que personne n'a suivi sauf son auteur +est une hypothèse ; la reconstruction from-zero est le test de cette documentation. Écrire +la formation avant, ce serait enseigner une procédure que personne n'a exécutée. + ## 2026-08-08 — D-68 / D-69 : la règle n'est pas « toujours l'API » Question de l'exploitant après deux pannes causées par `kcadm` : ne devrait-on pas toujours diff --git a/docs/autorisation.md b/docs/autorisation.md index 4408092..5e66602 100644 --- a/docs/autorisation.md +++ b/docs/autorisation.md @@ -96,6 +96,28 @@ départ, service par service — et il faudrait un déploiement pour révoquer q Ce qui suit est destiné au sysadmin le jour de la livraison. **C'est la partie utile de ce document.** +### 6.0 D'abord : demander au système où il en est + +Avant de suivre quoi que ce soit, cinq commandes disent l'état réel. Elles ne modifient +rien et sortent en erreur s'il y a un écart entre ce qui tourne et ce que le plan décrit. + +``` +make identite-plan # realm, fédération LDAP, mappeurs, politique de mot de passe, comptes +make certificats-plan # certificats sur disque contre certificats réellement servis +make expositions-plan # chaque service publié répond-il — depuis l'edge et depuis ton poste +make postgresql-plan # chiffrement imposé, et à quels réseaux +make courriel-plan # Postfix → LDAP → LMTP → Dovecot → IMAP, file d'attente comprise +``` + +C'est le premier réflexe à prendre, et pas seulement le jour de la livraison : après tout +changement, après une panne, avant d'appeler quelqu'un. `make deployer` **répare** ; +ces devis **constatent**. Le détail de ce qu'ils vérifient et de ce qu'ils ne vérifient +pas est dans `devis-services.md`. + +Un exemple de ce qu'ils voient et que rien d'autre ne voyait : le 2026-08-08, le +certificat de l'autorité elle-même était expiré depuis plus de huit heures, le +renouvellement échouant toutes les quatorze minutes. Aucun écran ne le disait. + ### 6.1 Récupérer le mot de passe d'amorçage ``` diff --git a/docs/carte-set-ops.md b/docs/carte-set-ops.md index 422c457..14bd933 100644 --- a/docs/carte-set-ops.md +++ b/docs/carte-set-ops.md @@ -21,8 +21,9 @@ code + les README de rôles). Cette page comble ces deux trous. | **Conceptions de domaine** | `docs/identite-sso.md`, `docs/courriel-conception.md`, `docs/bindings-conception.md`, `docs/dns-interne.md`, `docs/dimensionnement-ressources.md`, `docs/integrations-vm.md` | | **Réseau / pare-feu** | `docs/flux-conception.md` (le modèle) → `docs/registre-flux.md` (**généré**, matrice d'audit) → `docs/frontiere-opnsense.md` (la bordure nord/sud) ; underlay : `underlay.yml.example` + `make underlay` | | **Ordre de déploiement** | `docs/couches-deploiement.yml` (couches) + `docs/dependances-groupes.yml` (graphe) → `playbooks/site.yml` (**généré**, `make site`) | -| **Preuve / recette** | `docs/audit/affirmations.md` (registre), `make prouver` → `docs/audit/preuve-.md`, `docs/audit/plan-de-recette.md` (**généré** du wiki), `docs/audit/protocole-operateur-independant.md` | -| **Décisions d'architecture** | `docs/decisions-architecture.md` — **28 décisions**, pourquoi, où lire le détail, et ce qui les garde ; plus les **décisions renversées** et leur cause | +| **Conformité du déployé** | `docs/devis-services.md` — les **cinq devis de service** (`make identite-plan`, `certificats-plan`, `expositions-plan`, `postgresql-plan`, `courriel-plan`). Répondent à ce que `make prouver` ne demande jamais : *ce qui tourne correspond-il à ce qui est déclaré ?* | +| **Preuve / recette** | `docs/audit/affirmations.md` (registre), `make prouver` → `docs/audit/preuve-.md` — **statique** : lit le dépôt, aucun appel réseau ; la conformité du déployé est l'affaire des devis de service (ligne au-dessus), `docs/audit/plan-de-recette.md` (**généré** du wiki), `docs/audit/protocole-operateur-independant.md` | +| **Décisions d'architecture** | `docs/decisions-architecture.md` — **66 décisions en vigueur** (D-01 → D-69, 3 renversées), pourquoi, où lire le détail, et ce qui les garde ; plus les **décisions renversées** et leur cause | | **SDN / routage** | `docs/sdn-evpn.md` — décision du 2026-08-02 : le routage inter-zone passe des commutateurs aux hyperviseurs (zones EVPN = VRF). **Non éprouvé** : spike avant génération | | **Migration de tenant** | `docs/migration-tenant.md` — recette en 8 étapes, machine à états, gardes ; le receveur se construit **avant** tout gel | | **Exploitation courante** | `docs/runbooks-exploitation.md`, `docs/intrants-communs.md`, `docs/intrants-base-gui-conception.md`, `docs/theme-forgejo-hors-flotte.md` | @@ -50,10 +51,11 @@ Ce que je re-découvre sinon. **Consulter avant de concevoir un nouveau mécanis | Exposition → edge | app expose un FQDN public servi par un edge | `plan/domaines.yml` + `expose` (applications) | `bindings-conception.md` §4 | | Exploitation de l'hébergeur | ses **opérations** (supervision de la fabric, sauvegarde des configs, DNS d'underlay) n'appartiennent à aucun tenant et restent **hors overlay** | décidé, **non construit** : aucun équipement d'hébergeur n'est encore dans un inventaire | `hebergeur-exploitation.md` | | Authentification | web → Keycloak ; LDAP source unique ; secours par `sudo`, formulaire local non annoncé | `_connexion_locale: false` (grafana, forgejo, nextcloud) ; garde de version Forgejo ≥ 10 | `authentification.md` | -| Accès & habilitations | Set-OPS **amorce** un accès sysadmin puis se retire ; les appartenances aux groupes ne sont **jamais réconciliées** — c'est une personne qui gouverne | **décidé, non construit** : `ou=people` et `ou=groups` existent et restent vides | `autorisation.md` (§6 = runbook de reprise) | +| Accès & habilitations | Set-OPS **amorce** un accès sysadmin puis se retire ; les appartenances aux groupes ne sont **jamais réconciliées** — c'est une personne qui gouverne | **construit et éprouvé** (2026-08-08) : rôle `amorcage_acces` (idempotence par existence, D-67), groupes projetés en rôles par `serveur_keycloak`, `meta/acces.yml` dans les 5 rôles web ; chaîne LDAP → Keycloak → groupe → service exercée de bout en bout sur Icinga Web 2 | `autorisation.md` (§6 = runbook de reprise) | | SDN EVPN | ajouter un tenant implique **1 zone + 6 VNets + 6 sous-réseaux**, tous dérivés du seed | `scripts/devis_sdn.py` (`make devis-sdn`) ; nommage dérivé du tenant (`CHEZ17`, `chez174`), ≤ 8 caractères ; garde **P30** | `sdn-evpn.md` §2 | | Pools Proxmox | un pool par tenant : les noms courts de VM sont **volontairement identiques** d'un tenant à l'autre (même fonction, même nom), et seule la console Proxmox en souffrait | `scripts/devis_proxmox_pools.py` (`make devis-proxmox-pools`) ; nom dérivé de l'`index` ; garde de collision = preuve **P28** | `decisions-architecture.md` D-37 | | Routage | **aucun commutateur ne route** : la frontière est le seul équipement L3 ; les switches commutent | `passerelle` dit qui porte la passerelle, le SVI se dérive du rôle du porteur | `decisions-architecture.md` D-49/50 | +| **Devis de service** | LIT le système en marche et le compare à ce que le plan dérive ; n'écrit rien (D-23/D-24 portés du réseau aux services). Le playbook **relève**, Python **compare** | `playbooks/maintenance/devis-*.yml` + `scripts/devis_*.py` ; cible `make -plan` | `devis-services.md` | | Frontière nord/sud | les flux `pair: externe` — **sautés** par le pare-feu d'hôte — sont la politique de bordure | `scripts/devis_opnsense.py` (`make devis-opnsense`) ; garde d'accès admin = preuve **P24** | `frontiere-opnsense.md` | > ⚠️ **Deux directions de binding, assumées** : `app→app` côté app (instancier), diff --git a/scripts/inventory_gui.py b/scripts/inventory_gui.py index 616b319..40b3460 100644 --- a/scripts/inventory_gui.py +++ b/scripts/inventory_gui.py @@ -1483,13 +1483,16 @@ HTML = r"""
Lecture seule. Éditer les meta/flux.yml des rôles, puis make flux.
`; } else if (vuePrincipale === 'reseau') { d.innerHTML = `
Réseau & fédération
-
Chaque instance fédérée dérive son adressage de son seed index (VLAN/VNI = 1000 + index×10 + zone, unique dans la fédération). La vue liste la flotte, signale toute collision d'index, et génère les deux devis : commutateurs et frontière nord/sud.
+
Chaque instance fédérée dérive son adressage de son seed index (VLAN/VNI = 1000 + index×10 + zone, unique dans la fédération). La vue liste la flotte, signale toute collision d'index, et génère les devis d'infrastructure : commutateurs (make devis-reseau), frontière nord/sud (make devis-opnsense), SDN EVPN (make devis-sdn) et pare-feu est-ouest Proxmox (make devis-proxmox-fw).
Lecture seule, régénérés du plan — make devis-reseau / make devis-opnsense. Le dialecte de CLI et le mode de routage (commutateur ou SDN EVPN) se règlent dans la section Fabric du panneau « Intrants de base ». En mode SDN, les commutateurs ne portent ni VLAN tenant, ni SVI, ni ACL : le routage et le filtrage inter-zone vivent sur les hyperviseurs.
Ce qui reste à nommer à la main : les ports physiques (<PORT-VERS-…>) et, en SDN, le nœud de sortie EVPN. Rien d'autre — adresses, VLAN et routes se dérivent.
`; } else { d.innerHTML = `
Reconstruction
L'ordre part du socle et remonte : chaque couche suppose la précédente debout. Le tri intra-couche vient du graphe des dépendances.
-
Lecture seule. Éditer docs/couches-deploiement.yml ; généré dans playbooks/site.yml par make site.
`; +
Lecture seule. Éditer docs/couches-deploiement.yml ; généré dans playbooks/site.yml par make site.
+
Vérifier ce qui a été remonté. Un déploiement vert ne dit pas que le service rend son service. Les devis de service lisent le système en marche et le comparent à ce que le plan dérive — ils n'écrivent rien et sortent en erreur s'il y a un écart : + make identite-plan, make certificats-plan, make expositions-plan, make postgresql-plan, make courriel-plan. + Détail dans docs/devis-services.md.
`; } }