--- # RBAC OIDC : rôles de realm + mapper de rôles sur les clients concernés + assignations. # Additif et idempotent (create-si-absent, kcadm à chaud — pas de restart Keycloak). # Permet à une app (ex. Grafana) de mapper un rôle du realm vers son niveau de droit. - name: Assurer les roles de realm (kcadm, idempotent) ansible.builtin.shell: executable: /bin/bash cmd: | set -euo pipefail KC={{ serveur_keycloak_home }}/bin/kcadm.sh "$KC" config credentials --server http://localhost:8080 --realm master \ --user {{ serveur_keycloak_admin_user }} --password "$KC_ADMIN_PW" >/dev/null if "$KC" get roles/{{ item }} -r {{ serveur_keycloak_realm }} >/dev/null 2>&1; then echo SETOPS_OK else "$KC" create roles -r {{ serveur_keycloak_realm }} -s name={{ item }} >/dev/null echo SETOPS_CHANGED fi environment: KC_ADMIN_PW: "{{ serveur_keycloak_admin_password }}" loop: "{{ serveur_keycloak_realm_roles }}" register: serveur_keycloak_role_reg changed_when: "'SETOPS_CHANGED' in serveur_keycloak_role_reg.stdout" no_log: true when: - not ansible_check_mode - serveur_keycloak_realm_roles | length > 0 - name: Assurer le mapper de roles de realm sur les clients (claim 'roles') ansible.builtin.shell: executable: /bin/bash cmd: | set -euo pipefail KC={{ serveur_keycloak_home }}/bin/kcadm.sh "$KC" config credentials --server http://localhost:8080 --realm master \ --user {{ serveur_keycloak_admin_user }} --password "$KC_ADMIN_PW" >/dev/null CID=$("$KC" get clients -r {{ serveur_keycloak_realm }} -q clientId={{ item }} 2>/dev/null \ | grep -oP '"id"\s*:\s*"\K[^"]+' | head -1) if [ -z "$CID" ]; then echo "SETOPS_OK client absent"; exit 0; fi if "$KC" get clients/$CID/protocol-mappers/models -r {{ serveur_keycloak_realm }} 2>/dev/null \ | grep -q '"realm-roles"'; then echo SETOPS_OK else "$KC" create clients/$CID/protocol-mappers/models -r {{ serveur_keycloak_realm }} \ -s name=realm-roles -s protocol=openid-connect \ -s protocolMapper=oidc-usermodel-realm-role-mapper \ -s 'config."claim.name"=roles' \ -s 'config."jsonType.label"=String' \ -s 'config."multivalued"=true' \ -s 'config."id.token.claim"=true' \ -s 'config."access.token.claim"=true' \ -s 'config."userinfo.token.claim"=true' >/dev/null echo SETOPS_CHANGED fi environment: KC_ADMIN_PW: "{{ serveur_keycloak_admin_password }}" loop: "{{ serveur_keycloak_role_mapper_clients }}" register: serveur_keycloak_mapper_reg changed_when: "'SETOPS_CHANGED' in serveur_keycloak_mapper_reg.stdout" no_log: true when: - not ansible_check_mode - serveur_keycloak_role_mapper_clients | length > 0 - name: Assigner les roles de realm aux utilisateurs (add-roles idempotent) ansible.builtin.shell: executable: /bin/bash cmd: | set -euo pipefail KC={{ serveur_keycloak_home }}/bin/kcadm.sh "$KC" config credentials --server http://localhost:8080 --realm master \ --user {{ serveur_keycloak_admin_user }} --password "$KC_ADMIN_PW" >/dev/null # L'utilisateur doit exister dans le realm (Keycloak fédère LDAP à la demande). # from-zero : l'annuaire peut être vide -> on n'échoue pas ; l'assignation # s'appliquera quand l'utilisateur existera (synchro / 1re connexion). if ! "$KC" get users -r {{ serveur_keycloak_realm }} -q username={{ item.user }} --fields username 2>/dev/null \ | grep -q '"{{ item.user }}"'; then echo SETOPS_SKIP exit 0 fi if "$KC" get-roles -r {{ serveur_keycloak_realm }} --uusername {{ item.user }} 2>/dev/null \ | grep -q '"{{ item.role }}"'; then echo SETOPS_OK else "$KC" add-roles -r {{ serveur_keycloak_realm }} --uusername {{ item.user }} --rolename {{ item.role }} >/dev/null echo SETOPS_CHANGED fi environment: KC_ADMIN_PW: "{{ serveur_keycloak_admin_password }}" loop: "{{ serveur_keycloak_role_assignments }}" loop_control: label: "{{ item.user }} -> {{ item.role }}" register: serveur_keycloak_assign_reg changed_when: "'SETOPS_CHANGED' in serveur_keycloak_assign_reg.stdout" no_log: true when: - not ansible_check_mode - serveur_keycloak_role_assignments | length > 0