Solde la dette documentaire repérée à l'audit du 2026-07-03. Tous les rôles ont désormais un README, au format maison (intention → rôle → variables → notes/limites → prérequis). Ils documentent ce qui ne se lit PAS dans les tâches : - serveur_debian : rôle-catégorie sans tâches — il ne porte que le flux SSH du plan de gestion, sans quoi les nftables générés couperaient l'accès Ansible à toute la flotte ; le vrai travail est dans le playbook de groupe. - hosts_statiques : le plancher /etc/hosts comme CONDITION de l'ordre de reconstruction (résolution par nom avant que PowerDNS existe) ; fichier entièrement géré, alias d'exposition best-effort. - resoudre_base / resoudre_annuaire : entrées, sorties (facts), et pourquoi le FQDN plutôt que le nom court (fédération + nom canonique pour verify-full). - serveur_dovecot : les 3 réglages Dovecot 2.4 qui conditionnent la remise (static_allow_all_users, mail_inbox_path vide, mail_path par utilisateur) et le local-part seul comme chemin commun LMTP/IMAP ; limite mono-domaine. - serveur_postfix : liens mailstore/milter, recopie de /etc/hosts dans le chroot. - serveur_rspamd : clé DKIM idempotente ; le domaine signé doit être PUBLIC en prod, sinon la signature ne vaut rien pour les MX distants. - client_backup / serveur_backup : jobs déclaratifs, chiffrement côté client, deux pièges (jobs vides = silencieux ; dépôt neuf vide après un from-zero) ; hors-nœud n'est pas hors-site. - serveur_oauth2_proxy : le patron réutilisable Keycloak-devant-n'importe-quoi, et pourquoi allow_unverified_email est nécessaire avec un annuaire LDAP. - serveur_icingaweb2 : modes ldap vs external, écoute à restreindre en SSO. - client_unbound : le garde-fou de bascule (apply ET confirm, validation réelle avant de toucher /etc/resolv.conf). docs/carte-set-ops.md ne décrivait plus l'état du code : - expose EST consommé au déploiement (annoncé comme « Phase 3 à venir ») : expositions_des_applications + expositions.conf.j2, alias /etc/hosts, SANs d'edge dérivés par instancier.py ; - 3 mécanismes transverses ajoutés (résolution d'annuaire, plancher de résolution, resoudre_base nommé dans les bindings app→base) ; - 5 entrées d'index ajoutées : réseau/pare-feu, ordre de déploiement, preuve/recette, exploitation courante, wiki — pans du corpus non indexés ; - ce qui reste ouvert est marqué : meta/liens.yml sur le seul serveur_postfix, requiert non consommé au déploiement (l'ordre vient des couches + du graphe). make verifier vert : ansible-lint 514 fichiers, tests, syntax-check, 23 preuves CONFORME / 0 échec / 0 sauté. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
82 lines
7.3 KiB
Markdown
82 lines
7.3 KiB
Markdown
# Carte d'orientation Set-OPS
|
|
|
|
> **À lire en premier.** 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é** (26 docs + 7 pièces d'audit + 21 unités de wiki, et un
|
|
README par rôle). 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.
|
|
|
|
## 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) ; 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`) |
|
|
| **Preuve / recette** | `docs/audit/affirmations.md` (registre), `make prouver` → `docs/audit/preuve-<date>.md`, `docs/audit/plan-de-recette.md` (**généré** du wiki), `docs/audit/protocole-operateur-independant.md` |
|
|
| **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/` — 21 unités (+ `_Sidebar`) 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 |
|
|
|
|
> ⚠️ **Deux directions de binding, assumées** : `app→app` côté app (instancier),
|
|
> `app→base` cô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_unbound`, `serveur_oauth2_proxy`, `serveur_icingaweb2`).
|
|
- ✅ **soldé** — `expose` **est** consommé au déploiement : `plan/applications.yml` →
|
|
filtre `expositions_des_applications` → vhosts nginx dérivés
|
|
(`roles/serveur_nginx/tasks/main.yml`, template `expositions.conf.j2`, drapeau
|
|
`serveur_nginx_publier_expositions`), + alias `/etc/hosts` posés par `hosts_statiques`,
|
|
+ SANs des certificats d'edge dérivés par `scripts/instancier.py`.
|
|
- ⏳ **ouvert** — `meta/liens.yml` seulement sur `serveur_postfix` (`mailstore`, `milter`) :
|
|
les autres liens app→app viendront.
|
|
- ⏳ **ouvert** — `requiert` : câblé **côté GUI** (édition + validation
|
|
`valider_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 dans
|
|
`docs/dependances-groupes.yml` + `docs/couches-deploiement.yml`, et sont bel et bien
|
|
consommées par l'orchestrateur (`scripts/orchestrer.py` → `playbooks/site.yml`).
|
|
|
|
## 4. Discipline (pour ne plus re-déterrer)
|
|
|
|
Avant de concevoir ou d'ajouter un mécanisme :
|
|
1. lire **cette carte** + le doc du sujet ;
|
|
2. **arpenter le code** (`grep`) et **lire les README des rôles** concernés ;
|
|
3. **é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`.
|