rotation : vault_openldap_admin, quatre consommateurs et deux pieges
`ldappasswd` ne peut pas le changer : `cn=admin` n'est pas une entree de la base mais le rootDN declare dans cn=config. Le mot de passe vit dans `olcRootPW` et se modifie par un bind EXTERNAL. L'echec etait sans degat — l'ancien fonctionnait toujours, verifie avant de continuer. Keycloak stocke le mot de passe de LIAISON dans sa base et le masque : la reconciliation d'hier couvrait l'URL, les DN et le mode, pas `bindCredential`. Tourner le secret aurait coupe Keycloak de l'annuaire. Comme la valeur est masquee, la reconciliation passe par une empreinte. Verifie consommateur par consommateur : synchro LDAP de Keycloak (qui prouve la liaison), carte LDAP de Postfix, Dovecot actif. Les trois rejouent a changed=0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
35602546eb
commit
4642ffec0a
4 changed files with 55 additions and 1 deletions
23
CHANGELOG.md
23
CHANGELOG.md
|
|
@ -2,6 +2,29 @@
|
||||||
|
|
||||||
## 2026-08-06 — le chemin nord-sud devient dérivable
|
## 2026-08-06 — le chemin nord-sud devient dérivable
|
||||||
|
|
||||||
|
### `vault_openldap_admin` — quatre consommateurs et deux pièges
|
||||||
|
|
||||||
|
Le secret le plus délicat de la liste : Keycloak, Dovecot, Postfix et Icinga Web 2 s'y lient
|
||||||
|
tous.
|
||||||
|
|
||||||
|
**Premier piège : `ldappasswd` ne peut pas le changer.** `cn=admin` n'est pas une entrée de
|
||||||
|
la base mais le **rootDN** déclaré dans `cn=config` — la commande répond « No such object ».
|
||||||
|
Le mot de passe vit dans `olcRootPW` et se modifie par un bind `EXTERNAL`. L'échec était sans
|
||||||
|
dégât : l'ancien fonctionnait toujours, vérifié avant de continuer.
|
||||||
|
|
||||||
|
**Second piège : Keycloak stocke le mot de passe de liaison dans sa base, et le masque.** La
|
||||||
|
réconciliation ajoutée hier couvrait l'URL, les DN et le mode — pas `bindCredential`. Tourner
|
||||||
|
le secret aurait coupé Keycloak de l'annuaire, et plus personne n'aurait pu se connecter.
|
||||||
|
Comme on ne peut pas comparer une valeur masquée, la réconciliation passe par une **empreinte**
|
||||||
|
— même mécanisme que les comptes de secours.
|
||||||
|
|
||||||
|
**Vérifié, consommateur par consommateur** : synchronisation LDAP de Keycloak (qui prouve la
|
||||||
|
liaison), carte LDAP de Postfix, Dovecot actif. Les trois rejouent à `changed=0`.
|
||||||
|
|
||||||
|
Six secrets tournés depuis hier ; chacun a d'abord demandé de **construire la capacité de le
|
||||||
|
faire**. C'est le motif de fond de ces deux jours : le dépôt savait créer, pas changer.
|
||||||
|
|
||||||
|
|
||||||
### `vault_forgejo_oidc` — le secret exposé ne vaut plus rien
|
### `vault_forgejo_oidc` — le secret exposé ne vaut plus rien
|
||||||
|
|
||||||
Il avait fui dans une sortie de diagnostic. Le faire tourner a d'abord demandé de rendre la
|
Il avait fui dans une sortie de diagnostic. Le faire tourner a d'abord demandé de rendre la
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,20 @@ s'authentifier pour poser la nouvelle valeur. L'ordre est donc inversé :
|
||||||
```
|
```
|
||||||
|
|
||||||
C'est une **procédure**, pas un redéploiement. La même contrainte vaut pour tout secret qui
|
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.
|
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
|
**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
|
« Admin password changed successfully » en écrivant dans une base qui n'était pas celle du
|
||||||
|
|
|
||||||
|
|
@ -116,3 +116,7 @@ serveur_keycloak_ldap_edit_mode: "WRITABLE"
|
||||||
# Compte d'amorcage dont le changement de mot de passe doit etre EXPLICITE dans
|
# Compte d'amorcage dont le changement de mot de passe doit etre EXPLICITE dans
|
||||||
# Keycloak. Vide = aucun alignement. Voir roles/amorcage_acces (D-67).
|
# Keycloak. Vide = aucun alignement. Voir roles/amorcage_acces (D-67).
|
||||||
serveur_keycloak_amorcage_uid: "{{ amorcage_acces_uid | default('sysadmin') }}"
|
serveur_keycloak_amorcage_uid: "{{ amorcage_acces_uid | default('sysadmin') }}"
|
||||||
|
|
||||||
|
# Empreinte du mot de passe de LIAISON LDAP applique — Keycloak le masque, on ne
|
||||||
|
# peut donc pas le comparer. Permet sa rotation. Voir tasks/federation-ldap.yml.
|
||||||
|
serveur_keycloak_marqueur_bind: "/etc/keycloak/.setops-bind-sha256"
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,20 @@
|
||||||
# `|| true` en fin de chaine : avec `pipefail`, un grep sans correspondance
|
# `|| true` en fin de chaine : avec `pipefail`, un grep sans correspondance
|
||||||
# tuerait le script entier. Et l'extraction ne s'ancre pas sur `$` — la ligne
|
# tuerait le script entier. Et l'extraction ne s'ancre pas sur `$` — la ligne
|
||||||
# se termine par un guillemet, pas par la valeur.
|
# se termine par un guillemet, pas par la valeur.
|
||||||
|
# Le mot de passe de LIAISON ne se compare pas : Keycloak le masque (`****`).
|
||||||
|
# On memorise donc son empreinte, comme pour les comptes de secours. Sans
|
||||||
|
# cela, faire tourner `vault_openldap_admin` couperait Keycloak de
|
||||||
|
# l'annuaire — la federation garderait l'ancienne valeur, et plus personne
|
||||||
|
# ne pourrait se connecter.
|
||||||
|
EMPREINTE_VOULUE="{{ serveur_keycloak_ldap_bind_password | hash('sha256') }}"
|
||||||
|
EMPREINTE_POSEE=$(cat {{ serveur_keycloak_marqueur_bind }} 2>/dev/null || true)
|
||||||
|
if [ "$EMPREINTE_POSEE" != "$EMPREINTE_VOULUE" ]; then
|
||||||
|
"$KC" update components/"$FEDID" -r {{ serveur_keycloak_realm }} \
|
||||||
|
-s "config.bindCredential=[\"$LDAP_BIND_PW\"]" >/dev/null
|
||||||
|
printf '%s\n' "$EMPREINTE_VOULUE" > {{ serveur_keycloak_marqueur_bind }}
|
||||||
|
chmod 600 {{ serveur_keycloak_marqueur_bind }}
|
||||||
|
CHANGED=1
|
||||||
|
fi
|
||||||
MODE_ACTUEL=$("$KC" get components/"$FEDID" -r {{ serveur_keycloak_realm }} 2>/dev/null \
|
MODE_ACTUEL=$("$KC" get components/"$FEDID" -r {{ serveur_keycloak_realm }} 2>/dev/null \
|
||||||
| sed -n 's/.*"editMode" : \[ "\([A-Z_]*\)".*/\1/p' | head -1 || true)
|
| sed -n 's/.*"editMode" : \[ "\([A-Z_]*\)".*/\1/p' | head -1 || true)
|
||||||
if [ "$URL_ACTUELLE" != "{{ serveur_keycloak_ldap_url }}" ] \
|
if [ "$URL_ACTUELLE" != "{{ serveur_keycloak_ldap_url }}" ] \
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue