resoudre_idp : le nom invente etait dans QUATRE roles
`forge-01` a echoue sur une URL de decouverte pointant `https://keycloak.<domaine>` — le nom que rien ne publie. J'avais corrige exactement ca dans `serveur_oauth2_proxy` quelques heures plus tot, en croyant regler un cas isole. Il etait dans quatre roles : forgejo, grafana, nextcloud, oauth2-proxy. Chacun fabriquait le meme nom par la meme convention. Une cinquieme correction a la main aurait diverge comme les quatre autres. `roles/resoudre_idp` lit l'exposition declaree au plan et rend hote, base et discovery. Les roles n'en gardent qu'un REPLI nomme, jamais la valeur de travail. Verifie en base sur forge-01 : discovery = auth.chezlepro.internal, GroupClaimName = groups, AdminGroup = sysadmin. Meme lecon que `resoudre_annuaire` hier : corriger la valeur la ou elle echoue ne corrige que la. Ce sont les copies silencieuses qui coutent la journee suivante. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
a08c61bb4e
commit
6699935dc7
10 changed files with 139 additions and 3 deletions
29
CHANGELOG.md
29
CHANGELOG.md
|
|
@ -2,6 +2,35 @@
|
|||
|
||||
## 2026-08-06 — le chemin nord-sud devient dérivable
|
||||
|
||||
### `resoudre_idp` — le nom inventé était dans **quatre** rôles
|
||||
|
||||
`forge-01` a échoué sur `serveur_forgejo_oidc_discovery`, qui pointait
|
||||
`https://keycloak.<domaine>` — le nom que rien ne publie. J'avais corrigé exactement ça dans
|
||||
`serveur_oauth2_proxy` quelques heures plus tôt, en croyant régler un cas isolé.
|
||||
|
||||
Il était en fait dans **quatre** rôles : forgejo, grafana, nextcloud, oauth2-proxy. Chacun
|
||||
fabriquait le même nom par la même convention, et chacun aurait échoué au même endroit —
|
||||
`oauth2-proxy` l'a fait le premier parce qu'il a été déployé le premier.
|
||||
|
||||
Une cinquième copie corrigée à la main aurait divergé comme les quatre autres. D'où
|
||||
`roles/resoudre_idp` : il lit l'exposition déclarée au plan et rend `resoudre_idp_hote`,
|
||||
`resoudre_idp_base`, `resoudre_idp_discovery`. Les trois rôles restants l'appellent ; leur
|
||||
défaut ne garde plus qu'un **repli** nommé, jamais la valeur de travail.
|
||||
|
||||
Vérifié en base sur `forge-01` :
|
||||
|
||||
```
|
||||
OpenIDConnectAutoDiscoveryURL : https://auth.chezlepro.internal/realms/chezlepro/…
|
||||
GroupClaimName : 'groups' AdminGroup : 'sysadmin'
|
||||
```
|
||||
|
||||
Le câblage par groupe et l'URL correcte, sur un service déployé pour la première fois.
|
||||
|
||||
**La leçon est la même que pour `resoudre_annuaire` hier**, et elle mérite d'être dite deux
|
||||
fois : corriger la valeur là où elle échoue ne corrige que là. Ce sont les autres copies,
|
||||
silencieuses, qui coûtent la journée suivante.
|
||||
|
||||
|
||||
### Forgejo et Nextcloud câblés — avant d'être déployés
|
||||
|
||||
Les deux services n'existaient pas encore : les câbler maintenant vaut mieux que les corriger
|
||||
|
|
|
|||
23
roles/resoudre_idp/README.md
Normal file
23
roles/resoudre_idp/README.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# resoudre_idp — l'URL publique du fournisseur d'identite
|
||||
|
||||
Resout `auth.<domaine>` depuis l'exposition que le plan declare, au lieu de fabriquer
|
||||
`keycloak.<domaine>` par convention.
|
||||
|
||||
## Pourquoi
|
||||
|
||||
Quatre roles construisaient le nom a la main. Aucun ne le publiait : le DNS resout
|
||||
`auth`, nginx sert `auth`, et Keycloak s'annonce sous `auth`. Un client qui interroge
|
||||
`keycloak.<domaine>` echoue — ou recoit un issuer qui ne correspond pas au sien
|
||||
(« issuer did not match the issuer returned by provider »).
|
||||
|
||||
Corrige une premiere fois dans `serveur_oauth2_proxy`, puis retrouve a l'identique
|
||||
dans trois autres roles. Une convention de nommage se contredit ; une declaration se
|
||||
corrige.
|
||||
|
||||
## Sorties
|
||||
|
||||
| Fait | Exemple |
|
||||
|---|---|
|
||||
| `resoudre_idp_hote` | `auth.chezlepro.internal` |
|
||||
| `resoudre_idp_base` | `https://auth.chezlepro.internal/realms/chezlepro` |
|
||||
| `resoudre_idp_discovery` | `…/.well-known/openid-configuration` |
|
||||
5
roles/resoudre_idp/defaults/main.yml
Normal file
5
roles/resoudre_idp/defaults/main.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
# Application du plan qui EST le fournisseur d'identite.
|
||||
resoudre_idp_app: "keycloak"
|
||||
# Realm applicatif — le meme pour tous les consommateurs d'une instance.
|
||||
resoudre_idp_realm: "{{ identite_realm | default('chezlepro') }}"
|
||||
42
roles/resoudre_idp/tasks/main.yml
Normal file
42
roles/resoudre_idp/tasks/main.yml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
# Role utilitaire (pas un groupe deployable) : resout l'URL PUBLIQUE du fournisseur
|
||||
# d'identite depuis l'exposition que le plan declare.
|
||||
#
|
||||
# Sorties (facts) :
|
||||
# resoudre_idp_hote — auth.<domaine> (le FQDN publie, pas un nom fabrique)
|
||||
# resoudre_idp_base — https://<hote>/realms/<realm>
|
||||
# resoudre_idp_discovery — .../.well-known/openid-configuration
|
||||
#
|
||||
# POURQUOI CE ROLE. Quatre roles fabriquaient `https://keycloak.<domaine>` par
|
||||
# convention de nommage — un nom que RIEN ne publie : le plan expose Keycloak sous
|
||||
# `auth.<domaine>`, et c'est ce nom que le DNS resout, que nginx sert et que
|
||||
# Keycloak annonce dans son issuer. Un client OIDC qui interroge l'autre nom
|
||||
# echoue, ou recoit un issuer qui ne correspond pas au sien.
|
||||
#
|
||||
# Corrige une premiere fois dans `serveur_oauth2_proxy` le 2026-08-07, puis
|
||||
# retrouve a l'identique dans forgejo, grafana et nextcloud. Une quatrieme copie
|
||||
# aurait diverge comme les trois premieres : d'ou ce role.
|
||||
- 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"
|
||||
|
||||
- name: Exiger que l'IdP declare une exposition
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ((applications | default({})).get(resoudre_idp_app, {}).get('expose', []) | length) > 0
|
||||
fail_msg: >-
|
||||
L'application `{{ resoudre_idp_app }}` n'expose aucun FQDN dans
|
||||
instance/plan/applications.yml. Un client OIDC ne peut pas joindre un
|
||||
fournisseur qui n'est publie nulle part.
|
||||
|
||||
- name: Deriver l'URL publique du fournisseur d'identite
|
||||
ansible.builtin.set_fact:
|
||||
resoudre_idp_hote: >-
|
||||
{{ (applications[resoudre_idp_app].expose | first) }}
|
||||
resoudre_idp_base: >-
|
||||
https://{{ (applications[resoudre_idp_app].expose | first) }}/realms/{{ resoudre_idp_realm }}
|
||||
resoudre_idp_discovery: >-
|
||||
https://{{ (applications[resoudre_idp_app].expose | first) }}/realms/{{ resoudre_idp_realm }}/.well-known/openid-configuration
|
||||
|
|
@ -60,7 +60,12 @@ serveur_forgejo_oidc_nom: "{{ organisation | default('organisation') | lower | r
|
|||
serveur_forgejo_oidc_client_id: "forgejo"
|
||||
serveur_forgejo_oidc_client_secret: "{{ vault_forgejo_oidc | default('') }}" # voûte (vault_forgejo_oidc)
|
||||
serveur_forgejo_oidc_realm: "{{ identite_realm | default('chezlepro') }}"
|
||||
serveur_forgejo_oidc_discovery: "https://keycloak.{{ domaine_interne }}/realms/{{ serveur_forgejo_oidc_realm }}/.well-known/openid-configuration"
|
||||
# DERIVE de l'exposition declaree au plan (role `resoudre_idp`). La valeur
|
||||
# ci-dessous n'est qu'un REPLI : `keycloak.<domaine>` n'est publie nulle part.
|
||||
serveur_forgejo_oidc_repli: >-
|
||||
https://keycloak.{{ domaine_interne }}/realms/{{ serveur_forgejo_oidc_realm }}/.well-known/openid-configuration
|
||||
serveur_forgejo_oidc_discovery: >-
|
||||
{{ resoudre_idp_discovery | default(serveur_forgejo_oidc_repli) }}
|
||||
|
||||
# TLS vers PostgreSQL (zero-confiance). 'disable' = compat ; 'verify-full' = chiffre + verifie
|
||||
# le cert serveur contre le root_ca step-ca (via PGSSLROOTCERT dans l'unite systemd).
|
||||
|
|
|
|||
|
|
@ -1,4 +1,12 @@
|
|||
---
|
||||
|
||||
# L'URL PUBLIQUE de l'IdP se derive de l'exposition declaree au plan, elle ne se
|
||||
# fabrique pas : `keycloak.<domaine>` n'est publie nulle part (voir resoudre_idp).
|
||||
- name: Resoudre le fournisseur d'identite (role partage)
|
||||
ansible.builtin.include_role:
|
||||
name: resoudre_idp
|
||||
vars:
|
||||
resoudre_idp_realm: "{{ serveur_forgejo_oidc_realm }}"
|
||||
- name: Refuser de fermer la connexion locale sur un Forgejo anterieur a la v10
|
||||
# `ENABLE_INTERNAL_SIGNIN` a ete ajoute en v10 (suivi amont, issue 7476). Sur une
|
||||
# version anterieure il est ignore EN SILENCE : le role croirait avoir ferme la porte
|
||||
|
|
|
|||
|
|
@ -36,7 +36,11 @@ serveur_grafana_oidc_nom: "{{ organisation | default('Organisation') }}"
|
|||
serveur_grafana_oidc_client_id: "grafana"
|
||||
serveur_grafana_oidc_client_secret: "{{ vault_grafana_oidc | default('') }}" # voûte (vault_grafana_oidc)
|
||||
serveur_grafana_oidc_realm: "{{ identite_realm | default('chezlepro') }}"
|
||||
serveur_grafana_oidc_base: "https://keycloak.{{ domaine_interne }}/realms/{{ serveur_grafana_oidc_realm }}/protocol/openid-connect"
|
||||
# DERIVE de l'exposition declaree au plan (role `resoudre_idp`) ; repli seulement.
|
||||
serveur_grafana_oidc_repli: >-
|
||||
https://keycloak.{{ domaine_interne }}/realms/{{ serveur_grafana_oidc_realm }}
|
||||
serveur_grafana_oidc_base: >-
|
||||
{{ (resoudre_idp_base | default(serveur_grafana_oidc_repli)) }}/protocol/openid-connect
|
||||
serveur_grafana_oidc_scopes: "openid email profile"
|
||||
# RBAC via SSO : mappe le claim 'roles' (rôles de realm Keycloak) vers le niveau Grafana.
|
||||
# Défaut : grafana-admin→Admin, grafana-editor→Editor, sinon Viewer. Vider pour désactiver.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,12 @@
|
|||
---
|
||||
|
||||
# L'URL PUBLIQUE de l'IdP se derive de l'exposition declaree au plan, elle ne se
|
||||
# fabrique pas : `keycloak.<domaine>` n'est publie nulle part (voir resoudre_idp).
|
||||
- name: Resoudre le fournisseur d'identite (role partage)
|
||||
ansible.builtin.include_role:
|
||||
name: resoudre_idp
|
||||
vars:
|
||||
resoudre_idp_realm: "{{ serveur_grafana_oidc_realm }}"
|
||||
- name: Exiger le mot de passe admin Grafana (Vault)
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
|
|
|
|||
|
|
@ -62,7 +62,11 @@ serveur_nextcloud_oidc_nom: "{{ organisation | default('Organisation') }}"
|
|||
serveur_nextcloud_oidc_client_id: "nextcloud"
|
||||
serveur_nextcloud_oidc_client_secret: "{{ vault_nextcloud_oidc | default('') }}"
|
||||
serveur_nextcloud_oidc_realm: "{{ identite_realm | default('chezlepro') }}"
|
||||
serveur_nextcloud_oidc_discovery: "https://keycloak.{{ domaine_interne }}/realms/{{ serveur_nextcloud_oidc_realm }}/.well-known/openid-configuration"
|
||||
# DERIVE de l'exposition declaree au plan (role `resoudre_idp`) ; repli seulement.
|
||||
serveur_nextcloud_oidc_repli: >-
|
||||
https://keycloak.{{ domaine_interne }}/realms/{{ serveur_nextcloud_oidc_realm }}/.well-known/openid-configuration
|
||||
serveur_nextcloud_oidc_discovery: >-
|
||||
{{ resoudre_idp_discovery | default(serveur_nextcloud_oidc_repli) }}
|
||||
|
||||
# --- Collabora Online (WOPI) — app richdocuments ---
|
||||
serveur_nextcloud_office_actif: true
|
||||
|
|
|
|||
|
|
@ -1,4 +1,12 @@
|
|||
---
|
||||
|
||||
# L'URL PUBLIQUE de l'IdP se derive de l'exposition declaree au plan, elle ne se
|
||||
# fabrique pas : `keycloak.<domaine>` n'est publie nulle part (voir resoudre_idp).
|
||||
- name: Resoudre le fournisseur d'identite (role partage)
|
||||
ansible.builtin.include_role:
|
||||
name: resoudre_idp
|
||||
vars:
|
||||
resoudre_idp_realm: "{{ serveur_nextcloud_oidc_realm }}"
|
||||
- name: Exiger les secrets Nextcloud (Vault)
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
|
|
|
|||
Loading…
Reference in a new issue