identite : une declaration de politique de mot de passe, deux executants
Quatre defauts mesures dans l'integration Keycloak/LDAP, meme famille : une
valeur declaree d'un cote, consommee de l'autre, rien qui verifie la jonction.
1. Aucune regle ne s'appliquait sur le chemin d'un vrai utilisateur. Sonde :
« abcd » refuse par l'operation etendue LDAP, accepte par Keycloak (204),
puis actif pour l'authentification. Keycloak ecrivait userPassword en
direct (ppolicy aveugle) et le realm n'avait aucune passwordPolicy.
2. ldap_entry ne fait que CREER : la politique etait figee a sa creation. Le
depot disait pwdMustChange TRUE, le serveur FALSE — une reconstruction
from-zero aurait ressuscite la boucle du 2026-08-07. ldap_attrs state=exact
reconcilie la politique et l'overlay (DN lu, pas devine).
3. syncRegistrations absent : un compte cree dans Keycloak n'atteignait jamais
ou=people — acces web, aucune boite, invisible du modele de groupes.
4. Le prenom pointait sur cn (nom complet) : « Administrateur systeme systeme ».
Ajoute roles/resoudre_politique_mdp : LA declaration, traduite en pwdPolicy,
passwordPolicy et anti-force-brute. Les deux roles la consomment sans la
redeclarer.
usePasswordModifyExtendedOp ET validatePasswordPolicy : la seconde est
porteuse, Keycloak se liant en rootDN et slapd n'appliquant pas ses controles
de qualite au rootDN. La premiere seule aurait paru juste sans tenir.
Verification : abcd -> 400 « minimum length 12 » et absent de LDAP ; mot de
passe conforme -> 204 puis ldapwhoami accepte ; POST users -> 201 ET present
dans ou=people. Second passage des deux playbooks : changed=0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 06:28:10 -04:00
|
|
|
---
|
|
|
|
|
# Projette LA declaration unique (`resoudre_politique_mdp`) dans le realm, et durcit
|
|
|
|
|
# la federation pour que l'annuaire soit consulte au lieu d'etre contourne.
|
|
|
|
|
#
|
|
|
|
|
# Sans cela, les regles n'existaient QUE cote LDAP — et LDAP ne sait que refuser,
|
|
|
|
|
# sans jamais dire pourquoi a l'ecran. Pire : Keycloak ecrivait `userPassword`
|
|
|
|
|
# directement, donc l'overlay `ppolicy` n'interceptait meme pas. Mesure du
|
|
|
|
|
# 2026-08-08 : `abcd` refuse par l'operation etendue LDAP, accepte par Keycloak,
|
|
|
|
|
# puis actif pour l'authentification.
|
|
|
|
|
#
|
|
|
|
|
# La conformite se teste partout ici de la meme facon : fusionner l'attendu dans le
|
|
|
|
|
# reel ne change rien => c'est deja conforme. Ca evite d'enumerer les champs deux fois.
|
|
|
|
|
|
|
|
|
|
- name: Résoudre la politique de mot de passe (déclaration unique)
|
|
|
|
|
ansible.builtin.include_role:
|
|
|
|
|
name: resoudre_politique_mdp
|
|
|
|
|
|
|
|
|
|
- name: Obtenir un jeton d'administration
|
|
|
|
|
ansible.builtin.uri:
|
|
|
|
|
url: "http://localhost:8080/realms/master/protocol/openid-connect/token"
|
|
|
|
|
method: POST
|
|
|
|
|
body_format: form-urlencoded
|
|
|
|
|
body:
|
|
|
|
|
grant_type: password
|
|
|
|
|
client_id: admin-cli
|
|
|
|
|
username: "{{ serveur_keycloak_admin_user }}"
|
|
|
|
|
password: "{{ serveur_keycloak_admin_password }}"
|
|
|
|
|
register: serveur_keycloak_pol_jeton
|
|
|
|
|
no_log: true
|
|
|
|
|
|
|
|
|
|
- name: Lire le realm
|
|
|
|
|
ansible.builtin.uri:
|
|
|
|
|
url: "http://localhost:8080/admin/realms/{{ serveur_keycloak_realm }}"
|
|
|
|
|
headers:
|
|
|
|
|
Authorization: "Bearer {{ serveur_keycloak_pol_jeton.json.access_token }}"
|
|
|
|
|
register: serveur_keycloak_pol_realm
|
|
|
|
|
no_log: true
|
|
|
|
|
|
|
|
|
|
- name: Composer l'état attendu du realm
|
|
|
|
|
ansible.builtin.set_fact:
|
|
|
|
|
serveur_keycloak_realm_attendu: >-
|
|
|
|
|
{{ {'passwordPolicy': resoudre_politique_mdp_keycloak}
|
|
|
|
|
| combine(resoudre_politique_mdp_brute) }}
|
|
|
|
|
|
|
|
|
|
- name: Appliquer la politique de mot de passe au realm
|
|
|
|
|
ansible.builtin.uri:
|
|
|
|
|
url: "http://localhost:8080/admin/realms/{{ serveur_keycloak_realm }}"
|
|
|
|
|
method: PUT
|
|
|
|
|
status_code: [204]
|
|
|
|
|
headers:
|
|
|
|
|
Authorization: "Bearer {{ serveur_keycloak_pol_jeton.json.access_token }}"
|
|
|
|
|
body_format: json
|
|
|
|
|
body: "{{ serveur_keycloak_realm_attendu }}"
|
|
|
|
|
no_log: true
|
|
|
|
|
changed_when: true
|
|
|
|
|
when: >-
|
|
|
|
|
(serveur_keycloak_pol_realm.json | combine(serveur_keycloak_realm_attendu))
|
|
|
|
|
!= serveur_keycloak_pol_realm.json
|
|
|
|
|
|
|
|
|
|
# --- Durcissement de la federation --------------------------------------------
|
|
|
|
|
# Voir `serveur_keycloak_ldap_durcissement` (defaults) pour ce que chaque cle repare.
|
|
|
|
|
- name: Lire la fédération LDAP
|
|
|
|
|
ansible.builtin.uri:
|
|
|
|
|
url: >-
|
|
|
|
|
http://localhost:8080/admin/realms/{{ serveur_keycloak_realm
|
|
|
|
|
}}/components?type=org.keycloak.storage.UserStorageProvider
|
|
|
|
|
headers:
|
|
|
|
|
Authorization: "Bearer {{ serveur_keycloak_pol_jeton.json.access_token }}"
|
|
|
|
|
register: serveur_keycloak_pol_fed
|
|
|
|
|
no_log: true
|
|
|
|
|
|
|
|
|
|
- name: Exiger une fédération LDAP en place
|
|
|
|
|
ansible.builtin.assert:
|
|
|
|
|
that:
|
|
|
|
|
- (serveur_keycloak_pol_fed.json | length) == 1
|
|
|
|
|
fail_msg: >-
|
|
|
|
|
{{ serveur_keycloak_pol_fed.json | length }} fournisseur(s) de stockage
|
|
|
|
|
d'utilisateurs dans le realme « {{ serveur_keycloak_realm }} » — il en faut
|
|
|
|
|
exactement un. Durcir le mauvais serait pire que ne rien durcir.
|
|
|
|
|
|
|
|
|
|
- name: Durcir la fédération LDAP
|
|
|
|
|
ansible.builtin.uri:
|
|
|
|
|
url: >-
|
|
|
|
|
http://localhost:8080/admin/realms/{{ serveur_keycloak_realm
|
|
|
|
|
}}/components/{{ serveur_keycloak_pol_fed.json[0].id }}
|
|
|
|
|
method: PUT
|
|
|
|
|
status_code: [204]
|
|
|
|
|
headers:
|
|
|
|
|
Authorization: "Bearer {{ serveur_keycloak_pol_jeton.json.access_token }}"
|
|
|
|
|
body_format: json
|
|
|
|
|
body: >-
|
|
|
|
|
{{ serveur_keycloak_pol_fed.json[0] | combine({
|
|
|
|
|
'config': serveur_keycloak_pol_fed.json[0].config
|
|
|
|
|
| combine(serveur_keycloak_ldap_durcissement)
|
|
|
|
|
}) }}
|
|
|
|
|
no_log: true
|
|
|
|
|
changed_when: true
|
|
|
|
|
when: >-
|
|
|
|
|
(serveur_keycloak_pol_fed.json[0].config | combine(serveur_keycloak_ldap_durcissement))
|
|
|
|
|
!= serveur_keycloak_pol_fed.json[0].config
|
|
|
|
|
|
|
|
|
|
- name: Reconcilier les mappeurs d'attributs
|
|
|
|
|
ansible.builtin.include_tasks: attributs-ldap.yml
|
2026-08-08 10:57:42 -04:00
|
|
|
|
|
|
|
|
- name: Activer le journal des évènements
|
|
|
|
|
ansible.builtin.include_tasks: journalisation.yml
|