Set-OPS-Public/roles/serveur_keycloak/tasks/politique-mdp.yml

107 lines
4 KiB
YAML
Raw Normal View History

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
- name: Activer le journal des évènements
ansible.builtin.include_tasks: journalisation.yml