diff --git a/Home.md b/Home.md index ba9eee7..0499ca7 100644 --- a/Home.md +++ b/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. diff --git a/Infra-as-Code-et-idempotence.md b/Infra-as-Code-et-idempotence.md index 09a4fdd..c7fe5db 100644 --- a/Infra-as-Code-et-idempotence.md +++ b/Infra-as-Code-et-idempotence.md @@ -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. --- diff --git a/La-preuve.md b/La-preuve.md index 56ce31d..049a818 100644 --- a/La-preuve.md +++ b/La-preuve.md @@ -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 (**P01–P21**) et écrit +- **Le harnais** : `make prouver` rejoue les preuves automatisables (**P01–P34**) et écrit `docs/audit/preuve-.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. diff --git a/Le-GUI-console-d-exploitation.md b/Le-GUI-console-d-exploitation.md index 6bc9c2a..4d3b264 100644 --- a/Le-GUI-console-d-exploitation.md +++ b/Le-GUI-console-d-exploitation.md @@ -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). diff --git a/Multi-instance-et-fédération.md b/Multi-instance-et-fédération.md index 0e0b1e4..ecce929 100644 --- a/Multi-instance-et-fédération.md +++ b/Multi-instance-et-fédération.md @@ -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 ` | **CIDR** : `ip route 0.0.0.0/0 ` | -*(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 | diff --git a/Reprendre-l-écosystème.md b/Reprendre-l-écosystème.md new file mode 100644 index 0000000..c5b2622 --- /dev/null +++ b/Reprendre-l-écosystème.md @@ -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./` 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= # 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. diff --git a/Vérifier-le-déployé.md b/Vérifier-le-déployé.md new file mode 100644 index 0000000..542864a --- /dev/null +++ b/Vérifier-le-déployé.md @@ -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 ». diff --git a/_Sidebar.md b/_Sidebar.md index 496289a..1cecc82 100644 --- a/_Sidebar.md +++ b/_Sidebar.md @@ -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`