docs : Set-OPS amorce les acces, le sysadmin gouverne (D-65 a D-67)

L'authentification etait resolue et gardee ; l'autorisation n'existait nulle
part. `ou=groups` est cree depuis le debut et AUCUN des 29 roles ne le lit ;
`ou=people` est vide.

D-67 contredit DELIBEREMENT la doctrine du depot : partout ailleurs un ecart est
un defaut a corriger, ici il est legitime — c'est le sysadmin qui travaille.
Set-OPS cree UN acces puis se retire. Idempotence par EXISTENCE, pas par
conformite : compte present, aucune action quel que soit son etat. Reconcilier
effacerait le compte cree la veille pour un nouvel employe.

D-65 : les groupes LDAP portent l'autorisation, Keycloak les projette. Dovecot
et Postfix ne savent pas lire un role Keycloak — un seul endroit a administrer.

D-66 : un service nomme un groupe, jamais une personne : revoquer quelqu'un ne
demande pas un deploiement.

Le §6 est un runbook de reprise. Il dit aussi ce qu'il faut regenerer pour que
la livraison soit un vrai transfert : les comptes de secours ont ete generes
pendant le deploiement, et leur auteur y a eu acces.

Sans registre de personnes, aucune donnee personnelle n'entre dans git.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-08-07 13:27:00 -04:00
parent 84afa6a2af
commit be20ab43a9
4 changed files with 156 additions and 95 deletions

View file

@ -2,36 +2,50 @@
## 2026-08-06 — le chemin nord-sud devient dérivable ## 2026-08-06 — le chemin nord-sud devient dérivable
### L'autorisation devient une doctrine (D-65, D-66) ### Set-OPS amorce les accès, le sysadmin gouverne (D-65 → D-67)
L'authentification était résolue et gardée (P29) ; l'**autorisation** n'existait nulle part. L'authentification était résolue et gardée (P29) ; l'**autorisation** n'existait nulle part.
Constat mesuré : `ou=groups` est créé par `serveur_openldap` depuis le début, et **aucun des Constat mesuré : `ou=groups` est créé par `serveur_openldap` depuis le début, et **aucun des
29 rôles ne le lit** — pas un `memberOf`, pas un filtre de groupe. Toute personne authentifiée 29 rôles ne le lit** — pas un `memberOf`, pas un filtre. `ou=people` est vide aussi : personne
obtient le défaut du service : tout, ou rien, jamais ce qu'on avait décidé — puisqu'on n'avait ne peut entrer autrement que par les comptes de secours en voûte.
rien décidé.
**D-65 — les groupes LDAP portent l'autorisation, Keycloak les projette.** L'argument est **La décision principale contredit délibérément la doctrine du dépôt (D-67).** Partout
mécanique, pas doctrinal : Dovecot et Postfix ne savent pas lire un rôle Keycloak. L'y loger ailleurs, un écart entre le déclaré et le réel est un défaut à corriger : les devis
rendrait la moitié courriel du système aveugle et imposerait deux modèles de permissions — réconcilient, les applicateurs retirent ce qui n'est plus demandé. Pour les habilitations,
donc leur divergence. **l'écart est légitime** — c'est le sysadmin qui fait son travail.
**D-66 — un service nomme un groupe, jamais une personne.** C'est ce qui rend une arrivée ou Deux régimes, et la frontière entre eux :
un départ instantané : une ligne au plan, aucun service touché. Nommer quelqu'un crée une dette
qu'on découvre le jour du départ, service par service.
Le vocabulaire d'habilitation reste **celui du service** (`Admin` chez Grafana, `owner` chez | | Qui décide | Régime |
Forgejo) : inventer une échelle commune obligerait à la traduire partout, et la traduction est |---|---|---|
précisément l'endroit où une habilitation se perd. | quel groupe accorde quoi dans un service | Set-OPS | réconcilié, comme le reste |
| qui appartient à quel groupe | **une personne** | **amorcé une fois, jamais réconcilié** |
Deux points tranchés en écrivant. Le groupe `personnel` mérite d'exister plutôt que d'être Set-OPS crée **un** accès — celui du sysadmin — puis se retire. **Idempotence par existence,
sous-entendu — sans lui, « avoir un compte » et « avoir une boîte aux lettres » sont la même pas par conformité** : compte absent, on le crée ; compte présent, aucune action *quel que soit
chose, et on ne peut désactiver l'un sans l'autre. Et le mot de passe initial n'est pas *le* son état*. Il a pu être renommé, promu, déplacé. Un dépôt qui réconcilierait les appartenances
mot de passe de quelqu'un : généré, en voûte, **changement forcé** à la première ouverture — effacerait le compte créé la veille pour un nouvel employé — exactement la « correction » qu'un
sans quoi l'exploitant connaîtrait celui de chacun. agent zélé ferait sans y penser, d'où la nécessité de l'écrire.
**Rien n'est construit.** Le registre `plan/acces.yml`, le rôle qui peuple LDAP, les **D-65 — les groupes LDAP portent l'autorisation, Keycloak les projette.** Argument mécanique :
`meta/acces.yml` et la preuve P31 restent à écrire. Dovecot et Postfix ne savent pas lire un rôle Keycloak. L'y loger rendrait la moitié courriel
aveugle et imposerait au sysadmin **deux** modèles de permissions. Conséquence pratique : un
seul endroit à administrer.
**D-66 — un service nomme un groupe, jamais une personne.** C'est ce qui rend la reprise
possible : révoquer quelqu'un ne demande pas un déploiement.
**Le §6 est un runbook de reprise**, et c'est la partie utile : récupérer le mot de passe
d'amorçage, où administrer quoi, comment se rouvrir si on se ferme dehors, et ce qu'il faut
changer en priorité. Ce dernier point mérite d'être dit : les comptes de secours ont été
générés pendant le déploiement, et **l'auteur du déploiement y a eu accès**. Les régénérer
n'est pas une formalité — c'est ce qui transforme une livraison en transfert.
Effet secondaire du cadrage : sans registre de personnes, **aucune donnée personnelle n'entre
dans l'historique git**.
**Rien n'est construit.** Le rôle d'amorçage, les `meta/acces.yml` et la preuve restent à
écrire.
### Le courriel interne, et l'annuaire qui ne désignait personne ### Le courriel interne, et l'annuaire qui ne désignait personne

View file

@ -1,8 +1,8 @@
# Autorisation : le groupe LDAP est l'unité d'habilitation # Accès et habilitations : Set-OPS amorce, le sysadmin gouverne
> **Directive d'architecture du 2026-08-07.** L'authentification dit *qui tu es* > **Directive d'architecture du 2026-08-07.** L'authentification dit *qui tu es*
> (`authentification.md`). Ce document dit *ce que tu peux faire*. Les deux sont > (`authentification.md`). Ce document dit *ce que tu peux faire* — et surtout **qui en
> distincts, et le second n'existait pas. > décide**. La réponse n'est pas « le dépôt ».
## 1. Le constat, mesuré ## 1. Le constat, mesuré
@ -10,107 +10,153 @@
**conteneur vide qu'aucun service ne lit** : pas un `memberOf`, pas un filtre de groupe **conteneur vide qu'aucun service ne lit** : pas un `memberOf`, pas un filtre de groupe
dans les 29 rôles du catalogue. dans les 29 rôles du catalogue.
Conséquence : toute personne qui s'authentifie obtient ce que le service accorde par Toute personne qui s'authentifie obtient donc le défaut du service — tout, ou rien. Et
défaut. Selon le service, c'est *tout* ou *rien* — jamais ce qu'on a décidé, puisqu'on aucun humain n'a de compte : `ou=people` est vide aussi. L'écosystème est déployé et
n'avait rien décidé. personne ne peut y entrer autrement que par les comptes de secours en voûte.
Ce n'est pas une négligence : l'authentification était le problème à résoudre d'abord. ## 2. Deux régimes, et la frontière entre eux
Mais une chaîne d'identité sans habilitations n'est qu'une porte d'entrée.
## 2. La décision : LDAP porte les habilitations, pas Keycloak C'est la décision principale, et elle **contredit délibérément la doctrine du dépôt**.
**Les groupes LDAP sont la source unique de l'autorisation.** Keycloak les *projette* en Partout ailleurs, un écart entre le déclaré et le réel est un défaut à corriger : les devis
rôles pour le web ; les services non-OIDC les lisent directement. réconcilient, les applicateurs retirent ce qui n'est plus demandé. **Ici, l'écart est
légitime** — c'est le sysadmin qui fait son travail.
L'argument n'est pas doctrinal, il est mécanique : **Dovecot et Postfix ne savent pas lire | | Qui décide | Régime |
un rôle Keycloak.** Si l'habilitation vivait dans Keycloak, la moitié courriel du système |---|---|---|
y serait aveugle, et il faudrait tenir deux modèles de permissions — donc les voir diverger. | **Infrastructure** — quel groupe accorde quoi dans un service | Set-OPS | réconcilié à chaque déploiement, comme le reste |
| **Habilitations** — qui appartient à quel groupe | **une personne** | **amorcé une fois, jamais réconcilié** |
C'est le prolongement de ce qui était déjà décidé pour les comptes (D-39), étendu aux Le mapping « le groupe `sysadmin` vaut `Admin` dans Grafana » est de la configuration
habilitations : une identité, un mot de passe, **et un seul endroit qui dit ce qu'elle d'infrastructure : il se déclare, se dérive et se corrige. Savoir **qui** est dans
peut**. `sysadmin` ne l'est pas — c'est une décision d'exploitation, prise par un humain, souvent
en urgence, et le dépôt n'a pas à la défaire au prochain `make deployer`.
| Ce que porte LDAP | Ce qui le consomme | Un dépôt qui réconcilierait les appartenances effacerait le compte créé la veille pour un
|---|---| nouvel employé. C'est exactement le genre de « correction » qu'il ne faut pas faire.
| l'identité (`ou=people`) | Keycloak (fédération), Dovecot, Postfix |
| l'habilitation (`ou=groups`) | Keycloak → rôles OIDC ; Dovecot/Postfix directement |
## 3. Un service nomme un groupe, jamais une personne ## 3. L'amorçage est un one-shot
C'est la règle qui rend une arrivée ou un départ instantané : une ligne au plan, **aucun Set-OPS crée **un** accès : celui du sysadmin, pour qu'il puisse prendre la main. Rien de
service touché**. Un service qui nomme quelqu'un crée une dette qu'on découvre le jour du plus.
départ, service par service.
Chaque rôle déclare donc son modèle dans `meta/acces.yml` — même patron que `meta/flux.yml` **Idempotence par non-intervention.** La condition n'est pas la conformité, c'est
et `meta/authentification.yml` : l'**existence** : si le compte est là, on n'y touche pas — ni son mot de passe, ni ses
groupes, ni ses attributs. Il a pu être renommé, promu, déplacé ; c'est le droit de celui
qui exploite.
```
compte sysadmin absent → créé, mot de passe généré en voûte, changement forcé
compte sysadmin présent → aucune action, quel que soit son état
```
C'est la différence entre `state: present` et une réconciliation. Le second serait un
défaut ici.
**Le premier mot de passe n'est pas *le* mot de passe de quelqu'un.** Généré, déposé en
voûte, **changement forcé à la première ouverture** : c'est un jeton d'amorçage à usage
unique. Sans ce changement, l'auteur du déploiement connaîtrait le mot de passe du
sysadmin — ce qui contredit « une identité, une personne ».
## 4. Où vivent les habilitations : LDAP, pas Keycloak
**Les groupes LDAP sont la source unique.** Keycloak les *projette* en rôles pour le web ;
les services non-OIDC les lisent directement.
L'argument est mécanique, pas doctrinal : **Dovecot et Postfix ne savent pas lire un rôle
Keycloak.** L'y loger rendrait la moitié courriel du système aveugle, et imposerait au
sysadmin de tenir deux modèles de permissions — donc de les voir diverger.
Conséquence pratique pour l'exploitant : **un seul endroit à administrer**. Ajouter
quelqu'un au groupe `sysadmin` dans LDAP lui ouvre Grafana, Forgejo, Icinga et le courriel,
sans toucher à un seul service.
## 5. Un service nomme un groupe, jamais une personne
C'est la règle qui rend la reprise possible. Chaque rôle déclare le **groupe** qu'il
reconnaît, dans son `meta/acces.yml` :
```yaml ```yaml
acces: acces:
- groupe: obs-admin # groupe LDAP, déclaré au plan - groupe: sysadmin # groupe LDAP
accorde: Admin # ce que ça vaut DANS ce service accorde: Admin # ce que ça vaut DANS ce service
raison: >- raison: >-
Édition des tableaux de bord et des sources de données. Administration : sources de données, tableaux de bord, utilisateurs.
``` ```
Le champ `accorde` est **le vocabulaire du service**, pas un niveau abstrait : `Admin` Le champ `accorde` est **le vocabulaire du service**, pas un niveau abstrait : `Admin` chez
chez Grafana, `owner` chez Forgejo, `admin` chez Nextcloud. Inventer une échelle commune Grafana, `owner` chez Forgejo. Inventer une échelle commune obligerait à la traduire
obligerait à la traduire partout, et la traduction est exactement l'endroit où une partout, et la traduction est exactement l'endroit où une habilitation se perd.
habilitation se perd.
## 4. Les groupes se déclarent au plan Un service qui nommerait une personne créerait une dette qu'on découvre le jour du
départ, service par service — et il faudrait un déploiement pour révoquer quelqu'un.
Un registre `instance/plan/acces.yml` déclare les personnes et les groupes, et le rôle qui ## 6. Prendre la main — le runbook
peuple LDAP le dérive — comme les VMID, les adresses et le supernet. Le plan reste la
seule chose qu'un opérateur édite.
**Trois ou quatre groupes, pas un modèle RBAC.** Chezlepro a un sysadmin et quatorze VM ; Ce qui suit est destiné au sysadmin le jour de la livraison. **C'est la partie utile de ce
une hiérarchie fine coûterait plus qu'elle ne protège. Affiner plus tard est facile, document.**
l'inverse ne l'est pas.
| Groupe | Qui | Ce que ça ouvre | ### 6.1 Récupérer le mot de passe d'amorçage
```
ansible-vault view instance/inventories/principal/group_vars/all/vault.yml \
| grep vault_sysadmin_amorcage
```
Il ne servira qu'une fois : la première connexion impose son changement.
> Le mot de passe de la voûte est lu depuis `ANSIBLE_VAULT_PASSWORD_FILE`
> (`~/.config/setops-vault-pass` par défaut). **Sans ce fichier, rien de ce qui suit n'est
> possible** — c'est la clé de voûte au sens propre, et la première chose à sauvegarder
> hors de la machine.
### 6.2 Où administrer quoi
| Ce que tu veux faire | Où | Comment |
|---|---|---| |---|---|---|
| `sysadmin` | l'exploitant | administration des services, supervision | | créer/désactiver une personne | **LDAP** (`ou=people`) | via Keycloak, ou `ldapmodify` |
| `personnel` | toute personne de l'organisation | courriel, nuage, espace de travail | | donner ou retirer un accès | **LDAP** (`ou=groups`) | ajouter/retirer du groupe |
| `dev` | qui écrit du code | forge | | changer ce qu'un groupe *vaut* dans un service | **le plan** (`meta/acces.yml`) | c'est de l'infrastructure : éditer, redéployer |
Le groupe `personnel` mérite d'être nommé plutôt que sous-entendu : sans lui, « avoir un La troisième ligne est la seule qui passe par Set-OPS. Les deux premières t'appartiennent
compte » et « avoir une boîte aux lettres » seraient la même chose, et on ne saurait pas et **le dépôt ne les touchera plus jamais**.
désactiver l'un sans l'autre.
## 5. Le premier mot de passe ### 6.3 Si tu te fermes dehors
Une personne est un **tiers** : elle choisit son mot de passe, le dépôt ne l'invente pas. Les comptes locaux de chaque service existent, sont en voûte, et leur formulaire n'est pas
La règle du dépôt est constante — un secret se **génère** quand le dépôt en est la source, annoncé (`authentification.md` §3). L'accès de secours passe par `sudo` sur l'hôte :
et se **saisit** quand un tiers l'est. Mais il faut bien un secret pour la première connexion.
**Généré, déposé en voûte, changement forcé à la première ouverture.** Le secret généré ```
n'est donc jamais *le* mot de passe de quelqu'un : c'est un jeton d'amorçage à durée de vie grafana-cli admin reset-admin-password
d'un usage. La distinction compte — sans le changement forcé, l'exploitant connaîtrait le forgejo admin user change-password
mot de passe de chacun, ce qui contredit « une identité, une personne ». occ user:resetpassword
```
## 6. La garde Et si LDAP lui-même est en panne, ces trois commandes fonctionnent quand même : elles ne
dépendent ni de Keycloak, ni de l'annuaire. C'est le sens de D-40.
Une directive qu'aucune garde ne vérifie finit par ne plus être vraie — c'est ce que ### 6.4 Ce que tu dois changer en priorité
`authentification.md` §5 a déjà appris. **P31** confronterait les deux sens :
- tout groupe nommé dans un `meta/acces.yml` **existe** au plan ; 1. **Le mot de passe d'amorçage** — dès la première connexion, imposé.
- toute personne déclarée appartient à **au moins un** groupe ; 2. **Les comptes de secours** générés au déploiement : ils sont en voûte, et l'auteur du
- aucun rôle `web-sso` n'accorde d'accès sans déclarer son modèle ; déploiement y a eu accès. Les régénérer transfère réellement le contrôle.
- aucun `meta/acces.yml` ne nomme une personne. 3. **Le mot de passe de la voûte** elle-même, si le dépôt change de mains.
Le dernier point est le plus important : c'est la règle du §3, et c'est celle qu'on
enfreint sans le remarquer, un service à la fois.
## 7. Ce que ce document ne couvre pas ## 7. Ce que ce document ne couvre pas
**La gestion courante des comptes.** Créer, suspendre, réaffecter : c'est le travail du
sysadmin, pas du dépôt. Set-OPS ne fournit ni registre de personnes, ni synchronisation —
volontairement. Un registre versionné mettrait des données personnelles dans l'historique
git, de façon permanente et difficile à retirer.
**L'autorisation machine-à-machine.** Les comptes de service (PostgreSQL, Redis, jetons **L'autorisation machine-à-machine.** Les comptes de service (PostgreSQL, Redis, jetons
d'API) ne sont pas des humains et ne passent pas par LDAP — ils vivent en voûte, liés à un d'API) ne sont pas des humains et ne passent pas par LDAP — ils vivent en voûte, liés à un
service et non à une personne. Les mêler aux groupes humains rendrait les deux illisibles. service et non à une personne.
**Les permissions internes à un service.** Qui peut écrire dans quel dépôt Forgejo, qui **Les permissions internes à un service.** Qui peut écrire dans quel dépôt Forgejo, qui voit
voit quel dossier Nextcloud : ça se règle dans le service, à partir du groupe qu'il a reçu. quel dossier Nextcloud : ça se règle dans le service, à partir du groupe qu'il a reçu.
Set-OPS accorde l'entrée et le niveau ; il ne réimplémente pas le modèle interne de chaque Set-OPS accorde l'entrée et le niveau ; il ne réimplémente pas le modèle de chaque
application. application.
**Rien n'est construit.** Ce document fixe la direction ; le registre, le rôle qui peuple **Rien n'est construit.** Ce document fixe la direction ; le rôle d'amorçage, les
LDAP, les `meta/acces.yml` et la preuve P31 restent à écrire. `meta/acces.yml` et la preuve restent à écrire.

View file

@ -50,7 +50,7 @@ Ce que je re-découvre sinon. **Consulter avant de concevoir un nouveau mécanis
| Exposition → edge | app expose un FQDN public servi par un edge | `plan/domaines.yml` + `expose` (applications) | `bindings-conception.md` §4 | | 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` | | 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` | | 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` |
| Autorisation | les **groupes LDAP** sont l'unité d'habilitation ; un service nomme un groupe, jamais une personne | **décidé, non construit** : `ou=groups` existe et reste vide, aucun rôle ne le lit | `autorisation.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 | **décidé, non construit** : `ou=people` et `ou=groups` existent et restent vides | `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 | | 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 | | 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 | | 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 |

View file

@ -79,8 +79,9 @@ sont les seules vérifiables.
| **D-40** | L'accès de secours passe par **`sudo` sur l'hôte**, pas par un compte web permanent | `service → Keycloak → LDAP` est en série : sans secours, une panne exclut tout le monde, y compris pour réparer | `authentification.md` §4 | — | | **D-40** | L'accès de secours passe par **`sudo` sur l'hôte**, pas par un compte web permanent | `service → Keycloak → LDAP` est en série : sans secours, une panne exclut tout le monde, y compris pour réparer | `authentification.md` §4 | — |
| **D-41** | Le formulaire de connexion locale n'est **pas proposé au repos** (`<rôle>_connexion_locale: false`) | il contourne la politique de mot de passe, le MFA et surtout la **révocation centrale** ; `sudo` est le mécanisme de réouverture | `authentification.md` §3 | — | | **D-41** | Le formulaire de connexion locale n'est **pas proposé au repos** (`<rôle>_connexion_locale: false`) | il contourne la politique de mot de passe, le MFA et surtout la **révocation centrale** ; `sudo` est le mécanisme de réouverture | `authentification.md` §3 | — |
| **D-65** | Les **groupes LDAP** portent l'autorisation ; Keycloak les *projette*, il ne les détient pas | Dovecot et Postfix ne savent pas lire un rôle Keycloak : l'y loger rendrait la moitié courriel du système aveugle, et imposerait deux modèles de permissions — donc leur divergence | `autorisation.md` §2 | P31 | | **D-65** | Les **groupes LDAP** portent l'autorisation ; Keycloak les *projette*, il ne les détient pas | Dovecot et Postfix ne savent pas lire un rôle Keycloak : l'y loger rendrait la moitié courriel aveugle et imposerait au sysadmin **deux** modèles de permissions — donc leur divergence. Un seul endroit à administrer | `autorisation.md` §4 | — |
| **D-66** | Un service nomme un **groupe**, jamais une personne | une arrivée ou un départ devient une ligne au plan, sans toucher un seul service ; nommer quelqu'un crée une dette qu'on découvre le jour du départ | `autorisation.md` §3 | P31 | | **D-66** | Un service nomme un **groupe**, jamais une personne | c'est ce qui rend la reprise possible : révoquer quelqu'un ne demande pas un déploiement. Nommer une personne crée une dette qu'on découvre le jour du départ, service par service | `autorisation.md` §5 | — |
| **D-67** | Les **appartenances aux groupes ne sont jamais réconciliées** : Set-OPS amorce **un** accès sysadmin, puis se retire | contredit délibérément la doctrine du dépôt, où un écart est un défaut. Ici l'écart **est** l'exploitation : réconcilier effacerait le compte créé la veille pour un nouvel employé. Idempotence par **existence**, pas par conformité | `autorisation.md` §2-3 | — |
| **D-42** | Chaque rôle **déclare sa position** d'authentification (`meta/authentification.yml`), gardée par une preuve | une directive qu'aucune garde ne vérifie finit par ne plus être vraie — c'était le cas des 28 lignes d'intégration recopiées | `authentification.md` §5 | P29 | | **D-42** | Chaque rôle **déclare sa position** d'authentification (`meta/authentification.yml`), gardée par une preuve | une directive qu'aucune garde ne vérifie finit par ne plus être vraie — c'était le cas des 28 lignes d'intégration recopiées | `authentification.md` §5 | P29 |
## 3. Les secrets ## 3. Les secrets