Set-OPS-Public/roles/serveur_keycloak/defaults/main.yml

179 lines
9.6 KiB
YAML
Raw Normal View History

---
# 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') }}"
# Empreinte du mot de passe de LIAISON LDAP applique — Keycloak le masque, on ne
# peut donc pas le comparer. Permet sa rotation. Voir tasks/federation-ldap.yml.
serveur_keycloak_marqueur_bind: "/etc/keycloak/.setops-bind-sha256"
# --- Courriel du realm : « mot de passe oublie » ------------------------------
# Sans SMTP, `resetPasswordAllowed` ne sert a rien — Keycloak n'a aucun moyen
# d'envoyer le lien. Et sans « mot de passe oublie », chaque oubli passe par
# l'exploitant, qui manipule alors le mot de passe de quelqu'un d'autre : ce que
# « une identite, une personne » cherche precisement a eviter.
#
# Le relais est le MTA du tenant, DERIVE du plan (`applications.postfix.hote`) :
# il accepte les hotes du supernet sans authentification (`mynetworks`), et
# `idm-01` porte deja `client_smtp` — le flux existe.
serveur_keycloak_smtp_actif: true
serveur_keycloak_smtp_app: "postfix"
serveur_keycloak_smtp_port: 25
serveur_keycloak_smtp_starttls: true
serveur_keycloak_smtp_expediteur: "identite@{{ domaine_interne }}"
serveur_keycloak_smtp_nom_expediteur: "{{ organisation | default('Set-OPS') }}"
# Repli : utilise seulement si le plan ne declare pas d'application `postfix`.
serveur_keycloak_smtp_hote: ""
# « Mot de passe oublie » sur l'ecran de connexion. Exige le SMTP ci-dessus et une
# adresse `mail` sur le compte — sans elle, Keycloak n'a nulle part ou ecrire.
serveur_keycloak_reset_mot_de_passe: true
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
# --- Durcissement de la federation LDAP ---------------------------------------
# Forme de l'API (chaque valeur est une LISTE de chaines) : on ecrit le dialecte
# reel plutot que de le fabriquer en Jinja.
#
# `usePasswordModifyExtendedOp` — sans lui, Keycloak ecrit l'attribut `userPassword`
# a la main et l'overlay `ppolicy` de slapd ne voit rien passer.
# `validatePasswordPolicy` — fait valider la politique DU REALM avant l'ecriture.
# C'est le controle porteur : Keycloak se lie en rootDN, et slapd n'applique pas
# ses controles de qualite au rootDN. Les deux cles ensemble, pas l'une ou l'autre.
# `syncRegistrations` — sans lui, un compte cree dans Keycloak n'atteint JAMAIS
# l'annuaire (mesure du 2026-08-08 : `POST users` -> 201, rien dans `ou=people`).
# Il aurait un acces web, aucune boite aux lettres, et serait invisible du modele
# de groupes : Postfix et Dovecot lisent LDAP, pas Keycloak.
# `trustEmail` — l'adresse vient de l'annuaire, qui est la source de verite ; la
# faire re-verifier par courriel demanderait a l'utilisateur de confirmer ce que
# l'exploitant a deja etabli.
# Les delais — un annuaire qui PEND, plutot qu'il refuse, bloque sinon les fils de
# Keycloak sans limite.
serveur_keycloak_ldap_durcissement:
usePasswordModifyExtendedOp: ["true"]
validatePasswordPolicy: ["true"]
syncRegistrations: ["true"]
trustEmail: ["true"]
connectionTimeout: ["5000"]
readTimeout: ["10000"]
# Mappeurs d'attributs a reconcilier : nom du mappeur -> attribut LDAP. Voir
# tasks/attributs-ldap.yml pour ce que le defaut de Keycloak faisait de travers.
serveur_keycloak_ldap_attributs:
first name: "givenName"
last name: "sn"
email: "mail"
username: "uid"