La revision a commence par un balayage par motifs — chemins morts, cibles make absentes, comptes derives. Il a trouve une trentaine d ecarts et rate presque tout le reste : un motif ne voit que ce qui s exprime en motif. make hote-planifier en est l exemple. La cible EXISTE, donc le controle passait au vert. C est une cible depreciee qui refuse et sort en 2, recommandee par AGENTS.md, et qui contredit la REGLE D OR du meme fichier trois ecrans plus haut. Il fallait lire pour la voir. 74 documents lus un par un. 66 corriges, 8 exacts. CE QUI ETAIT FRANCHEMENT FAUX AGENTS.md, la source d autorite, annoncait la flotte pas encore executee contre des VM reelles. Elle a ete rasee et remontee depuis zero trois fois. ecosysteme-chezlepro.md, le document montre a un client, portait la meme phrase : il se sous-vendait gravement. courriel-conception.md s ouvrait sur aucun role n est encore ecrit, au-dessus de son propre paragraphe 1 qui les nomme. autorisation.md se terminait sur rien n est construit alors qu il rapporte des mesures datees du role en fonctionnement. hebergeur-exploitation.md disait rien n est fait d un depot qui existe. filiation-emancipation.md se contredisait a deux ecrans de distance. DES MODELES DECRITS D APRES UN MONDE ANTERIEUR Le resolveur : cinq documents decrivaient un Unbound par VM en opt-in, trois le donnaient en exemple d integration FACULTATIVE — il est universel depuis le 2026-08-24. L adressage de nomenclature-vm.md : reseau unique, VLAN 11-15, VMID a cinq chiffres. Le nommage SDN de sdn-evpn.md contre le code : c est le wiki qui avait raison. CE QUI CASSE AU PREMIER ESSAI Le nom du gabarit dore etait faux a quatre endroits, dont la procedure qui le FABRIQUE et le critere R2 de l epreuve d operateur independant. preparer-un-site-hebergeur.md avertissait qu une VM faite a la main serait detruite : raser derive du plan, il ne la detruira jamais — le risque est l inverse. Un mot de passe d essai en clair dans un depot public. DEUX PREUVES ETENDUES, ET UNE QUI SE TROMPAIT ELLE-MEME P57 couvre les groupes : elle a signale aussitot 29 groupes annonces au-dessus d un tableau qui en cite 40. P29 confronte le tableau de authentification.md aux declarations reelles : 12 annonces, 21 reels. Et P57 imposait un chiffre faux — 56 preuves alors que le depot en porte 57, la conditionnelle vivant hors de tout comptage. Un garde-fou qui fait respecter une erreur ajoute l assurance a l erreur. CE QUI RESTE, ET QU AUCUNE PREUVE NE TIENT Deux comptes trouves a la main. Et une lacune reelle : rien ne garde les meta/acces.yml — ni qu un service web-sso en porte un, ni que le groupe qu il nomme existe. P29 tient les positions d authentification, personne ne tient les habilitations. make prouver : CONFORME, 56 OK, 0 echec, 1 saute. 0 lien mort. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
11 KiB
Le plan et la génération d'inventaire (méta-classe)
Pour qui : le mainteneur — le plan et la génération de l'inventaire, à fond.
Set-OPS ne s'édite plus comme un inventaire à la main : on décrit un plan, et l'inventaire Ansible en est généré. Le dépôt est la définition ; chaque VM en est une instance. Ce document décrit le modèle, les registres, les commandes et le flux de travail.
Règle d'or :
instance/inventories/<inventaire>/hosts.ymlest GÉNÉRÉ. Ne jamais l'éditer à la main. On édite le plan puis on régénère (make instancier-appliquer).
<inventaire>n'est pas un nom, c'est une place. Le dépôt n'impose pas comment une instance nomme son inventaire : le moteur le cherche, dans l'ordreprincipal, puisproduction(scripts/inventory_rules.py:ORDRE_INVENTAIRE; pour la construction du gabarit,ORDRE_INVENTAIRE_MODELEessaielabd'abord). La flotte utiliseprincipal; le modèle public livré dansexemples/modeles/socle/utiliseproduction, et le QUICKSTART l'écrit tel quel parce que c'est ce que son lecteur a sous la main. Les documents de doctrine, eux, écrivent<inventaire>: coder l'un des deux noms en dur y serait faux pour la moitié des lecteurs — et ça l'a été jusqu'au 2026-09-06.
1. Le modèle : deux ancres, cinq liens
L'écosystème = des serveurs (VM) et des applications, reliés à leurs bases, leurs domaines et leurs dépendances :
serveur (VM) ──fournit──▶ capacités (= groupes/rôles Ansible)
application ──tourne_sur──▶ serveur (une VM peut porter N applications)
application ──requiert──▶ application(s) (DNS, PKI, BD…)
application ──utilise──▶ base(s) (via le DSN)
application ──expose──▶ domaine(s) public(s) (le FQDN, derrière l'edge)
base ──hébergée_sur──▶ serveur de BD
L'application est l'entité pivot : tout ce qui décrit « ce qui tourne et à quoi c'est connecté » pend d'elle. Le groupe Ansible n'est plus une cible de liaison — seulement une capacité qu'une VM fournit (le rôle appliqué).
2. Les registres (source unique de vérité)
Machine-lisibles, validés, consommés par le GUI, le CLI et Ansible. Ils vivent dans
l'instance (instance/plan/), pas dans le moteur — c'est toute la séparation
moteur/instance. Seul dependances-groupes.yml est sous docs/, parce qu'il décrit une
propriété des rôles, la même pour toutes les instances.
| Registre | Décrit | Champs clés |
|---|---|---|
nomenclature.yml |
nommage & adressage | index (le seed, seul champ d'adressage), fonctions (catégorie/service), categories (libellés de zones), cidr_hote, reservations. Ni supernet, ni vlan, ni passerelle : P20 les refuse — ils se dérivent. |
serveurs.yml |
les VM du plan | fonction, etat (actif/planifie), placement Proxmox (noeud/stockage/disque/memoire/coeurs), integrations (les client_* facultatives seulement — les universelles viennent du rôle, voir integrations-vm.md) |
applications.yml |
les applications | groupe (capacité/rôle), hote (VM), port, requiert, expose, (+ bases via consommateur) |
bases-donnees.yml |
serveurs de BD + bases | serveurs_bd ; bases_donnees : serveur/base/proprietaire/secret(Vault), consommateur + portee (application/groupe/hote), usage |
domaines.yml |
zones DNS publiques | domaines_publics : autorite, edge, secondaires, dnssec, mail |
dependances-groupes.yml |
prérequis entre groupes | requiert_groupes_actifs |
Dérivations clés
- Nommage/adressage : tout part du seed
indexet de lafonctionde l'hôte.supernet = 10.<index>.0.0/16,zone = 10.<index>.(15+catégorie),VLAN = 1000 + index×10 + zone,VMID = <VLAN><octet-hôte><rang>— neuf chiffres, miroir de l'IP. Voirdocs/nomenclature-vm.md. (Les formules à cinq chiffres et le réseau unique10.0.xqui figuraient ici décrivaient le modèle d'avant le multi-instance.) - DSN (lien application↔base) :
<type>://<proprietaire>:<secret>@<hôte>:<port>/<base>. Une application reçoit les bases où(portee=application ET consommateur=elle)OU(portee=groupe ET consommateur=son groupe)OU(portee=hote ET consommateur=son hôte). - Exposition DNS :
application.expose: [fqdn]+ l'edgedu domaine parent →serveur_nginxgénère le vhost (application → hôte → IP:port).
3. La génération (méta-classe)
make instancier produit hosts.yml depuis le plan :
- host vars :
ansible_host/ansible_user+proxmox_*(IP/VMID/VLAN/passerelle dérivés de la nomenclature ; placement/taille depuisserveurs.yml). - groupes d'une VM = socle (
serveur_debian+serveur_durci)- services (les
groupedes applications de l'hôte) - intégrations universelles (politique du rôle :
roles/client_*/meta/integration.yml) - intégrations facultatives (
serveurs.yml: integrations) - état (
hotes_actifs/hotes_planifies).
- services (les
La comparaison est sémantique (via ansible-inventory --list, formatage
ignoré). « Diff vide » = le plan reproduit exactement l'inventaire courant ;
c'est le feu vert pour appliquer.
4. Le flux de travail
éditer le PLAN ──▶ make instancier (revoir le diff) ──▶ make instancier-appliquer ──▶ déployer
(GUI ou CLI) (que va-t-il changer ?) (régénère hosts.yml) (make deployer)
Via le GUI — make inventaire-ui
Onze vues, éditables ou dérivées (la table n'en listait que cinq) :
| Vue | Rôle |
|---|---|
| Serveurs (éditable) | les VM du plan : fonction/état/placement/intégrations (VMID·IP·VLAN dérivés en direct) ; bouton « Appliquer le plan » |
| Applications (éditable) | groupe/hôte/port/requiert/expose, et les liens acceptés par le rôle |
| Bases (éditable) | serveurs de BD et bases (portée + consommateur), DSN affiché (secret masqué) |
| Domaines (éditable) | zones publiques vs internes, autorité · edge · DNSSEC, expositions |
| Intégrations (éditable) | la matrice serveurs × intégrations ; les universelles en ✓ non décochables |
| Intrants (éditable) | les intrants de base — identité, Proxmox, fabric, et la liste de rappel des secrets (lecture seule) |
| Inventaire (lecture seule) | l'inventaire généré — vue d'ensemble des hôtes |
| Chaîne (lecture seule) | vue holistique par hôte : groupes → rôles, et par application ses expose / requiert / bases |
| Flux (lecture seule) | la matrice d'audit des flux — source de nftables et justification lisible |
| Couches (lecture seule) | l'ordre de déploiement en six couches |
| Réseau (lecture seule + bascule) | la flotte multi-instances, les collisions d'index, et le bouton « Activer » |
Édition → Sauvegarder (écrit le registre) → Appliquer le plan (régénère
hosts.yml). L'écriture directe de l'inventaire est refusée (409).
Via le CLI / make
Chaque registre a son script miroir et ses cibles make :
| Domaine | Lister | Vérifier | Bootstrap (depuis l'inventaire) |
|---|---|---|---|
| Serveurs | make serveurs |
make serveurs-verifier |
make serveurs-bootstrap |
| Applications | make applications |
make applications-verifier |
make applications-bootstrap |
| Bases | make bases |
make bases-verifier |
— |
| Domaines | make domaines |
make domaines-verifier |
— |
Génération :
make instancier # génère hosts.genere.yml (gitignoré) + diff sémantique
make instancier-appliquer # régénère hosts.yml (refuse si diff non vide ; FORCE=1 pour forcer)
Validation globale : make inventaire-verifier (ansible-inventory + tous les
registres + node --check du JS du GUI).
5. Garde-fous
- Validateurs : chaque registre est validé (références connues, énumérations,
unicité). Un
exposesans domaine parent, unrequiertfantôme, uneporteeinconnue, unefonctionabsente → rejet. - Diff vide :
instancier-appliquerrefuse d'écraser l'inventaire si le plan ne le reproduit pas (saufFORCE=1pour un changement intentionnel). node --check: le JS embarqué du GUI est vérifié (scripts/verifier_gui.py, intégré àmake inventaire-verifier) — une erreur de syntaxe JS casse toute la page.- git :
hosts.ymlest versionné ;git diff/git checkoutest le filet. - Secrets : jamais en clair ;
secret:nomme une variable Ansible Vault.
6. Réutilisation de la règle (Ansible)
La règle de résolution vit une seule fois, en Python (scripts/inventory_rules.py),
et est exposée à Ansible par un filter plugin (filter_plugins/registres.py) :
bases_de_application, applications_de_hote, expositions_des_applications,
chaine_connexion. Les playbooks par application (serveur_web_dorsal, serveur_web_frontal)
itèrent ainsi sur les applications de l'hôte et résolvent leurs DSN.
7. Amorçage / reconstruction
Pour (re)construire le plan depuis un inventaire existant :
make serveurs-bootstrap # VM -> instance/plan/serveurs.yml (fonction/état/placement/integrations)
make applications-bootstrap # services serveurs_* (hors socle) -> instance/plan/applications.yml
make instancier # vérifier le diff vide
C'est ainsi que le plan a été initialisé sans perte, avec diff vide vérifié.
8. Moteur et instance : deux dépôts
Le moteur (ce dépôt, Set-OPS) est générique et partageable ; il ne contient
aucune donnée d'instance. Une instance (le plan + l'inventaire d'une organisation) vit
dans son propre dépôt (ex. OPS-monatelier).
Le moteur localise l'instance via SETOPS_INSTANCE (défaut : instance). Deux
modèles :
- Modèle A — dépôts frères (en cours) : moteur et instance côte à côte ; un
symlink
instance -> ../OPS-monatelier(gitignoré) fait que le défaut résout l'instance sans configuration. Idéal quand on développe le moteur et l'instance. - Modèle B — moteur en sous-module (futur, quand plusieurs écosystèmes vivront chez des exploitants distincts) : l'instance épingle
une version du moteur ;
SETOPS_INSTANCEpointe la racine de l'instance.
Pour brancher une instance (modèle A) :
cd Set-OPS
ln -s ../OPS-monatelier instance # ou : export SETOPS_INSTANCE=/chemin/instance
make inventaire-verifier # lit l'instance via le symlink
Le moteur écrit hosts.yml (généré) dans le dépôt d'instance, jamais dans le sien.