icingaweb2 : habilitation par groupe d'annuaire, plus par liste d'uid

Le dernier `porte_par: liste-uid` du catalogue. `roles.ini` porte desormais
`groups = "sysadmin"` ; `serveur_icingaweb2_admins` devient un repli de
depannage, VIDE par defaut.

Le mode SSO complique le montage : les membres d'un `groupOfNames` sont des DN,
alors que `REMOTE_USER` est une chaine. Un backend LDAP supplementaire est
declare — jamais utilise pour authentifier — uniquement pour que `groups.ini`
resolve le nom vers son DN. Sans ce pont, l'habilitation par groupe est
impossible en SSO.

NON PROUVE : la resolution REMOTE_USER -> DN -> appartenance est interne a
Icinga Web 2 ; seule une connexion reelle par le SSO la confirmera.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-08-07 19:54:41 -04:00
parent 1b16e67cdc
commit df8ffb68d6
7 changed files with 71 additions and 7 deletions

View file

@ -2,6 +2,26 @@
## 2026-08-06 — le chemin nord-sud devient dérivable
### Icinga Web 2 cesse de nommer des personnes
Le dernier `porte_par: liste-uid` du catalogue. `serveur_icingaweb2_admins` valait un `uid`
en dur ; `roles.ini` porte désormais `groups = "sysadmin"`, et `serveur_icingaweb2_admins`
devient un repli de dépannage, **vide par défaut**.
**Le mode SSO complique le montage, et il faut le dire.** Les membres d'un `groupOfNames`
sont des **DN** ; en `auth: external`, le nom d'utilisateur vient de `REMOTE_USER` — une
chaîne, pas un DN. Un backend LDAP supplémentaire est donc déclaré dans
`authentication.ini` : **jamais utilisé pour authentifier** (l'externe répond en premier),
uniquement pour que `groups.ini` résolve le nom vers son DN.
Sans ce pont, l'habilitation par groupe est impossible en SSO — et il faudrait continuer à
nommer des personnes.
**Ce que je n'ai pas pu vérifier.** La configuration est déployée et cohérente, mais la
résolution `REMOTE_USER → DN → appartenance` est interne à Icinga Web 2 : seule une connexion
réelle par le SSO la prouve. Je ne la déclare donc pas prouvée.
### Administrer le realm par appartenance — le dernier `porte_par: aucun`
`realm-admin` (rôle du client `realm-management`) est attaché au **groupe** `sysadmin`.

View file

@ -49,7 +49,17 @@ serveur_icingaweb2_ldap_user_attr: "uid"
# En attendant, le défaut suit l'`uid` d'amorçage plutôt qu'un compte de test :
# `testmail` était codé en dur et n'existe dans aucune instance — le seul
# administrateur déclaré était donc un utilisateur inexistant (2026-08-07).
serveur_icingaweb2_admins: "{{ amorcage_acces_uid | default('sysadmin') }}"
# Repli seulement, et VIDE par defaut : l'habilitation passe par le GROUPE
# (`serveur_icingaweb2_groupe_admin`). Le renseigner nomme des personnes, ce que
# D-66 interdit — a n'utiliser que pour un depannage.
serveur_icingaweb2_admins: ""
# Habilitation par groupe d'annuaire. Le schema est celui que `amorcage_acces` pose :
# des `groupOfNames` dont les membres sont des DN.
serveur_icingaweb2_groupe_admin: "{{ amorcage_acces_groupe | default('sysadmin') }}"
serveur_icingaweb2_groupe_class: "groupOfNames"
serveur_icingaweb2_groupe_membre_attr: "member"
serveur_icingaweb2_groupes_dn: "ou=groups,{{ resoudre_annuaire_base_dn | default('') }}"
# Backend d'authentification : "ldap" (direct) ou "external" (utilisateur fourni par une
# passerelle SSO devant, ex. oauth2-proxy → Keycloak). En "external", nginx doit poser REMOTE_USER.

View file

@ -3,11 +3,15 @@
acces:
- groupe: sysadmin
accorde: Administrateur
# /!\ `liste-uid` NOMME DES PERSONNES (`serveur_icingaweb2_admins`), ce que
# D-66 interdit : revoquer quelqu'un demande alors un deploiement, et le
# service porte une liste qui vieillit sans que rien ne le signale.
# Icinga Web 2 sait lire un groupe d'annuaire (backend LDAP de type `group`) :
# c'est vers cela qu'il faut aller. Constate le 2026-08-07.
porte_par: liste-uid
# Backend de GROUPES LDAP (`groups.ini`) + `groups =` dans roles.ini.
#
# En mode SSO (`auth: external`) le nom d'utilisateur vient de REMOTE_USER,
# alors que les membres d'un `groupOfNames` sont des DN : un backend LDAP
# supplementaire est declare — jamais utilise pour authentifier — uniquement
# pour resoudre le nom vers son DN. Sans lui, l'habilitation par groupe est
# impossible en SSO et il faudrait nommer des personnes.
#
# `serveur_icingaweb2_admins` reste comme repli de depannage, VIDE par defaut.
porte_par: groupe-annuaire
raison: >-
Acces complet a la supervision : hotes, services, commandes.

View file

@ -52,6 +52,7 @@
- { s: config.ini.j2, d: config.ini }
- { s: resources.ini.j2, d: resources.ini, secret: true }
- { s: authentication.ini.j2, d: authentication.ini }
- { s: groups.ini.j2, d: groups.ini }
- { s: roles.ini.j2, d: roles.ini }
- { s: icingadb-config.ini.j2, d: modules/icingadb/config.ini }
- { s: icingadb-redis.ini.j2, d: modules/icingadb/redis.ini }

View file

@ -3,6 +3,18 @@
; SSO : l'utilisateur est fourni par la passerelle (oauth2-proxy → Keycloak) via REMOTE_USER.
[icingaweb2]
backend = "external"
; Backend LDAP declare mais JAMAIS utilise pour authentifier : l'externe repond en
; premier. Il sert au backend de GROUPES, qui doit resoudre un nom d'utilisateur vers
; son DN — les membres d'un `groupOfNames` sont des DN, pas des uid.
; Sans lui, l'habilitation par groupe est impossible en mode SSO, et il faudrait
; nommer des personnes (ce que D-66 interdit).
[ldap-annuaire]
backend = "ldap"
resource = "icingaweb_ldap"
user_class = "{{ serveur_icingaweb2_ldap_user_class }}"
user_name_attribute = "{{ serveur_icingaweb2_ldap_user_attr }}"
base_dn = "{{ serveur_icingaweb2_ldap_users_dn }}"
{% else %}
[icingaweb2]
backend = "ldap"

View file

@ -0,0 +1,12 @@
; Géré par Set-OPS (rôle serveur_icingaweb2). Ne pas éditer à la main.
; Habilitation par GROUPE d'annuaire (D-66) : ajouter quelqu'un a
; `{{ serveur_icingaweb2_groupe_admin }}` dans LDAP lui ouvre la supervision, sans
; deploiement et sans que personne ne soit nomme ici.
[annuaire]
backend = "ldap"
resource = "icingaweb_ldap"
user_backend = "{{ 'ldap-annuaire' if serveur_icingaweb2_auth == 'external' else 'icingaweb2' }}"
group_class = "{{ serveur_icingaweb2_groupe_class }}"
group_name_attribute = "cn"
group_member_attribute = "{{ serveur_icingaweb2_groupe_membre_attr }}"
base_dn = "{{ serveur_icingaweb2_groupes_dn }}"

View file

@ -1,4 +1,9 @@
; Géré par Set-OPS (rôle serveur_icingaweb2). Ne pas éditer à la main.
[Administrators]
; Le GROUPE, jamais des personnes (D-66) : revoquer quelqu'un ne demande alors
; aucun deploiement. `serveur_icingaweb2_admins` reste un repli, vide par defaut.
groups = "{{ serveur_icingaweb2_groupe_admin }}"
{% if serveur_icingaweb2_admins | length > 0 %}
users = "{{ serveur_icingaweb2_admins }}"
{% endif %}
permissions = "*"