Set-OPS-Public/roles/serveur_keycloak/tasks/main.yml
Daniel Allaire 8b0eaaec0a keycloak : le claim de groupes exige les clients — troisieme defaut d'ordre
Meme motif que les roles de realm, une etape plus loin. groupes-ldap.yml
posait aussi un oidc-group-membership-mapper sur les CLIENTS, alors que
clients-oidc.yml s'execute apres. Invisible tant que les clients existaient
d'un passage precedent.

Extrait dans claim-groupes.yml, place APRES clients-oidc. J'avais d'abord
insere l'appel AVANT — le defaut meme que je corrigeais ; rattrape avant tout
deploiement.

La lecon vaut au-dela du role : un fichier de taches nomme d'apres un SUJET
(« les groupes ») rassemble des etapes aux dependances differentes, et l'ordre
qui en resulte n'est correct que par accident. Ce qui doit gouverner le
decoupage, c'est ce dont chaque etape a BESOIN, pas ce dont elle parle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 18:06:16 -04:00

248 lines
8.9 KiB
YAML

---
# Le nom d'hote de Keycloak EST son identite OIDC. Le fabriquer par convention
# (`keycloak.<domaine>`) produisait un nom que rien ne publie : le plan expose `auth`,
# l'edge sert `auth`, le DNS resout `auth` — et Keycloak s'annoncait `keycloak`. Tout
# client OIDC comparait les deux et refusait. Constate le 2026-08-07 sur oauth2-proxy :
# « issuer did not match the issuer returned by provider ».
- name: Charger les registres applications et domaines (expositions)
ansible.builtin.include_vars:
file: "{{ item }}"
loop:
- "{{ setops_plan_dir }}/applications.yml"
- "{{ setops_plan_dir }}/domaines.yml"
when: serveur_keycloak_hostname_derive | bool
- name: Dériver le nom d'hôte public depuis l'exposition déclarée
ansible.builtin.set_fact:
serveur_keycloak_hostname: >-
{{ (applications | default({})).get('keycloak', {}).get('expose', []) | first }}
when:
- serveur_keycloak_hostname_derive | bool
- ((applications | default({})).get('keycloak', {}).get('expose', []) | length) > 0
- name: Exiger le mot de passe admin Keycloak (Vault)
ansible.builtin.assert:
that:
- serveur_keycloak_admin_password | length > 0
fail_msg: "serveur_keycloak_admin_password est requis (Ansible Vault)."
- name: Resoudre la base de donnees depuis le registre (role partage)
ansible.builtin.include_role:
name: resoudre_base
vars:
resoudre_base_groupe: "{{ serveur_keycloak_groupe }}"
- name: Adopter les facts de base pour Keycloak
ansible.builtin.set_fact:
serveur_keycloak_entree: "{{ resoudre_base_entree }}"
serveur_keycloak_db_password: "{{ resoudre_base_db_password }}"
serveur_keycloak_db_host: "{{ resoudre_base_db_host }}"
no_log: true
- name: Resoudre l'annuaire (role partage)
ansible.builtin.include_role:
name: resoudre_annuaire
when: serveur_keycloak_ldap_federation | bool
- name: Adopter la connexion annuaire pour Keycloak
ansible.builtin.set_fact:
serveur_keycloak_ldap_url: "{{ resoudre_annuaire_uri }}:{{ resoudre_annuaire_port }}"
serveur_keycloak_ldap_users_dn: "{{ resoudre_annuaire_users_dn }}"
serveur_keycloak_ldap_bind_dn: "{{ resoudre_annuaire_bind_dn }}"
serveur_keycloak_ldap_bind_password: "{{ resoudre_annuaire_bind_password }}"
no_log: true
when: serveur_keycloak_ldap_federation | bool
- name: Installer le JRE
ansible.builtin.apt:
name: "{{ serveur_keycloak_java_paquet }}"
state: present
update_cache: true
cache_valid_time: 3600
- name: Creer l'utilisateur systeme keycloak
ansible.builtin.user:
name: "{{ serveur_keycloak_utilisateur }}"
system: true
home: "{{ serveur_keycloak_home }}"
create_home: false
shell: /usr/sbin/nologin
- name: Creer le repertoire d'installation
ansible.builtin.file:
path: "{{ serveur_keycloak_home }}"
state: directory
owner: "{{ serveur_keycloak_utilisateur }}"
group: "{{ serveur_keycloak_utilisateur }}"
mode: "0750"
- name: Telecharger la distribution Keycloak
ansible.builtin.get_url:
url: "{{ serveur_keycloak_url }}"
dest: "/tmp/keycloak-{{ serveur_keycloak_version }}.tar.gz"
mode: "0644"
- name: Extraire Keycloak
ansible.builtin.unarchive:
src: "/tmp/keycloak-{{ serveur_keycloak_version }}.tar.gz"
dest: "{{ serveur_keycloak_home }}"
remote_src: true
extra_opts: ["--strip-components=1"]
owner: "{{ serveur_keycloak_utilisateur }}"
group: "{{ serveur_keycloak_utilisateur }}"
creates: "{{ serveur_keycloak_home }}/bin/kc.sh"
- name: Deployer keycloak.conf (config non sensible)
ansible.builtin.template:
src: keycloak.conf.j2
dest: "{{ serveur_keycloak_home }}/conf/keycloak.conf"
owner: "{{ serveur_keycloak_utilisateur }}"
group: "{{ serveur_keycloak_utilisateur }}"
mode: "0640"
notify: Redemarrer keycloak
- name: Creer le repertoire de configuration des secrets
ansible.builtin.file:
path: /etc/keycloak
state: directory
owner: root
group: "{{ serveur_keycloak_utilisateur }}"
mode: "0750"
- name: Deployer le fichier d'environnement (secrets)
ansible.builtin.template:
src: keycloak.env.j2
dest: /etc/keycloak/keycloak.env
owner: root
group: "{{ serveur_keycloak_utilisateur }}"
mode: "0640"
no_log: true
notify: Redemarrer keycloak
- name: Construire Keycloak (une fois par version)
ansible.builtin.shell:
cmd: >-
{{ serveur_keycloak_home }}/bin/kc.sh build --db=postgres
&& touch {{ serveur_keycloak_home }}/.kc-built-{{ serveur_keycloak_version }}
creates: "{{ serveur_keycloak_home }}/.kc-built-{{ serveur_keycloak_version }}"
become: true
become_user: "{{ serveur_keycloak_utilisateur }}"
notify: Redemarrer keycloak
- name: Deployer l'unite systemd keycloak
ansible.builtin.template:
src: keycloak.service.j2
dest: /etc/systemd/system/keycloak.service
owner: root
group: root
mode: "0644"
notify: Redemarrer keycloak
- name: Deployer les themes Set-OPS (identite Alliance Boreale)
ansible.builtin.copy:
src: themes/
dest: "{{ serveur_keycloak_home }}/themes/"
owner: "{{ serveur_keycloak_utilisateur }}"
group: "{{ serveur_keycloak_utilisateur }}"
mode: "0644"
directory_mode: "0755"
notify: Redemarrer keycloak
- name: Activer et demarrer keycloak
when: not ansible_check_mode
ansible.builtin.systemd:
name: "{{ serveur_keycloak_service }}"
enabled: true
state: started
daemon_reload: true
- name: Appliquer le theme (recharger Keycloak avant la config du realm)
ansible.builtin.meta: flush_handlers
- name: Configurer la federation LDAP (realm + provider OpenLDAP)
ansible.builtin.include_tasks: federation-ldap.yml
when: serveur_keycloak_ldap_federation | bool
- name: Appliquer la politique de mot de passe et durcir la fédération
ansible.builtin.include_tasks: politique-mdp.yml
when: not ansible_check_mode
- name: Configurer le courriel du realm (« mot de passe oublié »)
ansible.builtin.include_tasks: courriel-realm.yml
when: serveur_keycloak_smtp_actif | bool
- name: Créer les rôles de realm (prérequis de la projection des groupes)
ansible.builtin.include_tasks: roles-realm.yml
when: not ansible_check_mode
- name: Projeter les groupes LDAP (mapper + roles de groupe)
ansible.builtin.include_tasks: groupes-ldap.yml
when:
- serveur_keycloak_ldap_federation | bool
- serveur_keycloak_groupes_ldap | bool
- name: Enregistrer les clients OIDC applicatifs
ansible.builtin.include_tasks: clients-oidc.yml
when: serveur_keycloak_clients | length > 0
- name: Émettre le claim de groupes dans le jeton des clients
ansible.builtin.include_tasks: claim-groupes.yml
when: not ansible_check_mode
- name: Déclarer les URI de retour après déconnexion
ansible.builtin.include_tasks: deconnexion-oidc.yml
when: not ansible_check_mode
- name: Configurer le RBAC OIDC (roles de realm + mapper + assignations)
ansible.builtin.include_tasks: rbac-oidc.yml
when: >
serveur_keycloak_realm_roles | length > 0
or serveur_keycloak_role_assignments | length > 0
- name: Definir le theme de login du realm (identite Alliance Boreale)
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 realms/{{ serveur_keycloak_realm }} --fields loginTheme 2>/dev/null \
| grep -q '"{{ serveur_keycloak_login_theme }}"'; then
echo SETOPS_OK
else
"$KC" update realms/{{ serveur_keycloak_realm }} \
-s loginTheme={{ serveur_keycloak_login_theme }} >/dev/null
echo SETOPS_CHANGED
fi
environment:
KC_ADMIN_PW: "{{ serveur_keycloak_admin_password }}"
register: serveur_keycloak_theme_res
changed_when: "'SETOPS_CHANGED' in serveur_keycloak_theme_res.stdout"
when:
- serveur_keycloak_login_theme | length > 0
- not ansible_check_mode
- name: Definir le theme de la console de compte (identite Alliance Boreale)
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 realms/{{ serveur_keycloak_realm }} --fields accountTheme 2>/dev/null \
| grep -q '"{{ serveur_keycloak_account_theme }}"'; then
echo SETOPS_OK
else
"$KC" update realms/{{ serveur_keycloak_realm }} \
-s accountTheme={{ serveur_keycloak_account_theme }} >/dev/null
echo SETOPS_CHANGED
fi
environment:
KC_ADMIN_PW: "{{ serveur_keycloak_admin_password }}"
register: serveur_keycloak_account_res
changed_when: "'SETOPS_CHANGED' in serveur_keycloak_account_res.stdout"
when:
- serveur_keycloak_account_theme | length > 0
- not ansible_check_mode