`realm-admin` (role du client `realm-management`) est attache au GROUPE sysadmin. Administrer le realm ne passe plus par le compte local. Portee : CE realm, jamais `master` — le compte de secours reste hors d'atteinte du groupe, et c'est le sens meme d'un acces de secours (D-40). Les roles de CLIENT sont un espace de noms distinct : la declaration gagne `roles_client`. L'API attend l'UUID du client, pas son clientId — interroger par le nom rendait une erreur, la verification echouait toujours et la tache se declarait `changed` a chaque passage. Deux passages consecutifs a changed=0. La boucle de changement de mot de passe : `pwdMustChange: TRUE` signifie « quand un ADMINISTRATEUR pose un mot de passe, l'utilisateur doit le changer ». Keycloak ecrit en tant qu'administrateur — chaque changement relaye etait vu comme une reinitialisation. Incompatible par construction avec un IdP qui relaie. La contrainte est deplacee la ou l'utilisateur la voit : pwdMustChange FALSE cote annuaire, action `UPDATE_PASSWORD` posee par Keycloak. J'avais eprouve pwdReset au niveau LDAP, ou il marche, sans parcourir le chemin complet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
118 lines
6.5 KiB
YAML
118 lines
6.5 KiB
YAML
---
|
|
# Distribution Keycloak (Quarkus). Verifier/ajuster la version sur keycloak.org/downloads.
|
|
serveur_keycloak_version: "26.0.7"
|
|
serveur_keycloak_url: "https://github.com/keycloak/keycloak/releases/download/{{ serveur_keycloak_version }}/keycloak-{{ serveur_keycloak_version }}.tar.gz"
|
|
serveur_keycloak_java_paquet: "default-jre-headless"
|
|
|
|
serveur_keycloak_home: "/opt/keycloak"
|
|
serveur_keycloak_utilisateur: "keycloak"
|
|
serveur_keycloak_service: "keycloak"
|
|
|
|
# Publication (derriere serveur_nginx, TLS termine a l'edge).
|
|
# DERIVE de l'exposition que le plan declare (voir tasks/main.yml). Ce nom est celui que
|
|
# Keycloak ANNONCE dans son issuer OIDC : il doit etre exactement celui que l'edge sert et
|
|
# que le DNS resout, sinon tout client OIDC refuse le jeton — « issuer did not match ».
|
|
# La valeur ci-dessous n'est qu'un REPLI, si l'application n'expose rien.
|
|
serveur_keycloak_hostname_derive: true
|
|
serveur_keycloak_hostname: "keycloak.{{ domaine_interne }}"
|
|
|
|
# Base de donnees : resolue depuis le registre par le groupe consommateur.
|
|
serveur_keycloak_groupe: "serveur_keycloak"
|
|
# IP interne du serveur PostgreSQL (data-01, cf. nomenclature).
|
|
serveur_keycloak_db_host: "" # dérivé (FQDN) par resoudre_base au déploiement
|
|
|
|
# Secrets (Ansible Vault) — obligatoires.
|
|
serveur_keycloak_admin_user: "admin"
|
|
serveur_keycloak_admin_password: "{{ vault_keycloak_admin | default('') }}" # rempli depuis la voute (vault_keycloak_admin)
|
|
|
|
# --- Fédération LDAP : OpenLDAP source de vérité (modèle d'identité A) ---
|
|
# Keycloak lit l'annuaire (READ_ONLY) ; les users LDAP se connectent via le SSO.
|
|
# Requiert client_pki sur ce nœud (racine step_ca dans le bundle système pour LDAPS).
|
|
serveur_keycloak_ldap_federation: true
|
|
serveur_keycloak_realm: "{{ identite_realm | default('chezlepro') }}"
|
|
# Thèmes du realm (déployés depuis files/themes/). Vide = thème Keycloak par défaut.
|
|
serveur_keycloak_login_theme: ""
|
|
serveur_keycloak_account_theme: ""
|
|
# Cache des ressources de thème. true = prod (perf). false = lab (voir les tweaks sans casse-cache).
|
|
serveur_keycloak_theme_cache: true
|
|
serveur_keycloak_ldap_nom: "openldap"
|
|
# Connexion à l'annuaire (url, users_dn, bind_dn, bind_password) : fournie par le rôle
|
|
# partagé resoudre_annuaire (voir tasks/main.yml « Adopter la connexion annuaire »).
|
|
serveur_keycloak_ldap_username_attr: "uid"
|
|
serveur_keycloak_ldap_uuid_attr: "entryUUID"
|
|
serveur_keycloak_ldap_object_classes: "inetOrgPerson"
|
|
# Bundle d'AC de confiance (contient la racine step_ca, posée par client_pki) pour LDAPS.
|
|
serveur_keycloak_truststore_path: "/etc/ssl/certs/ca-certificates.crt"
|
|
|
|
# --- Clients OIDC applicatifs (enregistres dans le realm, kcadm idempotent) ---
|
|
# Chaque app qui delegue son auth a Keycloak declare ici son client confidentiel.
|
|
# Le 'secret' reference la MEME variable de voute que l'app (ex. grafana : vault_grafana_oidc).
|
|
# Ex. (a mettre en group_var d'instance, pas en defaut) :
|
|
# serveur_keycloak_clients:
|
|
# - clientId: grafana
|
|
# redirect_uris: ["https://grafana.{{ domaine_interne }}/login/generic_oauth"]
|
|
# web_origins: ["https://grafana.{{ domaine_interne }}"]
|
|
# secret: "{{ vault_grafana_oidc }}"
|
|
serveur_keycloak_clients: []
|
|
|
|
# --- RBAC OIDC (additif, idempotent) ---
|
|
# Rôles de realm à garantir (ex. ['grafana-admin', 'grafana-editor']).
|
|
serveur_keycloak_realm_roles: []
|
|
# Clients recevant le mapper « roles » (rôles de realm → claim 'roles' dans le jeton).
|
|
serveur_keycloak_role_mapper_clients: []
|
|
# Assignations rôle→utilisateur (ex. [{user: testmail, role: grafana-editor}]).
|
|
# En prod, préférer l'assignation via groupe d'annuaire ; ici, explicite pour la preuve.
|
|
serveur_keycloak_role_assignments: []
|
|
|
|
# TLS vers PostgreSQL (zero-confiance). Vide = pas de verif (compat). 'verify-full' =
|
|
# chiffre + verifie le cert serveur contre le root_ca step-ca (l'hote doit etre dans le SAN).
|
|
serveur_keycloak_db_sslmode: ""
|
|
serveur_keycloak_db_sslrootcert: "/etc/step/certs/root_ca.crt"
|
|
|
|
# --- Projection des groupes LDAP (D-65) ---------------------------------------
|
|
# LDAP porte les habilitations ; Keycloak les traduit en groupes de realm, puis en
|
|
# roles que les services lisent dans le jeton. Sans ce mapper, la chaine s'arrete
|
|
# avant le premier service et l'assignation se fait utilisateur par utilisateur —
|
|
# ce que D-66 interdit.
|
|
serveur_keycloak_groupes_ldap: true
|
|
serveur_keycloak_groupes_mapper_nom: "groupes-ldap"
|
|
|
|
# DERIVE de l'annuaire (resoudre_annuaire), jamais ecrit.
|
|
serveur_keycloak_groupes_dn: "ou=groups,{{ resoudre_annuaire_base_dn | default('') }}"
|
|
|
|
# Le schema REEL de l'annuaire Set-OPS : `serveur_openldap` cree `ou=groups`, et
|
|
# `amorcage_acces` y pose des `groupOfNames` dont les membres sont des DN.
|
|
serveur_keycloak_groupes_object_class: "groupOfNames"
|
|
serveur_keycloak_groupes_membership_attr: "member"
|
|
|
|
# Quel groupe LDAP porte quel role de realm. C'est ce qui REMPLACE l'assignation
|
|
# nominative : ajouter quelqu'un au groupe suffit, aucun deploiement n'est requis.
|
|
# Les roles doivent exister (`serveur_keycloak_realm_roles`).
|
|
serveur_keycloak_groupes_roles: []
|
|
|
|
# Le claim qui porte les groupes dans le jeton, et les clients qui le recoivent.
|
|
# Sans ce mapper de protocole, les groupes existent dans le realm mais n'atteignent
|
|
# jamais les services : Forgejo et Nextcloud liraient un claim vide.
|
|
serveur_keycloak_groupes_claim: "groups"
|
|
serveur_keycloak_groupes_mapper_clients: []
|
|
|
|
# Mode d'ecriture de la federation LDAP. TROIS valeurs possibles, et une seule tient
|
|
# avec la doctrine :
|
|
#
|
|
# READ_ONLY Keycloak lit, n'ecrit jamais. Un changement de mot de passe echoue sur
|
|
# « Federated storage is not writable » — donc `pwdReset` est un cul-de-sac :
|
|
# l'annuaire EXIGE le changement, et Keycloak ne peut pas le faire.
|
|
# UNSYNCED Keycloak ecrit dans SA base. Le mot de passe ne serait plus dans LDAP :
|
|
# Dovecot et Postfix, qui s'y lient DIRECTEMENT (D-39), continueraient de
|
|
# valider l'ancien. Une identite, deux mots de passe — exactement ce que la
|
|
# doctrine interdit.
|
|
# WRITABLE Keycloak ecrit A TRAVERS vers LDAP. L'annuaire reste la source unique ;
|
|
# Keycloak n'en est qu'un client. C'est le seul mode coherent.
|
|
#
|
|
# Constate le 2026-08-07 : READ_ONLY etait code en dur, et la premiere reprise du
|
|
# sysadmin butait dessus.
|
|
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') }}"
|