diff --git a/CHANGELOG.md b/CHANGELOG.md index 23def1a..a0a10bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,29 @@ ## 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 Il avait fui dans une sortie de diagnostic. Le faire tourner a d'abord demandé de rendre la diff --git a/docs/autorisation.md b/docs/autorisation.md index 5061474..7a7ba5f 100644 --- a/docs/autorisation.md +++ b/docs/autorisation.md @@ -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 -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 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 diff --git a/roles/serveur_keycloak/defaults/main.yml b/roles/serveur_keycloak/defaults/main.yml index adc47dd..e4955e5 100644 --- a/roles/serveur_keycloak/defaults/main.yml +++ b/roles/serveur_keycloak/defaults/main.yml @@ -116,3 +116,7 @@ serveur_keycloak_ldap_edit_mode: "WRITABLE" # Compte d'amorcage dont le changement de mot de passe doit etre EXPLICITE dans # Keycloak. Vide = aucun alignement. Voir roles/amorcage_acces (D-67). 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" diff --git a/roles/serveur_keycloak/tasks/federation-ldap.yml b/roles/serveur_keycloak/tasks/federation-ldap.yml index d0432aa..12764a7 100644 --- a/roles/serveur_keycloak/tasks/federation-ldap.yml +++ b/roles/serveur_keycloak/tasks/federation-ldap.yml @@ -42,6 +42,20 @@ # `|| 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 # 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 \ | sed -n 's/.*"editMode" : \[ "\([A-Z_]*\)".*/\1/p' | head -1 || true) if [ "$URL_ACTUELLE" != "{{ serveur_keycloak_ldap_url }}" ] \