2026-08-07 13:27:00 -04:00
|
|
|
# Accès et habilitations : Set-OPS amorce, le sysadmin gouverne
|
2026-08-07 13:05:48 -04:00
|
|
|
|
|
|
|
|
> **Directive d'architecture du 2026-08-07.** L'authentification dit *qui tu es*
|
2026-08-07 13:27:00 -04:00
|
|
|
> (`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 ».
|
2026-08-07 13:05:48 -04:00
|
|
|
|
|
|
|
|
## 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.
|
|
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
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.
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
## 2. Deux régimes, et la frontière entre eux
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
C'est la décision principale, et elle **contredit délibérément la doctrine du dépôt**.
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
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.
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
| | 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 ».
|
|
|
|
|
|
|
|
|
|
## 4. Où vivent les habilitations : LDAP, pas Keycloak
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
**Les groupes LDAP sont la source unique.** Keycloak les *projette* en rôles pour le web ;
|
|
|
|
|
les services non-OIDC les lisent directement.
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
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.
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
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.
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
## 5. Un service nomme un groupe, jamais une personne
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
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` :
|
2026-08-07 13:05:48 -04:00
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
acces:
|
2026-08-07 13:27:00 -04:00
|
|
|
- groupe: sysadmin # groupe LDAP
|
2026-08-07 13:05:48 -04:00
|
|
|
accorde: Admin # ce que ça vaut DANS ce service
|
|
|
|
|
raison: >-
|
2026-08-07 13:27:00 -04:00
|
|
|
Administration : sources de données, tableaux de bord, utilisateurs.
|
2026-08-07 13:05:48 -04:00
|
|
|
```
|
|
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
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.
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
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.
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
## 6. Prendre la main — le runbook
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
Ce qui suit est destiné au sysadmin le jour de la livraison. **C'est la partie utile de ce
|
|
|
|
|
document.**
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
### 6.1 Récupérer le mot de passe d'amorçage
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
```
|
|
|
|
|
ansible-vault view instance/inventories/principal/group_vars/all/vault.yml \
|
|
|
|
|
| grep vault_sysadmin_amorcage
|
|
|
|
|
```
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:52:00 -04:00
|
|
|
**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.
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
> 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.
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 17:48:43 -04:00
|
|
|
### 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 |
|
2026-08-07 19:47:10 -04:00
|
|
|
| **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` |
|
2026-08-07 17:48:43 -04:00
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
2026-08-07 19:47:10 -04:00
|
|
|
**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.
|
2026-08-07 17:48:43 -04:00
|
|
|
|
|
|
|
|
### 6.3 Faire confiance à l'AC interne
|
2026-08-07 17:26:35 -04:00
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
2026-08-07 17:48:43 -04:00
|
|
|
### 6.4 Où administrer quoi
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
| 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 |
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
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**.
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 17:48:43 -04:00
|
|
|
### 6.5 Si tu te fermes dehors
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
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.
|
|
|
|
|
|
2026-08-08 06:08:06 -04:00
|
|
|
### 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 Ce que tu dois changer en priorité
|
2026-08-07 13:27:00 -04:00
|
|
|
|
2026-08-07 13:52:00 -04:00
|
|
|
1. **Le mot de passe d'amorçage** — imposé dès la première connexion, tu n'as pas le
|
|
|
|
|
choix (§3).
|
2026-08-07 13:27:00 -04:00
|
|
|
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.
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-08 06:08:06 -04:00
|
|
|
### 6.8 Faire tourner un secret : l'ordre n'est pas indifférent
|
2026-08-07 21:16:51 -04:00
|
|
|
|
|
|
|
|
**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
|
2026-08-08 05:46:38 -04:00
|
|
|
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.
|
2026-08-07 21:16:51 -04:00
|
|
|
|
|
|
|
|
**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.
|
|
|
|
|
|
2026-08-07 13:05:48 -04:00
|
|
|
## 7. Ce que ce document ne couvre pas
|
|
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
**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.
|
|
|
|
|
|
2026-08-07 13:05:48 -04:00
|
|
|
**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
|
2026-08-07 13:27:00 -04:00
|
|
|
service et non à une personne.
|
2026-08-07 13:05:48 -04:00
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
**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
|
2026-08-07 13:05:48 -04:00
|
|
|
application.
|
|
|
|
|
|
2026-08-07 13:27:00 -04:00
|
|
|
**Rien n'est construit.** Ce document fixe la direction ; le rôle d'amorçage, les
|
|
|
|
|
`meta/acces.yml` et la preuve restent à écrire.
|