L'outil ne savait qu'AUTORISER — `"action": "pass"` etait en dur dans l'emetteur. Une regle de silence ne pouvait donc pas naitre du depot, et j'en avais pose deux a la main sur le boitier : exactement ce que ce projet refuse. CE QUI L'A MOTIVE. Le journal de la frontiere ecrivait 982 000 entrees par jour, dont 82 % un balayage Internet contre le port VNC et le reste du bavardage de decouverte du reseau local. Sa fenetre utile etait tombee a QUARANTE-QUATRE SECONDES. J'y ai cherche la trace d'un flux du site vers les hyperviseurs, je n'ai rien trouve, et j'en ai conclu a tort qu'aucune regle ne bloquait. Un journal noye ment aussi surement qu'un journal mort. Mesure apres declaration : ~20 700/jour. Une regle de silence ne change AUCUN comportement : ce qu'elle vise etait deja refuse par le defaut. Elle ne supprime qu'une trace que personne ne lira. TROIS PIECES. `cle_regle` accepte une action sans changer d'un octet la cle des regles `pass` deja posees. L'ajout naif d'un champ les aurait toutes detruites pour les recreer a l'identique, sur la frontiere, en production. Le plan l'a confirme : 7 a creer, 0 a retirer, 121 inchangees. `_corps_regle` lit l'action, la consignation et la SEQUENCE depuis le devis. La sequence est ce qui rend un `block` sur : OPNsense evalue en `quick`, donc un blocage large emis avant les `pass` fermerait courrier, web et acces distant. `devis_opnsense` lit `opnsense_silences` et en fabrique regles et alias, motif compris — une regle `block` muette sans raison ecrite est indiscernable d'un oubli. P50 garde ces deux dangers. Controles negatifs verifies : un silence en sequence 1 echoue, un silence sans motif echoue. Carte : 28 pieces d'audit (P48 l'avait vu juste). make prouver : CONFORME, 50 OK, 0 echec. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
12 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 | 61 | roles/*/ |
| README de rôles | 61 | roles/*/README.md — l'écart avec la ligne au-dessus est la dette |
| documents | 38 | docs/*.md |
| pièces d'audit | 28 | docs/audit/* |
| unités de wiki | 27 | wiki/*.md |
| décisions en vigueur | 78 | 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). 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). Non éprouvé : spike avant génération |
| Migration de tenant | docs/migration-tenant.md — recette en 8 étapes, 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 |
| 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) |
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 | ANSIBLE_VAULT_PASSWORD_FILE / ~/.config/setops-vault-pass ; déréférencé par lookup('vars', <nom>) |
— |
| 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 (supervision de la fabric, sauvegarde des configs, DNS d'underlay) n'appartiennent à aucun tenant et restent hors overlay | décidé, non construit : aucun équipement d'hébergeur n'est encore dans un inventaire | 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 tenant (CHEZ17, chez174), ≤ 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.