Publication du wiki depuis le depot (source: ac85278)

Daniel Allaire 2026-08-10 08:09:10 -04:00
parent 1efef83da9
commit b6167f2cf4
8 changed files with 364 additions and 25 deletions

10
Home.md

@ -1,5 +1,10 @@
# Set-OPS — moteur souverain **et** compagnon pédagogique
> **Pour qui :** celui qui **apprend le métier**. Chaque unité part d'un fondamental TIC, pas
> d'un produit. Pour *exploiter* dès aujourd'hui, va à
> **[Reprendre l'écosystème](Reprendre-l-écosystème)** ; pour *modifier* le moteur, la carte
> du dépôt est dans `docs/carte-set-ops.md`.
Bienvenue. **Set-OPS** est le moteur Ansible qui déploie un **écosystème numérique souverain
complet** (Alliance Boréale · *tout est libre*). Mais c'est aussi, et volontairement, un **outil
pédagogique** : il instancie *pour de vrai* la quasi-totalité des **fondamentaux des TIC**, avec
@ -12,6 +17,9 @@ des **méthodes 100 % génériques**.
« Keycloak » — tu apprends le **SSO/OIDC**. Pas « step-ca » — la **PKI**. Ces savoirs se
**transfèrent partout** (Active Directory, Okta, Vault, n'importe quel DNS…).
> **Ce wiki est publié depuis le dépôt** (`wiki/`). Une page modifiée dans l'interface de la
> forge est **détruite** à la publication suivante : on lit ici, on écrit dans le dépôt.
## Comment ce wiki est organisé
| Section | Contenu |
|---|---|
@ -29,6 +37,8 @@ Chaque unité suit **quatre temps** :
> **4. À toi de jouer** *(observe · interroge · casse · répare)*
## Par où commencer
- 🔑 **[Reprendre l'écosystème](Reprendre-l-écosystème)** — si tu dois l'**exploiter** dès
aujourd'hui : l'ordre des opérations, pas la théorie.
- 👉 **[Identité & SSO](Identité-et-SSO)** — l'unité-pilote côté *services* (SSO, annuaire, OIDC).
- 🧭 **[Le plan & l'adressage dérivé](Le-plan-et-l-adressage-dérivé)** — l'unité-pilote côté
*méthode* : un seed, tout en découle. C'est la clé de voûte du reste.

@ -30,9 +30,34 @@ en **contrôle de version** (git), donc auditable et réversible.
- `make deployer` applique les rôles ; le `Vérifier` (dry-run) **prévisualise** d'abord.
- Tout vit dans **git** (ce dépôt) — reproductible, revu, réversible.
Preuve d'idempotence, vue partout cette session : redéployer un rôle déjà en place →
**`changed=0`**. Et un refactor « neutre » (ex. le binding annuaire) → `changed=0` aussi : *même
état voulu = aucune modification*.
### L'idempotence ne se décrète pas : elle se mesure
Cette page a longtemps affirmé que redéployer un rôle donnait `changed=0`. C'était vrai **rôle
par rôle** — et faux à l'échelle de la flotte, ce que personne n'avait vérifié. Le 2026-08-09,
après une reconstruction complète, on a compté :
```
924 taches « changed » rejeu depuis zero (tout est neuf : normal)
17 taches « changed » second passage (la flotte devrait etre convergente)
0 taches « changed » apres correction
```
**Les 17 n'étaient pas du bruit.** Elles cachaient deux pannes qui ne se signalaient d'aucune
autre façon :
| Ce qu'on voyait | Ce que c'était |
|---|---|
| 13× « démarrer node_exporter » | le service **était mort** — tué par `SIGHUP` à chaque renouvellement de certificat, donc toutes les 24 h, sur les quatorze hôtes |
| 2× « déployer app.ini » | le dépôt **faisait tourner le secret JWT** de la forge à chaque déploiement, invalidant ses jetons |
La leçon dépasse Ansible : **un compteur de changements est un instrument de diagnostic.** Tant
qu'il indiquait 17, aucun de ces deux défauts n'était visible — ils se noyaient dans un fond
qu'on avait pris l'habitude d'ignorer. Ramené à zéro, le moindre `changed` sur une flotte non
modifiée devient un signal.
**Vérifier le zéro, aussi.** Un zéro peut vouloir dire « rien à faire » ou « plus rien ne
travaille ». On a compté les tâches exécutées : **2266 au passage à vide contre 2152 au rejeu**.
Plus de tâches, aucune modification — donc convergence, pas silence.
---

@ -26,7 +26,7 @@ Trois idées la portent :
- **Le registre** : `docs/audit/affirmations.md` — chaque affirmation du dépôt (README, docs,
aide `make`, GUI) reliée à une preuve et un statut (✅/🟡/❌/⚪).
- **Le harnais** : `make prouver` rejoue les preuves automatisables (**P01P21**) et écrit
- **Le harnais** : `make prouver` rejoue les preuves automatisables (**P01P34**) et écrit
`docs/audit/preuve-<date>.md`. `make verifier` les inclut : il **échoue** si une preuve échoue.
- **Chaque preuve garde une classe d'erreur.** Extrait :
@ -39,6 +39,16 @@ Trois idées la portent :
| P19 | un champ du plan que le **GUI** ne sait pas éditer |
| P20 | de l'**adressage stocké** (tout doit dériver du seed) |
| P21 | une **collision d'index** entre instances fédérées |
| P31 | une capacité du dépôt **non expliquée** (script muet, cible sans aide, rôle sans README) |
| P32 | un intrant qu'un rôle **exige** et que l'instance ne fournit pas |
| P33 | deux rôles co-localisés qui **revendiquent le même port** |
| P34 | un document qui ne **déclare pas son lecteur** — il finirait rangé par sujet, donc introuvable |
> **Ce que ces preuves ne font pas, et il faut le savoir avant de leur faire confiance.** Elles
> sont toutes **statiques** : elles lisent le dépôt, sans un seul appel réseau. Elles établissent
> qu'il est cohérent *avec lui-même* — jamais que le système déployé lui ressemble. C'est dans
> cet angle mort qu'un certificat d'autorité a pu rester expiré huit heures sous un harnais vert.
> La conformité du **déployé** est l'affaire des **devis de service** (voir `docs/devis-services.md`).
Ce n'est pas un framework de test parallèle : le harnais **orchestre** l'outillage existant, il ne
réimplémente aucune validation.

@ -26,7 +26,7 @@ Une bonne console d'exploitation obéit à trois règles :
| Vues **éditables** (le plan) | Vues **dérivées** (lecture seule) |
|---|---|
| Serveurs · Applications · Bases · Domaines · **Intrants** | Flux · Couches · **Réseau** (flotte + devis) |
| Serveurs · **Intégrations** · Applications · Bases · Domaines · **Intrants** | Flux · Couches · **Réseau** (flotte + devis) |
Le flux d'exploitation, de bout en bout :
@ -73,6 +73,16 @@ un pointeur seulement) et le **DSN dérivé** (secret masqué).
![Vue Domaines, annotée](img/Set-OPS-Domaines-annote.svg)
**Intégrations** *(éditable)* — la **matrice serveurs × intégrations**. Les colonnes ✓ vertes
sont la **politique des rôles** : elles s'appliquent à tout hôte et ne se décochent pas ; un `—`
barré signale une **exemption dérivée du service rendu** (l'AC ne s'enrôle pas auprès d'elle-même).
Les autres colonnes sont de vrais choix, cochables ici. La ligne **couverture** ne juge pas — elle
rend le motif visible : c'est au lecteur de savoir si les manquants sont des décisions ou des oublis.
> Cette vue existe parce que la fiche de détail ne montrait les intégrations que **d'un serveur à
> la fois**. Deux serveurs sans supervision ni journaux sont restés invisibles jusqu'à ce qu'un
> devis de pare-feu les énumère : l'information était à l'écran, répartie sur quatorze clics.
**Flux** *(dérivée)* — la **matrice d'audit** : la source de nftables *et* la justification lisible
de chaque flux (sens ingress/egress, chiffrement).

@ -41,37 +41,83 @@ chevauchement possible : VLAN `1000+index×10+zone` (les VLAN de deux index diff
**Garde-fous.** `federe: false` exclut un bac à sable local du réseau convergé. La **preuve P21**
échoue si deux instances fédérées partagent un `index`.
**Le devis du commutateur.** `make devis-reseau` **dérive** des nomenclatures fédérées la config
à coller dans le switch : les VLAN par zone, les **SVI** (`ip address …`, passerelles) et les
**ACL d'isolation** (default-deny inter-tenant — un tenant ne parle qu'à lui-même, le reste passe
par OPNsense). C'est le pendant matériel de l'isolation logique.
**Qui route les tenants : deux mondes.** L'adressage dérive toujours du seed `index`, mais
*qui* l'applique se déclare — `underlay.routage_tenants` :
**Le dialecte de CLI.** Toutes les CLI de switch ne se ressemblent pas. Set-OPS génère par défaut
du **Cisco** (`cisco`), mais connaît aussi le **Binardat** (`binardat`), qui diffère sur deux
pièges qui font *passer un VLAN mais fuir un tenant* :
| | `switch` | `sdn` |
|---|---|---|
| Passerelle d'une zone | **SVI** sur le commutateur L3 | **anycast** sur chaque hyperviseur |
| Isolation inter-tenant | ACL de commutateur | **VRF** (une zone EVPN par tenant) |
| Sur le fil | VLAN étiquetés par zone | **VXLAN** — aucun VLAN de tenant ne circule |
| Inter-tenant | bloqué par ACL | sort du VRF → **passe par la frontière** |
Le `.1` d'une passerelle ne change pas d'adresse d'un monde à l'autre : il **change de
porteur**. C'est la même dérivation, appliquée ailleurs.
**Le devis du commutateur.** `make devis-reseau` dérive la config à coller. En mode `switch` :
VLAN par zone, SVI, ACL d'isolation. En mode `sdn` : rien de tout ça — le commutateur redevient
un **transport IP** qui achemine du VXLAN sans le lire, et le devis dit à sa place pourquoi ces
sections ont disparu.
**Le devis de la frontière.** `make devis-opnsense` dérive la politique de bordure du **même**
registre des flux — les flux `pair: externe`, que le pare-feu d'hôte saute justement parce
qu'ils relèvent de la bordure. Rien n'y est saisi : ni port, ni adresse, ni nom d'hôte.
**Le dialecte de CLI.** Toutes les CLI de commutateur ne se ressemblent pas. Set-OPS génère par
défaut du **Cisco**, mais connaît aussi le **Binardat**, qui diffère sur des détails capables de
faire *passer un VLAN mais fuir un tenant* :
| | Cisco | Binardat |
|---|---|---|
| Masque d'ACL | **inversé** (wildcard `0.0.255.255`) | **normal** (`255.255.0.0`) |
| Commentaire d'ACL | `remark …` | **absent** (omis) |
| Route statique | `ip route <réseau> <masque> <saut>` | **CIDR** : `ip route 0.0.0.0/0 <saut>` |
*(Le SVI `ip address … 255.255.255.0` est en masque normal sur les deux — rien à changer.)*
Choisir le dialecte : `make devis-reseau DIALECTE=binardat`, la variable d'environnement
`SETOPS_DIALECTE=binardat` (défaut permanent), ou l'option `--dialecte`. La GUI (vue Réseau,
lecture seule) suit l'environnement. **Le dépôt public reste générique** (`cisco`).
*(Le SVI `ip address … 255.255.255.0` est en masque normal sur les deux.)* Le dialecte est un
**intrant** — section *Fabric* du panneau — surchargeable par `--dialecte` ou `SETOPS_DIALECTE`.
**Le dépôt public reste générique** (`cisco`).
> **La leçon qui vaut au-delà de Set-OPS.** Trois de ces formes ont été *supposées* avant d'être
> confrontées au matériel ; deux étaient fausses. La pire ne levait aucune erreur :
> `switchport trunk allowed vlan **add** …` *ajoute* à la liste courante, et sur un port neuf
> qui autorise déjà tout, elle ne retranchait rien. La configuration avait l'air d'isoler et
> n'isolait pas. **Une commande acceptée n'est pas une commande qui fait ce qu'on croit.**
**L'underlay — le sous-sol.** Les VLAN tenant (`1000+index×10+zone`) sont les *overlays*. En
dessous vit la **fabric physique** partagée par toute la flotte : management des switches et de
Proxmox/OOB, iSCSI, Ceph (public + cluster). Elle **n'appartient à aucun tenant** et ne dérive
d'aucun `index`. On la décrit dans `underlay.yml` (racine du moteur, gitignore comme le vault ;
gabarit `underlay.yml.example`) :
d'aucun `index`. On la décrit dans `underlay.yml`, qui vit dans le dépôt de **l'hébergeur**
(ses switches, ses câbles) et que le moteur monte par symlink à sa racine — comme il monte le
plan par `instance/`. Ce lien ne suit pas `make instance-utiliser` : la fabric reste celle de
l'hébergeur, quel que soit le tenant actif. Gabarit : `underlay.yml.example`.
| Underlay | VLAN | Sous-réseau |
|---|---|---|
| management (switches, Proxmox, OOB) | 10 | `10.0.0.0/24` |
| stockage / iSCSI | 20 | `10.0.1.0/24` |
| ceph-public | 30 | `10.0.2.0/24` |
| ceph-cluster | 31 | `10.0.3.0/24` |
| Underlay | VLAN | Sous-réseau | Fabric |
|---|---|---|---|
| management (commutateurs, Proxmox, OOB) | 10 | `10.0.0.0/24` | principale |
| **transit** vers la frontière | 40 | `10.0.4.0/29` | principale |
| stockage / iSCSI | 20 | `10.0.1.0/24` | stockage |
| ceph-public | 30 | `10.0.2.0/24` | stockage |
| ceph-cluster | 31 | `10.0.3.0/24` | stockage |
Deux choses à retenir de cette table.
**Les fabrics.** Tous les réseaux ne partagent pas les mêmes câbles. Le stockage jumbo peut
vivre sur ses propres commutateurs ; le devis de l'une ne déclare alors rien de l'autre, et le
dit — `HORS PERIMETRE`. Un devis est une configuration qu'on applique, pas un inventaire.
**Le transit.** C'est le lien entre le routeur et la frontière, et **sans lui la flotte n'a ni
sortie ni chemin de retour**. Il vit dans l'underlay parce qu'il est *partagé* : la frontière
route vers tous les tenants par ce même saut, il ne peut donc dériver d'aucun `index`.
> **Le piège qui a coûté une passe de déploiement.** La route *aller* ne suffit pas. Sans route
> de **retour** vers le réseau d'administration, la réponse d'une VM sort par une autre
> interface que celle où l'état a été créé, et le pare-feu la jette **en silence** — ni réponse,
> ni message d'erreur. Symptôme déroutant : la passerelle répond au ping, aucun hôte derrière
> elle n'est joignable. On cherche une règle de pare-feu ; c'est une route manquante à l'autre
> bout.
En mode `sdn`, ces réseaux transportent du VXLAN : leur **MTU doit atteindre 1550** au minimum,
sinon le ping passe et les transferts échouent. `make underlay` le refuse.
`make underlay` l'affiche et le **valide** : VLAN < 1000 et sous-réseaux hors des supernets
tenant (`10.(10+index).0.0/16`) — **aucune collision possible** avec les overlays. `make
@ -85,7 +131,7 @@ règle ; elle est *sautée* si aucun `underlay.yml` n'est défini.
| Set-OPS | Équivalents ailleurs |
|---|---|
| un moteur, N tenants | **multi-tenancy** SaaS, *cloud accounts/projects* |
| isolation par VLAN/adressage | VRF, VLAN, *namespaces* Kubernetes, VPC |
| isolation par VRF (zone EVPN) | VRF matériel, VPC, *namespaces* Kubernetes |
| découverte par convention | *convention over configuration* (Rails, etc.) |
| tenants NetBox | modèle de source de vérité multi-tenant |

131
Reprendre-l-écosystème.md Normal file

@ -0,0 +1,131 @@
# Reprendre l'écosystème — tu viens d'hériter de tout ça
> **Pour qui :** l'exploitant qui reprend un écosystème Set-OPS déjà déployé — livraison,
> passation, ou retour après six mois. Ce n'est pas une unité d'apprentissage : c'est un
> **ordre d'opérations**. Il ne contient presque rien en propre, il t'envoie au bon endroit
> dans le bon ordre.
**La règle avant toutes les autres :** ce wiki est publié depuis le dépôt (`wiki/`). Une page
modifiée dans l'interface de la forge est **détruite** à la publication suivante. On lit ici,
on écrit dans le dépôt.
---
## ① Dans quel état hérites-tu ?
**Avant de toucher à quoi que ce soit.** Tu ne sais pas encore si tu reprends un système sain
ou une panne déjà commencée, et personne ne te le dira. Ces commandes 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 instance-courante # vers quel écosystème pointe l'instance active ?
make prouver # le dépôt est-il cohérent avec lui-même ? (aucun appel réseau)
make identite-plan # realm, fédération LDAP, mappeurs, politique de mot de passe, comptes
make certificats-plan # ce que le disque porte contre ce que la mémoire sert
make expositions-plan # chaque service publié répond-il — depuis l'edge et depuis ton poste
make postgresql-plan # le chiffrement est-il imposé, et à quels réseaux
make courriel-plan # Postfix → LDAP → LMTP → Dovecot → IMAP, file d'attente comprise
make frontiere-mesurer # ce qui n'est pas déclaré à la frontière est-il refusé ?
```
Quelques minutes pour ce qui demandait une journée d'enquête à la main. C'est aussi le
premier réflexe **après** la reprise : après tout changement, après une panne, avant
d'appeler quelqu'un.
> **`make prouver` ne suffit pas, et c'est important de le savoir tout de suite.** Il lit le
> dépôt, jamais les machines. Le 2026-08-08, l'autorité de certification de la flotte est
> restée expirée **huit heures** sous un harnais entièrement vert. Voir
> [Vérifier le déployé](Vérifier-le-déployé).
Détail de ce que chaque devis vérifie — et de ce qu'il ne vérifie pas : `docs/devis-services.md`.
---
## ② Entrer
Un prérequis et trois pièges, tous à la première connexion. Le runbook complet est dans
`docs/autorisation.md` **§6** ; voici l'ordre et la raison de chaque geste.
**1. La clé de voûte.** Le mot de passe de la voûte est lu depuis
`ANSIBLE_VAULT_PASSWORD_FILE` (`~/.config/setops-vault-pass` par défaut). **Sans ce fichier,
rien n'est possible** — ni les devis ci-dessus, ni un déploiement. C'est la première chose à
sauvegarder hors de la machine, avec les `vault.yml` de chaque instance, qui ne sont pas
versionnés.
**2. Le mot de passe d'amorçage, à changer avant tout le reste** (§6.1). L'annuaire refuse
toute opération tant qu'il n'est pas changé, sauf le changement lui-même. Ce n'est pas
optionnel.
**3. La racine mène à la mauvaise console** (§6.2). `https://auth.<domaine>/` redirige vers la
console du realm `master`, où ton compte n'existe pas. Keycloak répond *« invalid username or
password »* — exact, et parfaitement trompeur : le mot de passe est bon, c'est la porte qui ne
l'est pas.
**4. Fais confiance à l'AC interne** (§6.3), sinon ton navigateur criera sur chaque service.
`make ca-racine` récupère la racine et son empreinte, `make ca-empreinte` la relit **sur l'AC
elle-même** — c'est le témoin auquel comparer avant d'installer quoi que ce soit.
Et si tu te fermes dehors : §6.5.
---
## ③ De quoi c'est fait
Rien de tout ça n'est écrit à la main — **tout se dérive du plan**, et c'est le sujet de
[Le plan & l'adressage dérivé](Le-plan-et-l-adressage-dérivé). Demande-le plutôt que de le
lire quelque part :
```
make inventaire # vérifie l'inventaire et affiche le graphe des groupes
make hote-afficher HOTE=<nom> # tout ce que le plan dérive pour un hôte
make inventaire-ui # la même chose, en console web
```
| Pour comprendre | Va lire |
|---|---|
| ce que fait chaque service et pourquoi celui-là | [Accueil du wiki](Home), unités d'apprentissage |
| qui parle à qui, sur quel port | `docs/flux-conception.md` |
| comment un service en atteint un autre | [Liaisons (bindings)](Liaisons-bindings) |
| la carte du dépôt, pour **modifier** | `docs/carte-set-ops.md` |
---
## ④ Quand ça casse
Les procédures : `docs/runbooks-exploitation.md`.
Deux réflexes qui évitent la moitié des fausses pistes :
- **Un certificat renouvelé sur disque n'est pas un certificat servi.** Tant que nginx,
Postfix ou slapd n'ont pas été rechargés, ils servent l'ancien depuis la mémoire.
`make certificats-plan` compare les deux, justement.
- **Répare avec `make deployer`, constate avec les devis.** Ce sont deux gestes différents, et
les confondre fait perdre l'information au moment où elle sert.
---
## ⑤ Ce qui va te mentir
Un écosystème ne tombe pas en panne franchement : il te donne d'abord un **signal faux**. Et
un signal faux coûte une demi-journée à qui n'est pas prévenu.
**La règle qui les couvre tous : quand une mesure accuse un composant, vérifie d'abord que ton
instrument mesure ce que tu crois.** Une sonde porte toujours un **contrôle** — une cible dont
tu connais déjà la réponse. Si le contrôle ment, ne conclus rien.
Les trois que tu rencontreras, et où chacun est traité :
| Le signal | Ce qu'il te fera croire | Où c'est expliqué |
|---|---|---|
| un `connect()` TCP qui réussit **vers le vide** | que le port est ouvert | `docs/frontiere-opnsense.md` — la frontière répond à la poignée sans jamais relayer. Le contrôle : sonder `172.31.99.99`, et n'accepter que la **livraison**. C'est ce que fait `make frontiere-mesurer`. |
| `make prouver` **tout vert** | que le système va bien | [Vérifier le déployé](Vérifier-le-déployé) — les preuves lisent le dépôt, jamais les machines. |
| `Connection timed out during banner exchange` | que le réseau est en cause | `docs/runbooks-exploitation.md` **§3** — c'est le plus souvent une VM pas encore là, ou `sshd` qui refuse une rafale. |
---
## Ce que tu dois changer en priorité
Avant d'oublier, et c'est dans `docs/autorisation.md` §6.8 : le mot de passe d'amorçage
(section ② ci-dessus), les secrets restants de la voûte, et tout accès hérité de la livraison
qui n'est pas à toi.

103
Vérifier-le-déployé.md Normal file

@ -0,0 +1,103 @@
# Vérifier le déployé — quand la preuve statique ne suffit plus
> **Unité d'apprentissage.** Moule : ① concept → ② Set-OPS → ③ transférable → ④ à toi de jouer.
---
## ① Le concept *(générique)*
Il y a **deux questions** qu'on confond tout le temps, et seule la première est facile :
| Question | Ce qu'on lit | Ce que ça prouve |
|---|---|---|
| « Mon **code** est-il cohérent ? » | le dépôt | qu'il ne se contredit pas lui-même |
| « Mon **système** ressemble-t-il à mon code ? » | les machines | qu'il fait ce qu'on a écrit |
Un test unitaire, un *linter*, une validation de schéma répondent tous à la première. Ils sont
rapides, ils tournent partout, et ils **ne touchent jamais** la machine. C'est leur force et
c'est leur limite.
La seconde question exige d'aller *demander* au système. Et elle est la seule qui compte le jour
où quelque chose ne marche pas.
> **Le piège n'est pas d'ignorer la seconde question. C'est de croire que la première y répond.**
> Un tableau de bord tout vert dit « le code est bon », et on le lit « le service fonctionne ».
---
## ② Comment Set-OPS le fait
Set-OPS a longtemps eu **31 preuves statiques** (`make prouver`) — zéro appel réseau, zéro SSH.
Elles établissent que le dépôt est cohérent avec lui-même : les *handlers* existent, l'adressage
dérive du seed, aucun intrant n'est orphelin.
Le 2026-08-08, l'autorité de certification de la flotte est restée **expirée pendant huit
heures** sous un harnais entièrement vert. Le renouvellement échouait toutes les quatorze
minutes. Aucune preuve ne pouvait le voir : aucune ne parlait à une machine.
D'où les **devis de service** — même patron que les devis réseau (D-23/D-24), porté aux services :
```
make identite-plan le realm, la fédération LDAP, la politique de mot de passe, les comptes
make certificats-plan ce que le disque porte contre ce que la mémoire sert
make expositions-plan chaque service publié répond-il — depuis l'edge et depuis ton poste
make postgresql-plan le chiffrement est-il imposé, et à quels réseaux
make courriel-plan Postfix → LDAP → LMTP → Dovecot → IMAP, file d'attente comprise
```
| Pièce | Rôle |
|---|---|
| un **playbook** (`playbooks/maintenance/devis-*.yml`) | **relève** le déclaré et le réel, dépose un JSON |
| un **script** (`scripts/devis_*.py`) | **compare**, affiche les écarts, sort en code 1 |
| `make deployer` | **répare** — ce n'est pas le rôle du devis |
**Trois règles qui font la différence entre un devis utile et un devis décoratif :**
**Le devis ne redéclare jamais ce qu'il vérifie.** Il charge les défauts du rôle et appelle les
résolveurs. Un contrôle qui recopie la valeur attendue ne contrôle rien — il se compare à
lui-même.
**Une vraie requête, jamais un `connect()`.** À travers un pare-feu qui fait de l'anti-usurpation,
toute connexion TCP réussit, même vers une adresse où rien n'existe. Et en TLS c'est le *client*
qui parle en premier : le silence après connexion ne distingue pas un service sain d'un trou.
Seul un échange applicatif complet tranche.
**Un code de retour n'est pas un verdict.** Un `502` *est* une réponse, et pourtant le service
est mort derrière.
---
## ③ Pourquoi c'est transférable
| Set-OPS | Équivalents ailleurs |
|---|---|
| preuves statiques | tests unitaires · *linters* · validation de schéma · `terraform validate` |
| devis de service | tests de bout en bout · sondes *black-box* · `terraform plan` sur l'état réel |
| relevé puis comparaison | *drift detection* — AWS Config, Chef `--why-run`, Puppet `--noop` |
Le mot que tout le monde emploie est **dérive** (*drift*) : l'écart qui s'installe entre ce qu'on
a déclaré et ce qui tourne. Aucun outil ne l'empêche ; ils aident seulement à la **voir**.
Et la vraie leçon n'est pas technique : **une garantie qui n'a jamais échoué n'est pas une
garantie, c'est une habitude.** Un contrôle qu'on n'a pas vu dire *non* ne prouve rien — il faut
l'éprouver dans les deux sens, en cassant volontairement ce qu'il surveille.
---
## ④ À toi de jouer
1. Lance les cinq devis sur ta flotte. Note le temps que ça prend : quelques minutes pour ce qui
demandait une journée d'enquête à la main.
2. **Casse quelque chose exprès** — arrête un service publié, change un port — et relance le
devis concerné. S'il ne dit rien, c'est *lui* qu'il faut réparer, pas le service.
3. Cherche, dans ton propre outillage, une vérification qui n'a **jamais** échoué. Demande-toi si
c'est parce que tout va bien, ou parce qu'elle ne regarde rien.
| Terme | Ce que tu retiens |
|---|---|
| preuve statique | lit le **code** ; rapide, universelle, aveugle au réel |
| devis / *drift detection* | interroge le **système** ; seule réponse à « est-ce que ça marche ? » |
| test négatif | éprouver qu'un contrôle sait dire **non** |
Tu as appris **la différence entre valider du code et vérifier un système** — pas « les devis
Set-OPS ».

@ -1,6 +1,9 @@
### Set-OPS
[🏠 Accueil](Home)
**Tu viens d'arriver**
- [🔑 Reprendre l'écosystème](Reprendre-l-écosystème)
**Unités d'apprentissage**
*Fondations*
@ -33,6 +36,7 @@
*Flotte & preuve*
- [Multi-instance & fédération](Multi-instance-et-fédération)
- [La preuve](La-preuve)
- [Vérifier le déployé](Vérifier-le-déployé)
**Opérations**
- Runbooks → dépôt `docs/runbooks-exploitation.md`