diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ccfa27..e120780 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,13 @@ dur à des liens déclaratifs — `make instancier` donne **DIFF VIDE** (mêmes variables générées), puis les group_vars sont retirés. La topologie mail devient déclarative et portable. Cf. `docs/bindings-conception.md`. Suite : bases (Phase 2), exposition/domaines (Phase 3), GUI (Phase 4). +- **Bindings — Phase 2 (bases) : constat + réconciliation de la note (`docs/bindings-conception.md` §5/§9).** + Inspection du code réel : le binding app→base **existe déjà** — **côté base** (`consommateur`/`portee` + dans `bases-donnees.yml`), résolu **dans le rôle** au déploiement (`include_vars` + filtre + + `lookup('vars', secret)`), sur 4 rôles (postgresql, forgejo, keycloak, icinga). **Délibérément + conservé** (le secret ne quitte jamais le rôle) — ne PAS dupliquer en app-side/instancier. Deux + directions assumées : app→app côté app (instancier), app→base côté base (registre). Reste (reporté + à l'épreuve de Keycloak) : factoriser le bloc de résolution copié-collé en include partagé (DRY). ## 2026-07-02 diff --git a/docs/bindings-conception.md b/docs/bindings-conception.md index 92d9fea..19b0686 100644 --- a/docs/bindings-conception.md +++ b/docs/bindings-conception.md @@ -141,17 +141,41 @@ applications: `domaines.yml` reste le **registre** des domaines publics (autorité, DNSSEC, secondaires, edge) ; le lien app ↔ domaine relie enfin app + domaine + edge, aujourd'hui séparés. -## 5. Réconcilier l'existant (bases) +## 5. Les bases : binding **côté base**, déjà en place (constat 2026-07-03) -Le binding base existe aujourd'hui **côté base** (`consommateur` pointe l'app). On l'aligne sur la -direction retenue : +> **Correction du modèle après inspection du code réel.** La §3.1 tranchait « tout lien côté +> app ». Mais le binding app→base **existe déjà et fonctionne**, par un mécanisme *différent* de +> celui des liens app→app. Il **ne faut pas le dupliquer** dans `instancier`. -- `bases-donnees.yml` garde la **définition** de la base (type, hôte, port, `secret`, - `proprietaire`) — la base reste une entité à part entière ; -- le **lien de consommation** passe côté app (`role: base`) ; la résolution injecte chez le - consommateur la chaîne de connexion + le **nom** de la variable Vault (jamais le secret) ; -- `consommateur` / `portee` sur la base deviennent une **rétro-référence calculée** (ou sont - dépréciés). Migration douce. +Réalité : quatre rôles (`serveur_postgresql`, `serveur_forgejo`, `serveur_keycloak`, +`serveur_icinga`) résolvent leur base **au déploiement, dans le rôle**, depuis le registre +`plan/bases-donnees.yml` : + +```yaml +- include_vars: bases-donnees.yml # charge le registre +- set_fact: entree = bases_donnees | selectattr(consommateur == mon_groupe) # filtre côté base +- assert: entree + secret présents +- set_fact: db_password = "{{ lookup('vars', entree.secret) }}" # déréférence le secret par NOM +- set_fact: db_host = +``` + +Le binding est donc **côté base** (`consommateur` + `portee`), **résolu à l'exécution dans le +rôle**. C'est **délibérément conservé**, pour deux raisons : + +1. **le secret ne quitte jamais le rôle** — `lookup('vars', entree.secret)` déréférence la + variable Vault *par son nom* au moment du déploiement ; instancier n'a jamais à toucher un + secret ni à l'écrire dans l'inventaire ; +2. c'est **déjà utilisé et cohérent** sur 4 rôles ; le refaire en app-side/instancier serait de + la duplication à risque, sans gain. + +**Conséquence sur la §3.1** : la direction « côté app » vaut pour les liens **app→app** (mail, +annuaire, milter…) résolus par instancier. Les liens **app→base** restent **côté base**, résolus +dans le rôle. Deux directions, **assumées**, chacune selon la nature de la cible et la sensibilité +du secret. La §3.1 est donc raffinée, pas contredite. + +Reste comme valeur réelle (non bloquant) : **factoriser** le bloc de résolution copié-collé dans +les 4 rôles en un include partagé (ex. `roles/_resoudre_base/`). À faire **avec l'épreuve de +Keycloak** (qui utilise ce mécanisme), pour valider le DRY en le déployant. Cf. §9. ## 6. Règles de validation @@ -179,11 +203,15 @@ Premier cas concret, à faire en régression (les mêmes variables doivent être ## 9. Phasage -- **Phase 0** : cette note + décision. ✅ (direction : liens côté app) +- **Phase 0** : cette note + décision. ✅ (direction : liens côté app pour app→app) - **Phase 1** : résolveur de liens dans `instancier.py` + `meta/liens.yml` des rôles mail ; - migrer les 3 liens mail ; prouver que le déploiement reste identique (régression). -- **Phase 2** : réconcilier les bases (consommateur → liens app ; chaîne de connexion). -- **Phase 3** : exposition / domaines (vhosts nginx dérivés des liens). + migrer les liens mail ; régression DIFF VIDE. ✅ (2026-07-03 : `mailstore` + `milter` migrés) +- **Phase 2** : bases. ✅ **déjà en place** — binding **côté base** (registre + résolution en + rôle, 4 rôles), cf. §5. Ne PAS dupliquer dans instancier. **Reste (reporté à la session + Keycloak)** : factoriser le bloc de résolution copié-collé en un include partagé (DRY), + validé en déployant Keycloak. +- **Phase 3** : exposition / domaines (vhosts nginx dérivés des liens ; machinerie `expose` / + `expositions_des_applications` déjà présente). - **Phase 4** : vue GUI des liens + graphe. ## 10. Décisions ouvertes