Some checks failed
verifier / verifier (push) Has been cancelled
La revision a commence par un balayage par motifs — chemins morts, cibles make absentes, comptes derives. Il a trouve une trentaine d ecarts et rate presque tout le reste : un motif ne voit que ce qui s exprime en motif. make hote-planifier en est l exemple. La cible EXISTE, donc le controle passait au vert. C est une cible depreciee qui refuse et sort en 2, recommandee par AGENTS.md, et qui contredit la REGLE D OR du meme fichier trois ecrans plus haut. Il fallait lire pour la voir. 74 documents lus un par un. 66 corriges, 8 exacts. CE QUI ETAIT FRANCHEMENT FAUX AGENTS.md, la source d autorite, annoncait la flotte pas encore executee contre des VM reelles. Elle a ete rasee et remontee depuis zero trois fois. ecosysteme-chezlepro.md, le document montre a un client, portait la meme phrase : il se sous-vendait gravement. courriel-conception.md s ouvrait sur aucun role n est encore ecrit, au-dessus de son propre paragraphe 1 qui les nomme. autorisation.md se terminait sur rien n est construit alors qu il rapporte des mesures datees du role en fonctionnement. hebergeur-exploitation.md disait rien n est fait d un depot qui existe. filiation-emancipation.md se contredisait a deux ecrans de distance. DES MODELES DECRITS D APRES UN MONDE ANTERIEUR Le resolveur : cinq documents decrivaient un Unbound par VM en opt-in, trois le donnaient en exemple d integration FACULTATIVE — il est universel depuis le 2026-08-24. L adressage de nomenclature-vm.md : reseau unique, VLAN 11-15, VMID a cinq chiffres. Le nommage SDN de sdn-evpn.md contre le code : c est le wiki qui avait raison. CE QUI CASSE AU PREMIER ESSAI Le nom du gabarit dore etait faux a quatre endroits, dont la procedure qui le FABRIQUE et le critere R2 de l epreuve d operateur independant. preparer-un-site-hebergeur.md avertissait qu une VM faite a la main serait detruite : raser derive du plan, il ne la detruira jamais — le risque est l inverse. Un mot de passe d essai en clair dans un depot public. DEUX PREUVES ETENDUES, ET UNE QUI SE TROMPAIT ELLE-MEME P57 couvre les groupes : elle a signale aussitot 29 groupes annonces au-dessus d un tableau qui en cite 40. P29 confronte le tableau de authentification.md aux declarations reelles : 12 annonces, 21 reels. Et P57 imposait un chiffre faux — 56 preuves alors que le depot en porte 57, la conditionnelle vivant hors de tout comptage. Un garde-fou qui fait respecter une erreur ajoute l assurance a l erreur. CE QUI RESTE, ET QU AUCUNE PREUVE NE TIENT Deux comptes trouves a la main. Et une lacune reelle : rien ne garde les meta/acces.yml — ni qu un service web-sso en porte un, ni que le groupe qu il nomme existe. P29 tient les positions d authentification, personne ne tient les habilitations. make prouver : CONFORME, 56 OK, 0 echec, 1 saute. 0 lien mort. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
413 lines
22 KiB
Markdown
413 lines
22 KiB
Markdown
# Accès et habilitations : Set-OPS amorce, le sysadmin gouverne
|
|
|
|
> **Pour qui :** l'**exploitant**, le jour de la reprise — le §6 est la partie utile. La doctrine qui précède (§1-5) s'adresse au mainteneur.
|
|
|
|
> **Directive d'architecture du 2026-08-07.** L'authentification dit *qui tu es*
|
|
> (`authentification.md`). Ce document dit *ce que tu peux faire* — et surtout **qui en
|
|
> décide**. La réponse n'est pas « le dépôt ».
|
|
|
|
## 1. Le constat, mesuré
|
|
|
|
`ou=groups` est créé par `serveur_openldap` depuis le début. Au 2026-08-07, c'est un
|
|
**conteneur vide qu'aucun service ne lit** : pas un `memberOf`, pas un filtre de groupe
|
|
dans les 29 rôles du catalogue.
|
|
|
|
Toute personne qui s'authentifie obtient donc le défaut du service — tout, ou rien. Et
|
|
aucun humain n'a de compte : `ou=people` est vide aussi. L'écosystème est déployé et
|
|
personne ne peut y entrer autrement que par les comptes de secours en voûte.
|
|
|
|
> **Révisé le 2026-09-05 — le constat ci-dessus est daté, et il a bougé.** `ou=groups`
|
|
> n'est plus un conteneur que personne ne lit : `amorcage_acces`, `serveur_keycloak` et
|
|
> `serveur_icingaweb2` s'en servent. La mesure du 2026-08-07 est conservée telle quelle
|
|
> parce qu'elle explique *pourquoi* ce document existe — mais elle ne décrit plus l'état
|
|
> du dépôt. Le §2 et la suite, eux, restent la doctrine en vigueur.
|
|
|
|
## 2. Deux régimes, et la frontière entre eux
|
|
|
|
C'est la décision principale, et elle **contredit délibérément la doctrine du dépôt**.
|
|
|
|
Partout ailleurs, un écart entre le déclaré et le réel est un défaut à corriger : les devis
|
|
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.
|
|
|
|
| | Qui décide | Régime |
|
|
|---|---|---|
|
|
| **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é** |
|
|
|
|
Le mapping « le groupe `sysadmin` vaut `Admin` dans Grafana » est de la configuration
|
|
d'infrastructure : il se déclare, se dérive et se corrige. Savoir **qui** est dans
|
|
`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`.
|
|
|
|
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.
|
|
|
|
## 3. L'amorçage est un one-shot
|
|
|
|
Set-OPS crée **un** accès : celui du sysadmin, pour qu'il puisse prendre la main. Rien de
|
|
plus.
|
|
|
|
**Idempotence par non-intervention.** La condition n'est pas la conformité, c'est
|
|
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 ».
|
|
|
|
### 3.1 Raser un hôte d'identité réarme le jeton — et détruit tout le reste
|
|
|
|
Le « one-shot » tient **tant que l'annuaire vit**. `make raser` sur l'hôte qui porte
|
|
`openldap` (dérivé : `applications.openldap.hote`) détruit `ou=people` et `ou=groups` avec
|
|
la VM.
|
|
|
|
La condition étant l'**existence** et non la conformité, le redéploiement retrouve un compte
|
|
absent et le recrée. Mesuré le 2026-08-11, après rasage de `idm-01` :
|
|
|
|
```
|
|
dn: uid=sysadmin,ou=people,dc=chezlepro,dc=internal
|
|
pwdReset: TRUE
|
|
```
|
|
|
|
Le jeton d'amorçage de la voûte redevient donc la valeur en vigueur, et le changement forcé
|
|
est réarmé. **Le mot de passe que l'exploitant avait choisi n'existe plus.**
|
|
|
|
**Ce n'est pas la perte principale.** Par le §2, les appartenances ne sont *jamais*
|
|
réconciliées : Set-OPS crée **un** compte, et rien d'autre. Tout compte créé depuis, toute
|
|
appartenance à un groupe, toute promotion décidée en exploitation sont détruits — et **ne
|
|
seront pas recréés**. Le code ne peut pas reconstruire ce qu'il a délibérément choisi de ne
|
|
pas posséder. C'est la contrepartie exacte du régime qui protège ces décisions du prochain
|
|
`make deployer`.
|
|
|
|
> **Il y a désormais quelque chose à restaurer — depuis le 2026-08-11 seulement.** Jusque-là
|
|
> `client_backup_jobs` valait `[]` et rien ne le surchargeait : onze hôtes lançaient chaque
|
|
> nuit un timer qui échouait sur `Fatal: nothing to backup`, et `infra-pki-01` — les clés de
|
|
> l'AC — n'avait aucune sauvegarde. `client_backup` dérive maintenant ses jeux de
|
|
> l'appartenance aux groupes, et **P36** prouve statiquement que tout détenteur d'état porte
|
|
> `client_backup`. L'annuaire de `idm-01` est sorti par `slapcat` à chaque exécution.
|
|
|
|
La sauvegarde ne dispense pas de la vérifier avant un geste destructeur. Sortir l'annuaire à
|
|
la main reste le réflexe juste avant de raser :
|
|
|
|
```
|
|
ansible <hote_openldap> -m shell -a "slapcat -b dc=<domaine> > /tmp/annuaire.ldif" -b
|
|
ansible <hote_openldap> -m fetch -a "src=/tmp/annuaire.ldif dest=./ flat=yes" -b
|
|
```
|
|
|
|
## 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
|
|
acces:
|
|
- groupe: sysadmin # groupe LDAP
|
|
accorde: Admin # ce que ça vaut DANS ce service
|
|
raison: >-
|
|
Administration : sources de données, tableaux de bord, utilisateurs.
|
|
```
|
|
|
|
Le champ `accorde` est **le vocabulaire du service**, pas un niveau abstrait : `Admin` chez
|
|
Grafana, `owner` chez Forgejo. Inventer une échelle commune obligerait à la traduire
|
|
partout, et la traduction est exactement l'endroit où une habilitation se perd.
|
|
|
|
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.
|
|
|
|
## 6. Prendre la main — le runbook
|
|
|
|
Ce qui suit est destiné au sysadmin le jour de la livraison. **C'est la partie utile de ce
|
|
document.**
|
|
|
|
### 6.0 D'abord : demander au système où il en est
|
|
|
|
Avant de suivre quoi que ce soit, cinq commandes disent l'état réel. Elles ne modifient
|
|
rien et sortent en erreur s'il y a un écart entre ce qui tourne et ce que le plan décrit.
|
|
|
|
```
|
|
make identite-plan # realm, fédération LDAP, mappeurs, politique de mot de passe, comptes
|
|
make certificats-plan # certificats sur disque contre certificats réellement servis
|
|
make expositions-plan # chaque service publié répond-il — depuis l'edge et depuis ton poste
|
|
make postgresql-plan # chiffrement imposé, et à quels réseaux
|
|
make courriel-plan # Postfix → LDAP → LMTP → Dovecot → IMAP, file d'attente comprise
|
|
```
|
|
|
|
C'est le premier réflexe à prendre, et pas seulement le jour de la livraison : après tout
|
|
changement, après une panne, avant d'appeler quelqu'un. `make deployer` **répare** ;
|
|
ces devis **constatent**. Le détail de ce qu'ils vérifient et de ce qu'ils ne vérifient
|
|
pas est dans `devis-services.md`.
|
|
|
|
Un exemple de ce qu'ils voient et que rien d'autre ne voyait : le 2026-08-08, le
|
|
certificat de l'autorité elle-même était expiré depuis plus de huit heures, le
|
|
renouvellement échouant toutes les quatorze minutes. Aucun écran ne le disait.
|
|
|
|
### 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
|
|
```
|
|
|
|
**Tu ne pourras rien faire d'autre avant de l'avoir changé** : l'annuaire refuse toute
|
|
opération sauf le changement lui-même (§3). C'est le premier geste de la reprise, et il
|
|
n'est pas optionnel.
|
|
|
|
> **La clé de la voûte — une voûte, une clé (depuis le 2026-08-28).** Ce paragraphe a
|
|
> longtemps désigné un `ANSIBLE_VAULT_PASSWORD_FILE` unique, `~/.config/setops-vault-pass`.
|
|
> Ce n'est plus le mécanisme : un seul mot de passe ouvrait alors *toutes* les voûtes de la
|
|
> flotte, celle de l'hébergeur comprise — compromettre le plus petit locataire, c'était
|
|
> obtenir les secrets de tous. Chaque dépôt a désormais **sa** clé, nommée d'après lui :
|
|
> `~/.config/setops-vault-<dépôt-en-minuscules>`. Le `Makefile` les rassemble tout seul dans
|
|
> `ANSIBLE_VAULT_IDENTITY_LIST` (`scripts/voutes.py`), et Ansible les essaie toutes — il n'y
|
|
> a **rien à exporter**. Pour voir ce que cette machine peut ouvrir :
|
|
>
|
|
> ```
|
|
> python3 scripts/voutes.py etat
|
|
> ```
|
|
>
|
|
> **Sans la clé de ton écosystème, rien de ce qui suit n'est possible** — c'est la clé de
|
|
> voûte au sens propre, et la première chose à sortir de la machine
|
|
> (`make cles-exporter`, cf. [`sortir-les-cles-du-poste.md`](sortir-les-cles-du-poste.md)).
|
|
|
|
### 6.2 Deux consoles Keycloak, et la racine mène à la mauvaise
|
|
|
|
**C'est le piège de la première connexion.** `https://auth.<domaine>/` redirige vers `/admin/`
|
|
— la console d'administration du realm **`master`**. Le compte `sysadmin` n'y existe pas : il
|
|
vit dans le realm applicatif. Keycloak répond alors *« invalid username or password »*, ce qui
|
|
est exact et parfaitement trompeur — le mot de passe est bon, c'est la porte qui ne l'est pas.
|
|
|
|
| Ce que tu veux faire | URL | Compte |
|
|
|---|---|---|
|
|
| **ton compte, tes accès** | `https://auth.<domaine>/realms/<realm>/account/` | `sysadmin` + jeton d'amorçage |
|
|
| **administrer ton realm** | `https://auth.<domaine>/admin/<realm>/console/` | `sysadmin` — par le groupe |
|
|
| Keycloak lui-même (secours) | `https://auth.<domaine>/admin/` | `admin` + `vault_keycloak_admin` |
|
|
|
|
La première ligne est celle de la reprise. C'est là que le changement de mot de passe te sera
|
|
imposé, et c'est cette connexion qui **importe ton groupe dans le realm** — sans elle, les
|
|
habilitations sur Grafana, Forgejo et Nextcloud restent câblées mais jamais exercées.
|
|
|
|
**Administrer ton realm passe désormais par le groupe** : `realm-admin` (rôle du client
|
|
`realm-management`) est attaché à `sysadmin`. La console est celle du realm —
|
|
`/admin/<realm>/console/` — pas la racine `/admin/`, qui est celle de `master`.
|
|
|
|
La dernière ligne reste le **compte de secours** (D-40). Sa portée est `master`, hors d'atteinte
|
|
du groupe : c'est voulu. Un accès de secours qui dépendrait des habilitations qu'il doit pouvoir
|
|
réparer ne serait pas un accès de secours.
|
|
|
|
### 6.3 Faire confiance à l'AC interne
|
|
|
|
Les interfaces web portent des certificats de l'autorité interne, qu'aucun navigateur ne
|
|
connaît. Récupérer la racine et **son empreinte** :
|
|
|
|
```
|
|
make ca-racine # écrit ./root_ca.crt, affiche sujet, validité, empreinte
|
|
make ca-empreinte # la même empreinte, lue SUR l'AC — le témoin de comparaison
|
|
```
|
|
|
|
**Compare les deux avant d'installer.** Ce n'est pas une formalité : installer une AC, c'est
|
|
lui donner le droit de signer *n'importe quel nom* pour ton navigateur. La comparaison est ce
|
|
qui distingue ta racine d'une racine interceptée.
|
|
|
|
```
|
|
sudo cp root_ca.crt /usr/local/share/ca-certificates/setops-root.crt
|
|
sudo update-ca-certificates
|
|
```
|
|
|
|
Firefox a son propre magasin : *Paramètres → Certificats → Autorités → Importer*.
|
|
|
|
La racine est un certificat **public** — elle n'a rien à faire dans la voûte, et tout à faire
|
|
dans le magasin de confiance de qui administre.
|
|
|
|
### 6.4 Où administrer quoi
|
|
|
|
| Ce que tu veux faire | Où | Comment |
|
|
|---|---|---|
|
|
| créer/désactiver une personne | **LDAP** (`ou=people`) | via Keycloak, ou `ldapmodify` |
|
|
| donner ou retirer un accès | **LDAP** (`ou=groups`) | ajouter/retirer du groupe |
|
|
| changer ce qu'un groupe *vaut* dans un service | **le plan** (`meta/acces.yml`) | c'est de l'infrastructure : éditer, redéployer |
|
|
|
|
La troisième ligne est la seule qui passe par Set-OPS. Les deux premières t'appartiennent
|
|
et **le dépôt ne les touchera plus jamais**.
|
|
|
|
### 6.5 Si tu te fermes dehors
|
|
|
|
Les comptes locaux de chaque service existent, sont en voûte, et leur formulaire n'est pas
|
|
annoncé (`authentification.md` §3). L'accès de secours passe par `sudo` sur l'hôte :
|
|
|
|
```
|
|
grafana-cli admin reset-admin-password
|
|
forgejo admin user change-password
|
|
occ user:resetpassword
|
|
```
|
|
|
|
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.
|
|
|
|
### 6.6 « Mot de passe oublié » — pour ne pas dépendre de toi
|
|
|
|
Un utilisateur qui oublie son mot de passe ne doit pas avoir à t'appeler : la seule issue
|
|
serait alors que tu manipules le mot de passe de quelqu'un d'autre, ce que « une identité,
|
|
une personne » cherche précisément à écarter. L'écran de connexion du realm porte donc le
|
|
lien **Forgot password?**, et Keycloak envoie lui-même le courriel.
|
|
|
|
Deux conditions, toutes deux tenues par le code :
|
|
|
|
- **Un relais SMTP.** `serveur_keycloak` le dérive du plan (`applications.postfix.hote`) —
|
|
aucun nom de machine n'est écrit nulle part. Le MTA accepte les hôtes du supernet sans
|
|
authentification (`mynetworks`) et `idm-01` porte déjà `client_smtp`, donc le flux existe.
|
|
Si le plan ne déclare pas de MTA, le rôle **refuse** plutôt que d'afficher un écran qui
|
|
promet un courriel que personne n'enverrait.
|
|
- **Une adresse sur le compte.** C'est la seule valeur de l'amorçage qui ne se dérive pas :
|
|
elle désigne une personne, donc quelque chose d'extérieur au système qu'on amorce.
|
|
`amorcage_acces_courriel` doit être déclarée, et le rôle refuse de créer le compte sans
|
|
elle. Une adresse `sysadmin@<domaine_interne>` serait un piège : elle est servie par une
|
|
boîte que tu ne peux pas encore lire.
|
|
|
|
**Attention à un reliquat.** Tant que la fédération LDAP était en `READ_ONLY`, une adresse
|
|
saisie dans la console de compte restait dans la base de Keycloak sans jamais atteindre
|
|
l'annuaire. Les deux côtés pouvaient donc afficher des adresses différentes sans que rien
|
|
ne le signale. En `WRITABLE` (le mode actuel) le problème ne se reproduit pas, mais les
|
|
comptes créés avant peuvent encore porter l'écart. Pour le voir et le réduire :
|
|
|
|
```
|
|
ldapsearch -x -H ldapi:/// -D "cn=admin,$BASE" -W -b "uid=<uid>,ou=people,$BASE" mail
|
|
# puis, si les deux diffèrent : corriger dans LDAP (source de vérité), et resynchroniser
|
|
# Identity providers → LDAP → Sync all users
|
|
```
|
|
|
|
### 6.7 La politique de mot de passe : une déclaration, deux exécutants
|
|
|
|
Les règles sont déclarées **une seule fois**, dans `resoudre_politique_mdp`, en termes
|
|
neutres. Le rôle les traduit dans les deux dialectes qui doivent les appliquer :
|
|
`pwdPolicy` pour OpenLDAP, `passwordPolicy` pour le realm. Changer la longueur minimale
|
|
se fait à un seul endroit.
|
|
|
|
Il a fallu en arriver là parce que les deux se renvoyaient la balle. LDAP portait bien les
|
|
règles — mais il ne sait que **refuser**, sans jamais dire pourquoi à l'écran. Keycloak,
|
|
lui, ne validait rien, et écrivait `userPassword` directement : l'overlay `ppolicy` ne
|
|
voyait même pas passer le changement. Mesuré le 2026-08-08 avec un compte sonde, le même
|
|
`abcd` était refusé par l'opération étendue LDAP et **accepté** par Keycloak, puis actif
|
|
pour l'authentification.
|
|
|
|
Deux réglages de la fédération tiennent la correction, et il faut les deux :
|
|
|
|
| Réglage | Ce qu'il répare |
|
|
|---|---|
|
|
| `usePasswordModifyExtendedOp` | slapd voit le changement passer, donc `ppolicy` s'applique |
|
|
| `validatePasswordPolicy` | Keycloak valide la politique du realm **avant** d'écrire |
|
|
|
|
Le second est le contrôle porteur : Keycloak se lie en rootDN, et slapd n'applique pas ses
|
|
contrôles de qualité au rootDN. L'utilisateur voit désormais *« Invalid password: minimum
|
|
length 12 »* au lieu d'un refus muet.
|
|
|
|
**`pwdMustChange` reste délibérément à `FALSE`.** Il signifie « quand un *administrateur*
|
|
pose un mot de passe, l'utilisateur devra le changer ». Comme Keycloak se lie en rootDN,
|
|
tout changement qui passe par lui *est* un changement administrateur : l'utilisateur
|
|
choisissait un nouveau mot de passe, `ppolicy` reposait aussitôt `pwdReset`, et l'écran
|
|
redemandait un changement — sans fin. Le changement forcé à la première connexion est
|
|
obtenu par l'action requise `UPDATE_PASSWORD` de Keycloak, qui, elle, se consomme.
|
|
|
|
### 6.8 Ce que tu dois changer en priorité
|
|
|
|
1. **Le mot de passe d'amorçage** — imposé dès la première connexion, tu n'as pas le
|
|
choix (§3).
|
|
2. **Les comptes de secours** générés au déploiement : ils sont en voûte, et l'auteur du
|
|
déploiement y a eu accès. Les régénérer transfère réellement le contrôle.
|
|
3. **Le mot de passe de la voûte** elle-même, si le dépôt change de mains.
|
|
|
|
### 6.9 Faire tourner un secret : l'ordre n'est pas indifférent
|
|
|
|
**Les comptes de secours des services** (`vault_grafana_admin`, `vault_forgejo_admin`,
|
|
`vault_nextcloud_admin`) se régénèrent en voûte, puis un redéploiement les applique. Les rôles
|
|
savent désormais *changer* un mot de passe existant, pas seulement le créer.
|
|
|
|
**Le compte d'administration de Keycloak est différent : il est le moyen de se changer
|
|
lui-même.** Régénérer la voûte d'abord le rendrait inapplicable — plus rien ne pourrait
|
|
s'authentifier pour poser la nouvelle valeur. L'ordre est donc inversé :
|
|
|
|
```
|
|
1. s'authentifier avec la valeur ACTUELLE
|
|
2. poser la nouvelle valeur dans Keycloak
|
|
3. vérifier que la nouvelle fonctionne
|
|
4. seulement alors, écrire la voûte
|
|
```
|
|
|
|
C'est une **procédure**, pas un redéploiement. La même contrainte vaut pour tout secret qui
|
|
est aussi la clé de son propre changement.
|
|
|
|
**`vault_openldap_admin` en est un, avec deux pièges de plus.** Il ne se change pas par
|
|
`ldappasswd` : `cn=admin` n'est pas une entrée de la base mais le **rootDN** déclaré dans
|
|
`cn=config`. Le mot de passe vit dans `olcRootPW`, et se modifie par un bind `EXTERNAL` :
|
|
|
|
```
|
|
slappasswd -h '{SSHA}' -s <nouveau> puis ldapmodify -Y EXTERNAL sur olcDatabase={1}mdb
|
|
```
|
|
|
|
Et il a **quatre consommateurs** : Keycloak (dans sa base), Dovecot, Postfix, Icinga Web 2
|
|
(fichiers de configuration). Les trois derniers suivent au redéploiement ; Keycloak stocke le
|
|
mot de passe de liaison et le masque — sa réconciliation passe donc par une empreinte, comme
|
|
les comptes de secours.
|
|
|
|
**Et une vérification n'est pas un message de succès.** `grafana-cli` annonçait
|
|
« Admin password changed successfully » en écrivant dans une base qui n'était pas celle du
|
|
serveur. Ce qui l'a démasqué est l'**état** — le champ `updated` du compte, inchangé. Après
|
|
toute rotation, s'authentifier réellement avec la nouvelle valeur.
|
|
|
|
## 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
|
|
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 permissions internes à un service.** Qui peut écrire dans quel dépôt Forgejo, qui voit
|
|
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 de chaque
|
|
application.
|
|
|
|
**Ce qui est construit, et ce qui ne l'est pas — mesuré le 2026-09-06.** Ce document s'est
|
|
terminé jusqu'à cette date sur « **Rien n'est construit** [...] le rôle d'amorçage, les
|
|
`meta/acces.yml` et la preuve restent à écrire ». C'était devenu faux au point de contredire
|
|
le §3 du même document, qui rapporte des mesures **datées du 2026-08-11** prises sur le rôle
|
|
en fonctionnement. L'état réel :
|
|
|
|
| | État |
|
|
|---|---|
|
|
| Le rôle d'amorçage | **`roles/amorcage_acces/`** — écrit, déployé, et c'est lui qui crée l'unique compte `sysadmin` du §3 |
|
|
| Les `meta/acces.yml` | **écrits pour les cinq services `web-sso`** : `serveur_forgejo`, `serveur_grafana`, `serveur_icingaweb2`, `serveur_keycloak`, `serveur_nextcloud` |
|
|
| La preuve | **toujours à écrire** — c'est la seule ligne d'origine qui tient |
|
|
|
|
La lacune restante mérite d'être nommée pour ce qu'elle est. Le §5 de
|
|
[`authentification.md`](authentification.md) le formule ainsi : *une directive qu'aucune
|
|
garde ne vérifie finit par ne plus être vraie*. `meta/acces.yml` est exactement dans ce cas
|
|
— rien ne vérifie qu'un service `web-sso` en porte un, ni que le groupe qu'il nomme existe
|
|
dans l'annuaire. **P29** garde les *positions* d'authentification ; personne ne garde encore
|
|
les *habilitations*.
|