Decision de l exploitant : sites et locataires se partagent la classe A, chacun avec son propre index. L exception du guide — un site derive du meme index que son tenant — disparait. Ce qu elle cachait : le plan d administration du site vit dans 10.17.0.0/24, a l interieur du supernet du locataire OPS-Chezlepro. Pas dangereux, mais 10.17.0.0/16 designait deux choses. Et les zones du site ne derivaient de rien — le site etait la seule partie du systeme sans seed. La seconde liste nait avec cette decision : un site et un locataire peuvent desormais reclamer le meme nombre, et make instances ne voyait que les depots OPS-*. La decouverte lit maintenant SITE-*/underlay.yml et son champ index. Un site sans index declare reste hors du compte. SITE-Technolibre : squelette du deuxieme site pour la visite du 14. Un seul noeud Proxmox en version 9, meme forme que Chezlepro, adresse depuis l index 31. COLLECTE.md liste les 35 valeurs a relever. Reste a l exploitant : OPS-Chezlepro passe a 37, ce qui libere 17 pour le site qui l utilise deja. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
13 KiB
Carte d'orientation Set-OPS
Pour qui : le mainteneur — celui qui va modifier le moteur. À lire avant d'ajouter quoi que ce soit.
Tu viens plutôt exploiter un écosystème déjà déployé ? Wiki → Reprendre l'écosystème. Tu apprends le métier ? Wiki → Accueil.
Point d'entrée vers le corpus documentaire, et catalogue des mécanismes transverses — ceux qui vivent dans le code et qu'on re-découvre sinon. Créée le 2026-07-03 après un audit du dépôt, revue le 2026-07-29. But : ne plus re-déterrer ce qui existe.
Le dépôt est déjà bien documenté. Le manque n'était pas la doc du modèle, mais (a) un index « par où commencer » et (b) une carte des mécanismes (dispersés dans le code + les README de rôles). Cette page comble ces deux trous.
Le dépôt en chiffres
Ces valeurs sont mesurées, pas recopiées : P48 les recompte et refuse tout écart. Elles étaient toutes fausses le 2026-08-26 — de 6 rôles, de 12 pièces d'audit, de 8 décisions. Aucune ne faisait travailler personne ; mais une carte dont les faits vérifiables sont faux cesse d'être consultée, et c'est alors ses pointeurs qu'on perd.
| Ce qu'on compte | Combien | Comment on le mesure |
|---|---|---|
| rôles | 68 | roles/*/ |
| README de rôles | 68 | roles/*/README.md — l'écart avec la ligne au-dessus est la dette |
| documents | 40 | docs/*.md |
| pièces d'audit | 43 | docs/audit/* |
| unités de wiki | 27 | wiki/*.md |
| décisions en vigueur | 85 | lignes | **D-nn** | de decisions-architecture.md |
| décisions renversées | 3 | lignes | **D-nn** — du même document |
1. À lire d'abord (dans l'ordre)
| Sujet | Documents |
|---|---|
| Autorité / gouvernance | AGENTS.md (source d'autorité), CLAUDE.md, docs/MISE-A-JOUR-CODEX-CLAUDE.md |
| Le modèle (plan) | docs/architecture-set-ops.md (survol) → docs/plan-et-generation.md (à fond) → docs/meta-classe.md (concept) |
| Services, maturité, dette | docs/catalogue-services.md (la carte de maturité + la cruft y sont déjà) |
| Exploitation / VM | docs/vm-lifecycle.md, docs/procedure-template-debian13-proxmox.md, docs/config-proxmox.md, docs/nomenclature-vm.md, docs/multi-instances.md |
| Conceptions de domaine | docs/identite-sso.md, docs/courriel-conception.md, docs/bindings-conception.md, docs/dns-interne.md, docs/dimensionnement-ressources.md, docs/integrations-vm.md |
| Réseau / pare-feu | docs/flux-conception.md (le modèle) → docs/registre-flux.md (généré, matrice d'audit) → docs/frontiere-opnsense.md (la bordure nord/sud) ; underlay : underlay.yml.example + make underlay |
| Ordre de déploiement | docs/couches-deploiement.yml (couches) + docs/dependances-groupes.yml (graphe) → playbooks/site.yml (généré, make site) |
| Conformité du déployé | docs/devis-services.md — les cinq devis de service (make identite-plan, certificats-plan, expositions-plan, postgresql-plan, courriel-plan) et les cinq devis d'infrastructure (frontiere-plan, proxmox-fw-plan, sdn-plan, underlay-plan, placement-plan). Répondent à ce que make prouver ne demande jamais : ce qui tourne correspond-il à ce qui est déclaré ? |
| Preuve / recette | docs/audit/affirmations.md (registre), make prouver → docs/audit/preuve-<date>.md — statique : lit le dépôt, aucun appel réseau ; la conformité du déployé est l'affaire des devis de service (ligne au-dessus), docs/audit/plan-de-recette.md (généré du wiki), docs/audit/protocole-operateur-independant.md |
| Décisions d'architecture | docs/decisions-architecture.md — les décisions en vigueur (comptées ci-dessus), pourquoi, où lire le détail, et ce qui les garde ; plus les décisions renversées et leur cause |
| SDN / routage | docs/sdn-evpn.md — décision du 2026-08-02 : le routage inter-zone passe des commutateurs aux hyperviseurs (zones EVPN = VRF). En service depuis le 2026-08-03 (routage_tenants: sdn dans l'underlay.yml du site) : les trunks ne portent plus que deux VLAN d'underlay au lieu de quinze, les passerelles .1 sont anycast sur chaque hyperviseur. Écart mesuré par make sdn-plan |
| Migration de tenant | docs/migration-tenant.md — recette en neuf étapes (0 à 8), machine à états, gardes ; le receveur se construit avant tout gel |
| Exploitation courante | docs/runbooks-exploitation.md, docs/intrants-communs.md, docs/intrants-base-gui-conception.md, docs/theme-forgejo-hors-flotte.md |
| Pédagogie (le wiki) | wiki/ — les unités (comptées ci-dessus) publiées par make wiki-publier ; entrer par wiki/Home.md |
| Vision / positionnement | docs/ecosysteme-chezlepro.md, docs/positionnement.md, docs/pouvoirs-set-ops.md |
2. Les mécanismes transverses (et OÙ ils vivent)
Ce que je re-découvre sinon. Consulter avant de concevoir un nouveau mécanisme.
| Mécanisme | Ce que c'est | Où, dans le code | Doc |
|---|---|---|---|
| Plan → inventaire | plan/*.yml → hosts.yml généré |
scripts/instancier.py, scripts/inventory_rules.py |
plan-et-generation.md |
| Schéma des registres | la forme des six registres — champs, types, énumérations, requis — dérivée des validateurs, jamais écrite à la main. Sert à générer les formulaires plutôt qu'à les écrire. La cohérence reste aux valider_* : un schéma ne sait pas dire qu'un consommateur désigne une application inexistante |
scripts/schema_plan.py (make schema) → docs/audit/schema-plan.json ; garde P61 |
plan-et-generation.md |
| Nomenclature dérivée | VMID / IP / VLAN / FQDN dérivés | inventory_rules.deriver_nomenclature + plan/nomenclature.yml |
nomenclature-vm.md |
| Dimensionnement | RAM/CPU/disque sommés par logiciel | roles/*/meta/empreinte.yml → deriver_ressources |
dimensionnement-ressources.md |
| Bindings app→app | lien côté app (liens) résolu en host_vars |
plan/applications.yml liens: + roles/*/meta/liens.yml + instancier.resoudre_liens |
bindings-conception.md |
| Bindings app→base | lien côté base (consommateur/portee) résolu dans le rôle |
plan/bases-donnees.yml + rôle utilitaire resoudre_base (lookup('vars', secret), no_log) inclus par le consommateur |
bindings-conception.md §5 |
| Résolution d'annuaire | connexion LDAP (uri/base DN/bind) dérivée, jamais recopiée | rôle utilitaire resoudre_annuaire (inclus par dovecot/postfix/keycloak/icingaweb2 et amorcage_acces) |
identite-sso.md |
| Plancher de résolution | /etc/hosts généré depuis l'inventaire + alias d'expose → l'écosystème se résout DNS éteint |
rôle hosts_statiques (appliqué dans la couche socle) |
dns-interne.md |
| Pont de certificat | cert step_ca → service, resync au renouvellement | script *-cert-sync + unité .path, dans chaque rôle serveur ; cert déposé par client_pki |
— |
| Ordonnancement socle-first | socle/durci avant les client_* |
serveur_debian/serveur_durci d'abord (posent /etc/hosts via hosts_statiques) |
— |
| Sûreté check-mode | dry-run fiable | when: not ansible_check_mode sur les tâches de service + handlers |
— |
| Voûte au déploiement | secret jamais en clair ; une voûte, une clé depuis le 2026-08-28 | ANSIBLE_VAULT_IDENTITY_LIST construit par scripts/voutes.py (clé nommée ~/.config/setops-vault-<dépôt>) ; déréférencé par lookup('vars', <nom>) |
autorisation.md §6.1 |
| Multi-instance | un dépôt par écosystème ; l'active = symlink instance/, les autres découvertes par convention (dossiers frères, aucun registre) |
active : symlink instance/ ; découverte : scripts/instances.py / devis_reseau.py (glob ../*/plan/nomenclature.yml avec index) ; garde-fou collision : preuve P21 |
multi-instances.md |
| Exposition → edge | app expose un FQDN public servi par un edge | plan/domaines.yml + expose (applications) |
bindings-conception.md §4 |
| Exploitation de l'hébergeur | ses opérations n'appartiennent à aucun tenant et restent hors overlay | à moitié construit : les VM du site ont leur inventaire (scripts/site_inventaire.py), leur socle, leur durcissement, leurs sauvegardes et leur supervision (site-mon-01, 2026-09-02). Les équipements — hyperviseurs, commutateurs, frontière — n'ont toujours ni inventaire, ni sauvegarde de configuration, ni supervision |
hebergeur-exploitation.md |
| Authentification | web → Keycloak ; LDAP source unique ; secours par sudo, formulaire local non annoncé |
<rôle>_connexion_locale: false (grafana, forgejo, nextcloud) ; garde de version Forgejo ≥ 10 |
authentification.md |
| Accès & habilitations | Set-OPS amorce un accès sysadmin puis se retire ; les appartenances aux groupes ne sont jamais réconciliées — c'est une personne qui gouverne | construit et éprouvé (2026-08-08) : rôle amorcage_acces (idempotence par existence, D-67), groupes projetés en rôles par serveur_keycloak, meta/acces.yml dans les 5 rôles web ; chaîne LDAP → Keycloak → groupe → service exercée de bout en bout sur Icinga Web 2 |
autorisation.md (§6 = runbook de reprise) |
| SDN EVPN | ajouter un tenant implique 1 zone + 6 VNets + 6 sous-réseaux, tous dérivés du seed | scripts/devis_sdn.py (make devis-sdn) ; nommage dérivé du seed (t17, t17serv), ≤ 8 caractères ; garde P30 |
sdn-evpn.md §2 |
| Pools Proxmox | un pool par tenant : les noms courts de VM sont volontairement identiques d'un tenant à l'autre (même fonction, même nom), et seule la console Proxmox en souffrait | scripts/devis_proxmox_pools.py (make devis-proxmox-pools) ; nom dérivé de l'index ; garde de collision = preuve P28 |
decisions-architecture.md D-37 |
| Routage | aucun commutateur ne route : la frontière est le seul équipement L3 ; les switches commutent | passerelle dit qui porte la passerelle, le SVI se dérive du rôle du porteur |
decisions-architecture.md D-49/50 |
| Devis de service | LIT le système en marche et le compare à ce que le plan dérive ; n'écrit rien (D-23/D-24 portés du réseau aux services). Le playbook relève, Python compare | playbooks/maintenance/devis-*.yml + scripts/devis_*.py ; cible make <sujet>-plan |
devis-services.md |
| Frontière nord/sud | les flux pair: externe — sautés par le pare-feu d'hôte — sont la politique de bordure |
scripts/devis_opnsense.py (make devis-opnsense) ; garde d'accès admin = preuve P24 |
frontiere-opnsense.md |
⚠️ Deux directions de binding, assumées :
app→appcôté app (instancier),app→basecôté base (registre, résolu en rôle pour que le secret ne quitte jamais le rôle). Ne pas unifier l'un dans l'autre sans raison. Cf.bindings-conception.md.
3. Maturité & dette
- Maturité des rôles, échafaudages, rôles-catégories inertes : voir
docs/catalogue-services.md« État d'implémentation » (source de vérité, tenue à jour). - Dette (audit 2026-07-03, revu le 2026-07-29) :
- ✅ soldé — README de rôles : tous les rôles en ont un (les 12 manquants écrits le
2026-07-29 :
serveur_debian,hosts_statiques,resoudre_base,resoudre_annuaire,serveur_dovecot,serveur_postfix,serveur_rspamd,client_backup,serveur_backup,client_resolveur,serveur_oauth2_proxy,serveur_icingaweb2). - ✅ soldé —
exposeest consommé au déploiement :plan/applications.yml→ filtreexpositions_des_applications→ vhosts nginx dérivés (roles/serveur_nginx/tasks/main.yml, templateexpositions.conf.j2, drapeauserveur_nginx_publier_expositions), + alias/etc/hostsposés parhosts_statiques,- SANs des certificats d'edge dérivés par
scripts/instancier.py.
- SANs des certificats d'edge dérivés par
- ⏳ ouvert —
meta/liens.ymlseulement surserveur_postfix(mailstore,milter) : les autres liens app→app viendront. - ⏳ ouvert —
requiert: câblé côté GUI (édition + validationvalider_applications) mais pas consommé au déploiement ; c'est un indice de dépendance applicative. Les dépendances de groupes (celles qui pilotent l'ordre) vivent dansdocs/dependances-groupes.yml+docs/couches-deploiement.yml, et sont bel et bien consommées par l'orchestrateur (scripts/orchestrer.py→playbooks/site.yml).
- ✅ soldé — README de rôles : tous les rôles en ont un (les 12 manquants écrits le
2026-07-29 :
4. Discipline (pour ne plus re-déterrer)
Avant de concevoir ou d'ajouter un mécanisme :
- lire cette carte + le doc du sujet ;
- arpenter le code (
grep) et lire les README des rôles concernés ; - éprouver l'outil AVANT d'écrire le rôle qui l'enveloppe — une machine jetable hors
plan se fabrique en deux minutes (
make cloner-vm, cf.vm-lifecycle.md§4bis). C'est ce qui a évité les bugs de premier déploiement de rspamd, et ce qui a tranché le pivot Stalwart → Postfix/Dovecot. Elle est invisible au moteur : à détruire à la main ; - étendre / factoriser l'existant plutôt qu'ajouter un chemin parallèle.
Un seul agent IA travaille dans le dépôt à la fois (Codex ou Claude) — cf. AGENTS.md.