diff --git a/CHANGELOG.md b/CHANGELOG.md index 72329a9..03a2a38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,62 @@ # CHANGELOG — Set-OPS +## 2026-08-21 — Le glossaire définissait Set-OPS et laissait dehors tout le métier + +Demande de l'exploitant, après une soirée passée à croiser *strophe FRR*, *VRF*, *VNet* et +*nexthop-vrf* : *« il importe que cet écosystème soit pilotable par des humains, idéalement +un seul. Alors révise notre glossaire, et que chacune des notions sous-jacentes soit +enseignée. »* + +Mesuré avant d'écrire — **40 termes employés par le dépôt et absents du glossaire** : + +``` +LDAP 184 fois underlay 106 fois EVPN 66 fois +playbook 165 fois VRF 33 fois LMTP 25 fois +``` + +Le glossaire expliquait le vocabulaire **propre à Set-OPS** — plan, index, voûte, zone — +et laissait dehors tout ce qui vient du métier. Or c'est le métier qui perd le lecteur. + +### Ce n'est pas un défaut de rédaction + +La règle fondatrice du dépôt est qu'un humain doit pouvoir piloter cet écosystème **sans +IA**, idéalement seul. Chaque mot obscur retire une personne à la liste de celles qui +peuvent reprendre le système. Un vocabulaire non expliqué est donc un défaut de +**conception**. + +### Ce qui a été fait + +**Le glossaire est réécrit** — 67 termes, groupés par famille (le plan, les machines, +Ansible, le réseau, les noms, la confiance, l'identité, le courriel, l'état et sa preuve). +Chaque entrée dit ce que c'est **et pourquoi ce dépôt s'en sert**, avec le renvoi vers +l'unité qui développe. + +**Une unité d'apprentissage manquait** : [Le réseau des tenants](wiki/Le-réseau-des-tenants.md). +Dix-sept des quarante termes y vivaient sans domicile. Elle raconte le chemin dans l'ordre +où les problèmes se sont posés : deux clients sur un même câble → le VLAN → ses deux +limites → l'encapsulation → pourquoi 1450 → qui distribue les enveloppes → et le VRF, qui +n'est pas une interdiction mais une **ignorance structurelle**. + +### P39, et ce qu'elle avoue ne pas savoir faire + +Elle vérifie trois choses : chaque terme du jargon a une entrée ; chaque lien du glossaire +mène à une page qui existe ; chaque page du wiki est atteignable depuis la navigation. + +La liste des termes est **déclarée**, et c'est un choix mesuré. La dérivation automatique a +été essayée : 153 acronymes dans le wiki et le README, dont la moitié sont des mots +français en capitales — `AUCUNE`, `AVANT`, `TOUS`. Un contrôle qui exige une entrée de +glossaire pour « AUCUNE » finit désactivé, et une preuve désactivée ne garde rien. + +Éprouvée en négatif contre le glossaire d'avant : **49 termes manquants**, nommés un par +un. + +`make verifier` : 39 OK, 0 échec, 0 sauté. + +> **Ce que la preuve ne mesurera jamais.** Qu'une explication soit *bonne*. Elle compte des +> entrées ; elle ne sait pas si on comprend. Ça, seul un lecteur peut le dire — et c'est +> précisément le lecteur qu'on cherche à ne pas perdre. + + ## 2026-08-20 — Le devis d'avant-vol validait le mauvais réseau Remarque de l'exploitant, en préparant patient 0 : *« le pont ne me semble pas approprié diff --git a/docs/audit/plan-de-recette.md b/docs/audit/plan-de-recette.md index 76279cf..abcc691 100644 --- a/docs/audit/plan-de-recette.md +++ b/docs/audit/plan-de-recette.md @@ -10,7 +10,7 @@ Ce plan est le **pendant manuel** de `make prouver` : là où le harnais prouve le côté humain **est** la preuve de l'affirmation « exploitable sans IA » (cf. `protocole-operateur-independant.md`). -**81 gestes** sur **20 unités** · **19** en « casse-répare » +**85 gestes** sur **21 unités** · **19** en « casse-répare » · **5** doublés d'un garde-fou machine (colonne *Preuve auto*). > **Honnêteté de couverture.** La colonne *Preuve auto* n'est remplie que lorsqu'une @@ -131,6 +131,17 @@ le côté humain **est** la preuve de l'affirmation « exploitable sans IA » (c *Source : [Le plan & l'adressage dérivé](Le-plan-et-l-adressage-dérivé) · § À toi de jouer.* +## Le réseau des tenants — du câble au VRF + +| # | Ce qu'on éprouve | Le geste (avec l'attendu) | Type | Preuve auto | +|---|---|---|---|---| +| 1 | Lis ton réseau physique | : make underlay. Repère les VLAN sous 1000 (l'underlay) et les MTU. Pourquoi le transport doit-il être à 1500 quand l'overlay est à 1450 ? | 👁 observe | — | +| 2 | Regarde sans écrire | : make sdn-plan. Si le cluster dit déjà ce que le plan dit, la sortie tient en une ligne. | 👁 observe | — | +| 3 | Trouve la sortie d'un tenant | : dans make devis-sdn, repère la strophe FRR et l'adresse du prochain saut. À quel équipement appartient-elle ? | 👁 observe | — | +| 4 | Change `index` dans un modèle | (jamais en production) et régénère : combien de valeurs ont bougé ? C'est la mesure exacte de ce que la dérivation t'épargne. Pour aller plus loin : docs/sdn-evpn.md (référence technique), Le plan & l'adressage dérivé, Multi-instance & f… | 👁 observe | — | + +*Source : [Le réseau des tenants — du câble au VRF](Le-réseau-des-tenants) · § À toi de jouer.* + ## Liaisons (bindings) | # | Ce qu'on éprouve | Le geste (avec l'attendu) | Type | Preuve auto | diff --git a/scripts/prouver.py b/scripts/prouver.py index 5b4af99..135d739 100644 --- a/scripts/prouver.py +++ b/scripts/prouver.py @@ -24,6 +24,7 @@ import datetime as _dt import ast import json import re +import unicodedata import os import subprocess import sys @@ -711,6 +712,102 @@ def preuve_lecteur_declare() -> tuple[bool, str]: f"({generes} genere(s) exempte(s)).") +# Le jargon que Set-OPS met sous les yeux de l'exploitant, et qu'il s'engage a enseigner. +# LISTE DECLAREE, ET C'EST UN CHOIX. La derivation automatique a ete essayee le +# 2026-08-21 : 153 acronymes dans le wiki et le README, dont la moitie sont des mots +# francais en capitales (AUCUNE, AVANT, TOUS, UNE...). Un critere qui exige une entree de +# glossaire pour « AUCUNE » ne se respecte pas longtemps — on l'aurait desactive, et la +# preuve serait morte. Une liste explicite qu'on allonge a la main vaut mieux qu'un +# controle qu'on eteint. +JARGON_A_ENSEIGNER = [ + # reseau — la famille la plus obscure, et celle qui a motive cette preuve + "underlay", "overlay", "VLAN", "VXLAN", "EVPN", "SDN", "VNet", "VRF", "strophe", + "FRR", "blackhole", "MTU", "SVI", "IPAM", "spanning-tree", "MLAG", "nftables", + "policy drop", "CIDR", "supernet", "FQDN", "pont", "frontiere", + # machines et Ansible + "hyperviseur", "gabarit", "cloud-init", "VMID", "systemd", "snapshot", + "playbook", "role", "inventaire", "group_vars", "handler", "idempotence", "voute", + # noms, confiance, identite, courriel + "DNS", "plancher", "reverse proxy", "vhost", "WAF", "edge", + "PKI", "ACME", "SAN", "mTLS", "TLS", "certificat", + "LDAP", "SSO", "OIDC", "SAML", "realm", "RBAC", + "SMTP", "IMAP", "LMTP", "DKIM", "MTA", + # etat et methode + "restic", "devis", "preuve", "harnais", "GUI", "index", "plan", "tenant", +] + + +def preuve_glossaire_enseigne() -> tuple[bool, str]: + """Tout mot que le depot emploie devant l'exploitant est explique au glossaire. + + POURQUOI (exigence de l'exploitant, 2026-08-21). La regle fondatrice du depot est + qu'un humain doit pouvoir piloter cet ecosysteme SANS IA — idealement un seul. Un + vocabulaire qu'on n'explique pas est donc un defaut de conception, pas un detail de + redaction : chaque mot obscur retire une personne a la liste de celles qui peuvent + reprendre le systeme. + + Mesure du jour, qui a motive la preuve : 40 termes employes par le depot et absents + du glossaire — `underlay` 106 fois, `EVPN` 66, `VRF` 33, `LDAP` 184. Le glossaire + definissait le vocabulaire propre a Set-OPS (plan, index, voute) et laissait dehors + tout ce qui vient du metier. + + CE QU'ELLE TESTE : + - chaque terme de `JARGON_A_ENSEIGNER` a une entree au glossaire ; + - chaque lien du glossaire vers une page du wiki mene a une page qui EXISTE ; + - chaque page du wiki est atteignable depuis `_Sidebar.md` — une unite que la + navigation ne cite pas n'est lue par personne. + + CE QU'ELLE NE PEUT PAS TESTER, et il faut le dire : qu'un mot que PERSONNE n'a + declare manque a la liste. Elle garde ce qu'on lui confie ; elle ne devine pas. Et + elle ne juge pas la QUALITE d'une explication — cela se lit, cela ne se mesure pas. + """ + wiki = RACINE / "wiki" + glossaire = wiki / "Glossaire.md" + if not glossaire.is_file(): + return False, "wiki/Glossaire.md absent" + texte = glossaire.read_text(encoding="utf-8", errors="ignore") + + # Comparaison SANS ACCENTS et sur des mots entiers. Le glossaire s'ecrit en francais + # correct (« Frontière », « Voûte », « Rôle ») ; c'est a la preuve de s'y plier, pas + # au texte de s'appauvrir. Les bornes de mot evitent le faux positif classique : + # « controle » contient « role ». + def _sans_accent(s: str) -> str: + return "".join(c for c in unicodedata.normalize("NFD", s) + if unicodedata.category(c) != "Mn") + + nu = _sans_accent(texte) + manquants = [t for t in JARGON_A_ENSEIGNER + if not re.search(rf"\b{re.escape(_sans_accent(t))}\b", nu, re.IGNORECASE)] + + pages = {p.stem for p in wiki.glob("*.md")} + liens = set(re.findall(r"\]\(([A-Za-zÀ-ÿ0-9'’\-]+)\)", texte)) + casses = sorted(l for l in liens if l not in pages) + + sidebar = (wiki / "_Sidebar.md") + orphelines: list[str] = [] + if sidebar.is_file(): + nav = sidebar.read_text(encoding="utf-8", errors="ignore") + orphelines = sorted(p for p in pages + if p not in ("_Sidebar", "README", "Home") + and f"({p})" not in nav) + + echecs = [] + if manquants: + echecs.append(f"{len(manquants)} terme(s) employe(s) sans entree au glossaire : " + + ", ".join(manquants)) + if casses: + echecs.append(f"{len(casses)} lien(s) du glossaire vers une page inexistante : " + + ", ".join(casses)) + if orphelines: + echecs.append(f"{len(orphelines)} page(s) du wiki absente(s) de la navigation : " + + ", ".join(orphelines)) + if echecs: + return False, " | ".join(echecs) + return True, (f"Glossaire complet : {len(JARGON_A_ENSEIGNER)} terme(s) du jargon " + f"expliques, {len(liens)} lien(s) valides, {len(pages)} page(s) de wiki " + f"toutes atteignables.") + + def preuve_catalogue_a_jour() -> tuple[bool, str]: """Le catalogue des services nomme TOUT ce que le moteur sait deployer, et rien d'autre. @@ -970,6 +1067,8 @@ PREUVES: list[dict] = [ "func": preuve_placement_chez_hebergeur}, {"id": "P38", "titre": "Catalogue des services : la carte dit ce que le moteur fait", "refs": [], "func": preuve_catalogue_a_jour}, + {"id": "P39", "titre": "Glossaire : tout mot employe est enseigne", "refs": [], + "func": preuve_glossaire_enseigne}, {"id": "P33", "titre": "Aucune collision de port entre roles co-localises", "refs": [], "cmds": [[sys.executable, "scripts/verifier_ports.py"]]}, ] diff --git a/wiki/Glossaire.md b/wiki/Glossaire.md index 86b9199..1f3278d 100644 --- a/wiki/Glossaire.md +++ b/wiki/Glossaire.md @@ -1,64 +1,308 @@ # Glossaire -Les concepts-clés de Set-OPS, en une phrase chacun. Les mots *en italique* renvoient à une autre -entrée. Le détail vit dans les **unités d'apprentissage** et le dépôt (`docs/`). +Tout mot que Set-OPS te met sous les yeux se trouve ici. Chaque entrée dit **ce que c'est**, +et pourquoi ce dépôt s'en sert — pas seulement sa définition. + +Les mots *en italique* renvoient à une autre entrée ; les liens mènent à l'**unité +d'apprentissage** qui développe la notion. + +> **Règle de ce glossaire.** Un terme employé par le dépôt et absent d'ici est un défaut. +> La preuve **P39** le vérifie. Ce qu'elle ne peut pas voir : un mot que personne n'a +> pensé à déclarer — elle garde une liste, elle ne devine pas. --- -**Adressage dérivé** — Les IP, VLAN, VMID, sous-réseaux ne sont pas saisis : ils se **calculent** -depuis le *seed*. Cf. [Le plan & l'adressage dérivé](Le-plan-et-l-adressage-dérivé). +## Le plan, et ce qui en dérive -**Binding (liaison)** — Relation déclarative entre entités du plan (app→app, app→base) résolue par -le moteur, sans coder de variables à la main. Cf. [Liaisons (bindings)](Liaisons-bindings). +**Plan** — La source unique de vérité (`instance/plan/` : serveurs, applications, bases, +domaines, nomenclature). On l'édite ; l'*inventaire* en est **généré**, jamais l'inverse. -**DIFF VIDE** — État sain où le *plan* reproduit **exactement** l'inventaire généré : la source de -vérité et l'artefact concordent. Vérifié par `make instancier`. +**Index (seed)** — Le **seul** intrant d'adressage d'une *instance*. Tout en descend : +supernet `10..0.0/16`, *VLAN* `1000+index×10+zone`, *VMID*, *VNet*. Unique dans la +*fédération*. Cf. [Le plan & l'adressage dérivé](Le-plan-et-l-adressage-dérivé). -**Fédération** — Ensemble des *instances* qui cohabitent sur une infrastructure partagée, chacune -avec son *index* unique. Cf. [Multi-instance & fédération](Multi-instance-et-fédération). +**Adressage dérivé** — Les adresses ne sont pas saisies, elles se **calculent**. Deux +valeurs ne peuvent donc pas se contredire : il n'y en a qu'une, et le reste en découle. -**`federe: false`** — Drapeau marquant un *bac à sable* local, **exclu** du réseau convergé (il ne -provisionne pas ses VLAN sur les switches de production). +**Nomenclature** — Le registre du modèle réseau : *zones*, placement des fonctions, et +l'*index*. Ne contient **aucune** adresse (preuve P20). -**Hôte fantôme** — Erreur de plan : une application posée sur un hôte **non déclaré** dans les -serveurs. Refusé par la preuve **P06** et par la création de modèle. +**Zone** — Un domaine de sécurité : un `/24` et un *VLAN*. Frontière, Identité, Données, +Services-infra, Observabilité, Applications. Un pare-feu les sépare. -**Idempotence** — Rejouer la même description N fois donne le même résultat (`changed=0` après la -1ʳᵉ fois). Cf. [Infra as Code & idempotence](Infra-as-Code-et-idempotence). +**Supernet** — Le grand bloc d'adresses d'un tenant (`10.29.0.0/16`), dont ses *zones* +découpent des tranches. -**Index (seed)** — Le **seul** intrant d'adressage d'une instance. Détermine supernet -(`10.`), VLAN (`1000+index×10+zone`), VMID. Unique par instance fédérée. +**CIDR** — La notation `10.29.16.0/24` : une adresse, puis le nombre de bits **figés**. +`/24` fige les trois premiers nombres — 254 machines possibles. -**Instance** — Un écosystème réel (un *tenant*) : `../OPS-`, avec ses valeurs concrètes -(domaine, *voûte*, index). L'active est celle que pointe le symlink `instance/`. +**DIFF VIDE** — État sain : le *plan* reproduit **exactement** l'*inventaire* appliqué. +Vérifié par `make instancier`. -**ip-miroir** — Schéma de VMID à 9 chiffres où le numéro **contient** l'IP et le tenant -(`VLAN·octet-hôte·séquence`) — lisible d'un coup d'œil. +**Instance** — Un écosystème réel (`../OPS-`) : son domaine, son *index*, sa *voûte*. +L'active est celle que pointe le lien `instance/`. -**Modèle** — Un *plan* **générique** réutilisable (valeurs *placeholder*, sans *voûte*), dans le -dépôt privé `Set-OPS-Modeles`. Le socle public en est la preuve libre. On en crée une instance -(`instance-creer`) ; on en fabrique un (`model-creer`). +**Tenant** — Le même objet, vu depuis la *fédération* : un écosystème isolé parmi d'autres. -**Nomenclature** — Le registre du **modèle réseau** : zones, placement des fonctions, et le *seed* -`index`. Ne contient **aucun** adressage (il en dérive — preuve P20). +**Fédération** — L'ensemble des *instances* qui cohabitent sur une infrastructure +partagée, chacune avec son *index*. Cf. [Multi-instance & fédération](Multi-instance-et-fédération). -**Le plancher** — La première couche de résolution de noms : `/etc/hosts` posé par le socle, avant -même que le DNS soit debout. Cf. [DNS & résolution](DNS-et-résolution). +**`federe: false`** — Drapeau qui **exclut** une instance des devis du site : ni *VLAN*, ni +règles de frontière, ni *VNet* ne lui sont réservés. Pour un bac à sable local, ou pour un +écosystème encore à l'état de plan. -**Plan** — La source unique de vérité (`instance/plan/` : serveurs, applications, bases, domaines, -nomenclature). On l'édite ; l'inventaire en est **généré**, jamais l'inverse. +**Modèle** — Un *plan* générique réutilisable, sans *voûte*, dans `Set-OPS-Modeles`. Les +modèles sont les **offres** : `forge`, `identite`, `collaboration`… -**Preuve (Pxx)** — Une vérification rejouable du harnais `make prouver` qui garde une classe +**Socle** — Le modèle minimal public : DNS, PKI, edge TLS, relais courriel. + +**Liaison (binding)** — Relation déclarée entre entités du plan (app→base, app→app), +résolue par le moteur. Cf. [Liaisons (bindings)](Liaisons-bindings). + +**Hôte fantôme** — Erreur de plan : une application posée sur un hôte non déclaré. Refusée +par la preuve P06. + +--- + +## Les machines + +**VM** — Machine virtuelle : un ordinateur complet simulé par un *hyperviseur*. + +**Hyperviseur** — La machine physique qui fait tourner les *VM*. Ici : Proxmox. + +**Gabarit (template)** — Une VM **figée** qui sert de moule. Chaque machine de la flotte +en est un clone. Le gabarit doré de Set-OPS s'appelle `modeleSetOPS`. + +**Clone** — La copie du *gabarit* qui devient une machine réelle. Deux minutes, contre une +installation complète. + +**VMID** — Le numéro d'une VM sur le cluster. Set-OPS le **dérive** (schéma *ip-miroir*) au +lieu de le tirer au hasard. + +**ip-miroir** — Schéma où le *VMID* **contient** l'adresse IP et le tenant : le numéro se +lit d'un coup d'œil. + +**cloud-init** — Le mécanisme qui configure une VM **à sa toute première seconde** : +adresse IP, nom, clé SSH. Sans lui, un clone naîtrait identique à son moule, jumeau de +tous les autres. + +**Snapshot** — Photo d'une VM à un instant. Utile pour revenir en arrière ; ce n'est +**pas** une sauvegarde (elle vit sur le même stockage). + +**systemd** — Le chef d'orchestre des services d'une machine Linux : il démarre, arrête et +surveille. « Un service » veut dire « une unité systemd ». + +--- + +## Ansible : décrire au lieu d'exécuter + +**Ansible** — L'outil qui applique une **description** à des machines, par SSH. Cf. +[Infra as Code & idempotence](Infra-as-Code-et-idempotence). + +**Playbook** — Un fichier qui dit **quoi appliquer, à qui**. Ici : un par groupe +(`playbooks/groupes/.yml`). + +**Rôle** — Le paquet qui sait installer et configurer **une** chose (`serveur_nginx`, +`client_backup`). C'est l'unité réutilisable. + +**Inventaire** — La liste des machines et de leurs groupes (`hosts.yml`). **Généré** depuis +le plan : on ne l'édite jamais à la main. + +**group_vars** — Les valeurs d'un groupe de machines, rangées par fichier. C'est là que +vivent les *intrants* non secrets. + +**Handler** — Une action qui ne se déclenche **que si** quelque chose a changé — typiquement +recharger un service quand sa configuration a bougé. + +**Idempotence** — Rejouer la même description dix fois donne le même résultat. La deuxième +exécution ne change rien (`changed=0`). C'est ce qui rend une reconstruction sûre. + +**Voûte (vault)** — Le fichier **chiffré** des secrets d'une instance. Jamais dans un +modèle, jamais en clair. Seul le gabarit `vault.yml.example` — des **noms**, pas des +valeurs — est versionné. + +--- + +## Le réseau + +→ Unité complète : [Le réseau des tenants](Le-réseau-des-tenants) + +**Underlay** — Le réseau **physique** : câbles, commutateurs, adresses des hyperviseurs. Il +ne connaît aucun tenant. + +**Overlay** — Les réseaux **virtuels** des tenants, transportés par-dessus l'*underlay*. + +**VLAN** — Une étiquette posée sur chaque trame pour séparer des réseaux qui partagent un +câble. Limite : 4094 étiquettes, et chaque commutateur doit les connaître. + +**VXLAN** — L'encapsulation : la trame d'un tenant voyage **dans une enveloppe**. Le réseau +physique ne voit que des colis. L'enveloppe coûte **50 octets** — d'où le *MTU* 1450. + +**EVPN** — Le mécanisme par lequel les hyperviseurs s'annoncent les machines qu'ils +hébergent. Sans lui, la table des destinations serait tenue à la main. + +**SDN** — *Software-Defined Networking* : le réseau se **décrit** et se pose par API, au +lieu de se câbler à la main. + +**VNet** — Le réseau virtuel d'**une zone** d'un tenant (`t29fron`) : le point où la carte +d'une VM se branche. + +**VRF** — Une table de routage **étanche**. Dans celle du tenant A, les réseaux du tenant B +n'existent pas. Ce n'est pas une interdiction, c'est une ignorance. + +**Strophe (FRR)** — Le bloc de configuration qu'on pose par tenant dans +`/etc/frr/frr.conf.local`, sur chaque hyperviseur : sa **sortie** et son **puits**. + +**FRR** — Le démon de routage des hyperviseurs (*FRRouting*). + +**`nexthop-vrf`** — Emprunter **une seule** adresse à une autre table de routage, au lieu +d'importer celle-ci en entier. La différence entre une porte et un mur abattu. + +**Blackhole (puits)** — Une route qui **absorbe** le trafic vers les adresses non +attribuées d'un tenant, pour qu'il ne parte pas errer ailleurs. + +**MTU** — La plus grosse trame qu'un lien accepte. 1500 par défaut ; 1450 dans l'*overlay* +(l'enveloppe VXLAN prend 50). Se tromper suspend les grosses réponses sans casser les +petites — la panne la plus déroutante du domaine. + +**SVI** — L'adresse de passerelle portée par un **commutateur** pour un VLAN. Set-OPS ne +s'en sert plus : le routage des tenants vit sur l'hyperviseur (*VRF*). + +**Pont (bridge)** — Le commutateur **virtuel** d'un hyperviseur (`vmbr1`). Les VM de la +flotte se branchent sur leur *VNet*, pas sur un pont nu. + +**IPAM** — Le registre qui attribue les adresses. Ici, c'est la **dérivation** : personne +ne tient de liste. + +**Spanning-tree (STP)** — Le protocole qui empêche une boucle de commutateurs de saturer le +réseau. Il élit une racine ; c'est ce que désigne `routeur` dans l'*underlay*. + +**MLAG** — Deux commutateurs qui se font passer pour un seul. Set-OPS n'en a pas : d'où +*un seul* commutateur qui route, et les chemins doublés ailleurs. + +**nftables** — Le pare-feu **de chaque machine** Linux. Set-OPS le dérive du registre des +flux. + +**Policy drop** — Politique par défaut : *tout ce qui n'est pas autorisé est refusé*. Sans +règles chargées, elle mure la machine — d'où l'importance de `make flux`. + +**Frontière** — Le pare-feu de bordure (OPNsense), entre l'écosystème et l'extérieur. Hors +flotte Ansible : piloté par API. + +**FQDN** — Le nom complet d'une machine, `forge.genese.internal` — pas seulement `forge`. + +--- + +## Les noms + +→ Unité complète : [DNS & résolution](DNS-et-résolution) + +**DNS** — L'annuaire qui traduit un nom en adresse. + +**Le plancher** — La première couche de résolution : `/etc/hosts`, posé par le socle +**avant** que le DNS existe. Sans lui, rien ne peut s'amorcer. + +**Résolveur** — Le service qui pose les questions au DNS pour une machine (ici Unbound, +local à chaque hôte). + +**Reverse proxy** — Le portier : il reçoit toutes les requêtes web et les distribue au bon +service derrière. Cf. [Reverse-proxy & TLS](Reverse-proxy-et-TLS). + +**vhost** — La configuration d'**un site** dans le *reverse proxy* : quel nom, vers quel +service. + +**WAF** — Filtre qui inspecte les requêtes web et bloque les attaques connues. + +**Edge** — La machine de bordure qui publie les services web (ici nginx). + +--- + +## La confiance + +→ Unité complète : [PKI & confiance](PKI-et-confiance) + +**PKI** — L'ensemble qui fabrique et gère les certificats. + +**CA (autorité de certification)** — Celle qui **signe** les certificats. Ici, `step-ca`, +interne : l'écosystème est sa propre autorité. + +**Certificat** — Une pièce d'identité pour une machine : ce nom, cette clé, signé par la +*CA*. + +**ACME** — Le protocole qui **automatise** la demande et le renouvellement d'un certificat. +Personne ne le fait à la main. + +**SAN** — Les noms qu'un certificat couvre. Set-OPS les **dérive** du plan. + +**TLS** — Le chiffrement d'une connexion (le « s » de https). + +**mTLS** — TLS **des deux côtés** : le client prouve aussi son identité. C'est le +zéro-confiance entre serveurs. + +--- + +## L'identité + +→ Unité complète : [Identité & SSO](Identité-et-SSO) + +**LDAP** — L'annuaire des personnes et des groupes : la source de vérité des identités. + +**LDAPS** — LDAP chiffré. + +**SSO** — *Single Sign-On* : une seule authentification pour toutes les applications. + +**OIDC** — Le protocole moderne du *SSO* sur le web. C'est lui derrière « Se connecter +avec… ». + +**SAML** — L'ancêtre d'*OIDC*, encore répandu en entreprise. + +**Realm** — Le « royaume » d'un serveur d'identité : un espace de comptes, de groupes et de +règles. Un par écosystème. + +**RBAC** — Donner des droits à des **rôles**, pas à des personnes. Cf. +[Autorisation & RBAC](Autorisation-et-RBAC). + +--- + +## Le courriel + +→ Unité complète : [Courriel (SMTP/IMAP)](Courriel) + +**SMTP** — Le protocole qui **transporte** un courriel d'un serveur à l'autre. + +**MTA** — Le serveur qui fait ce transport (ici Postfix). + +**IMAP** — Le protocole par lequel **tu lis** ta boîte, depuis ton téléphone ou ton client. + +**LMTP** — Le dernier mètre : le MTA remet le message au serveur qui **détient** les boîtes +(ici Dovecot). + +**DKIM** — La signature qui prouve qu'un courriel vient bien de ton domaine. + +--- + +## L'état, et sa preuve + +**restic** — L'outil de sauvegarde chiffrée et dédupliquée. Cf. [Sauvegardes](Sauvegardes). + +**Sauvegarde vs snapshot** — L'infrastructure se **reconstruit** depuis le code ; seul +l'**état** (annuaire, bases, courriel, forge) se sauvegarde. Cf. [Sauvegardes](Sauvegardes). + +**Devis** — Une commande qui **interroge le système réel** et montre l'écart avec le plan, +sans rien écrire (`make sdn-plan`, `make placement-plan`). + +**Preuve (Pxx)** — Une vérification rejouable de `make prouver` qui garde une classe d'erreur. Cf. [La preuve](La-preuve). -**Socle** — L'infrastructure de base souveraine (DNS, PKI, edge TLS, relais courriel) — le modèle -minimal public, extensible. +**Harnais** — L'ensemble des preuves. Un `make prouver` vert veut dire : aucune des classes +d'erreur connues n'est présente. -**Tenant** — Synonyme d'*instance* dans le contexte de la *fédération* : un écosystème isolé parmi -d'autres. +**Chèque vert sur un périmètre vide** — Le piège central de ce dépôt : une vérification qui +réussit **sans rien avoir mesuré**. Une sauvegarde de zéro fichier, un devis qui lit un +intrant périmé, une preuve qui ne peut pas échouer. À chaque « ✅ », se demander **sur +quoi** il a porté. -**Voûte (vault)** — Le fichier chiffré des secrets d'une instance (`vault.yml`, Ansible Vault). -**Jamais** dans un *modèle* ni versionné ; seul le gabarit `vault.yml.example` l'est. +**GUI** — La console web d'exploitation (`make inventaire-ui`). Cf. +[Le GUI](Le-GUI-console-d-exploitation). -**Zone** — Un domaine de sécurité (un `/24` + un VLAN) : Frontière, Identité, Données, -Services-infra, Observabilité, Applications. Un pare-feu les sépare. +**CI** — La vérification automatique à chaque poussée (`make ci` la rejoue à l'identique). diff --git a/wiki/Le-réseau-des-tenants.md b/wiki/Le-réseau-des-tenants.md new file mode 100644 index 0000000..8326525 --- /dev/null +++ b/wiki/Le-réseau-des-tenants.md @@ -0,0 +1,161 @@ +# Le réseau des tenants — du câble au VRF + +> **Unité d'apprentissage.** Moule : ① concept → ② Set-OPS → ③ transférable → ④ à toi de jouer. + +C'est la partie de Set-OPS qui emploie le plus de mots obscurs — *underlay*, *VXLAN*, +*VNet*, *VRF*, *strophe FRR*. Aucun n'est là par goût du jargon : chacun répond à un +problème précis, et on peut les rencontrer dans l'ordre où ils sont apparus. + +--- + +## ① Le concept + +### Le problème de départ : deux clients sur le même fil + +Deux organisations hébergées sur le même matériel ne doivent pas se voir. Or leurs +machines partagent des câbles, des commutateurs, des hyperviseurs. Il faut donc +**séparer ce qui est physiquement mélangé**. + +### Première réponse : le VLAN + +Un **VLAN** colle une étiquette (un nombre) sur chaque trame. Deux machines n'échangent +que si leurs étiquettes correspondent. C'est simple, ça marche, et c'est vieux de trente +ans. + +Deux limites : + +- l'étiquette tient sur 12 bits — **4094 VLAN**, pas un de plus ; +- chaque commutateur du chemin doit connaître chaque VLAN. Ajouter un client, c'est + toucher à la configuration de tout le monde. + +### Deuxième réponse : l'encapsulation + +**VXLAN** prend la trame d'un tenant, la met **dans une enveloppe** et l'expédie comme +un colis ordinaire d'un hyperviseur à l'autre. Le réseau physique ne voit passer que des +colis — il n'a plus besoin de connaître les clients. + +Deux vocabulaires en découlent, et c'est la distinction la plus utile de cette page : + +| | | +|---|---| +| **underlay** | le réseau **physique** : les câbles, les commutateurs, les adresses des hyperviseurs. Il ne connaît aucun tenant. | +| **overlay** | les réseaux **virtuels** des tenants, transportés dans des enveloppes par-dessus l'underlay. | + +L'enveloppe coûte **50 octets**. C'est toute l'explication du `mtu_overlay: 1450` : +1450 + 50 = 1500, la taille standard d'une trame. Se tromper là ne casse rien +franchement — les petites requêtes passent, les grosses réponses restent suspendues. +C'est la panne la plus déroutante du domaine. + +### Qui distribue les enveloppes : EVPN + +Pour expédier un colis, il faut savoir **où** l'envoyer. **EVPN** est le mécanisme par +lequel les hyperviseurs s'annoncent mutuellement les machines qu'ils hébergent. Sans +lui, il faudrait tenir cette table à la main. + +### Le VRF : une table de routage étanche + +Un routeur ordinaire a **une** table de routage. Un **VRF** lui en donne plusieurs, +hermétiques : dans la table du tenant A, les réseaux du tenant B **n'existent pas**. Ce +n'est pas une règle de pare-feu qu'on pourrait oublier — c'est une ignorance +structurelle. + +C'est la différence entre *« je t'interdis d'y aller »* et *« la route n'existe pas »*. + +--- + +## ② Dans Set-OPS + +### Ce que tu écris, et ce qui se calcule + +Tu écris **un nombre** : `index`. Tout le reste en découle. + +``` +index: 29 + ↓ +supernet 10.29.0.0/16 +VLAN 1000 + 29×10 + zone → 1291, 1292, 1293… +zone SDN t29 +VNet t29fron, t29serv, t29donn, t29appl +sous-réseau 10.29.16.0/24, 10.29.17.0/24 … +``` + +Un **VNet** est le réseau virtuel d'**une zone** d'un tenant : le point où les cartes +réseau des VM se branchent. Une VM de la zone Frontière du tenant 29 se branche sur +`t29fron`, et nulle part ailleurs. + +### Trois commandes, trois questions + +| Commande | Question à laquelle elle répond | +|---|---| +| `make underlay` | mon réseau **physique** est-il cohérent, et n'empiète-t-il pas sur les tenants ? | +| `make sdn-plan` | ce que le cluster porte **diffère-t-il** de ce que le plan décrit ? (aucune écriture) | +| `make sdn-appliquer` | pose la différence — et **retire ce qui est périmé** | + +`sdn-plan` avant `sdn-appliquer`, toujours. La seconde écrit sur le cluster et sur les +hyperviseurs ; la première ne fait que regarder. + +### La strophe FRR + +**FRR** est le démon de routage des hyperviseurs. Set-OPS lui pose un bloc par tenant — +ce que le dépôt appelle une **strophe** — dans `/etc/frr/frr.conf.local`, sur chaque +nœud de sortie : + +``` +vrf vrf_t29 + ip route 0.0.0.0/0 10.0.4.1 nexthop-vrf default + ip route 10.29.0.0/16 blackhole +exit-vrf +``` + +**La première ligne, c'est la sortie.** Tout ce qui ne concerne pas le tenant part vers +la frontière. `nexthop-vrf default` **emprunte une seule adresse** à la table principale +au lieu de l'importer en entier : importer aurait fait entrer dans le VRF le transport +VXLAN, le plan de gestion et les VLAN hérités — et permis de contourner la frontière. + +**La deuxième ligne, c'est un puits.** Elle attrape les adresses **non attribuées** du +tenant. Elle est moins précise que les `/24` des VNets, donc le trafic légitime ne la +voit jamais. + +Sans ce puits (mesuré le 2026-08-09) : une adresse inexistante ne trouvait aucune route +locale, sortait par le défaut, revenait de la frontière vers l'hyperviseur, atterrissait +dans la table **principale** — et repartait vers la passerelle du réseau +d'**administration**. Deux conséquences : le trafic d'un tenant pouvait atteindre le +plan de gestion **par une faute de frappe**, et `connect()` réussissait vers n'importe +quelle adresse inexistante. Ce qu'on avait longtemps pris pour une protection de la +frontière n'était qu'une route manquante ici. + +> **Le fichier ne se sauvegarde pas : il se régénère.** Il porte son avertissement en +> tête — *« NE PAS ÉDITER À LA MAIN »*. La source de vérité est le plan. + +--- + +## ③ Transférable + +Rien de tout ça n'appartient à Set-OPS. Ce sont les briques de n'importe quel réseau +multi-locataire : + +- **underlay / overlay** : le vocabulaire de tous les centres de données depuis 2015 ; +- **VXLAN + EVPN** : la même paire chez tous les hébergeurs, du garage à AWS ; +- **VRF** : présent sur tout routeur professionnel, et sur Linux depuis 2016 ; +- **le puits (`blackhole`)** : une pratique standard d'anti-fuite. + +Ce que Set-OPS ajoute n'est pas de la technologie, c'est une **dérivation** : ailleurs, +ces objets se saisissent à la main, un par un, dans quatre interfaces différentes. Ici, +ils descendent tous d'un seul nombre — donc ils ne peuvent pas se contredire. + +--- + +## ④ À toi de jouer + +1. **Lis ton réseau physique** : `make underlay`. Repère les VLAN sous 1000 (l'underlay) + et les MTU. Pourquoi le transport doit-il être à 1500 quand l'overlay est à 1450 ? +2. **Regarde sans écrire** : `make sdn-plan`. Si le cluster dit déjà ce que le plan dit, + la sortie tient en une ligne. +3. **Trouve la sortie d'un tenant** : dans `make devis-sdn`, repère la strophe FRR et + l'adresse du prochain saut. À quel équipement appartient-elle ? +4. **Change `index` dans un modèle** (jamais en production) et régénère : combien de + valeurs ont bougé ? C'est la mesure exacte de ce que la dérivation t'épargne. + +**Pour aller plus loin** : [`docs/sdn-evpn.md`](../docs/sdn-evpn.md) (référence +technique), [Le plan & l'adressage dérivé](Le-plan-et-l-adressage-dérivé), +[Multi-instance & fédération](Multi-instance-et-fédération). diff --git a/wiki/_Sidebar.md b/wiki/_Sidebar.md index 1cecc82..ebb4a62 100644 --- a/wiki/_Sidebar.md +++ b/wiki/_Sidebar.md @@ -13,6 +13,7 @@ - [DNS & résolution de noms](DNS-et-résolution) *Communication* +- [Le réseau des tenants](Le-réseau-des-tenants) - [Reverse-proxy & TLS](Reverse-proxy-et-TLS) - [Courriel (SMTP/IMAP)](Courriel)