Set-OPS-Public/docs/authentification.md
Daniel Allaire 6a62f0a4c7 authentification : SSO Keycloak devant, secours par sudo, formulaire local fermé
Directive : toute authentification web passe par Keycloak, LDAP est la source
unique des comptes, chaque service garde un accès de secours par sudo sur
l'hôte. Les trois sont indissociables — la chaîne service → Keycloak → LDAP est
en série, donc sans secours une panne exclut tout le monde, y compris pour
réparer. Portée : le web seulement ; IMAP/SMTP se lient à LDAP directement et
SSH est en clé seule.

Posture <rôle>_connexion_locale, false par défaut. Le compte local existe — il
ne peut pas dépendre de Keycloak — mais son formulaire n'est plus proposé au
repos : ouvert en permanence, il contourne la politique de mot de passe, le MFA
et surtout la révocation centrale.

Vérifié auprès de l'amont, puis par rendu réel des gabarits dans les deux
postures :
- Grafana  GF_AUTH_DISABLE_LOGIN_FORM  → ferme ;
- Forgejo  ENABLE_INTERNAL_SIGNIN + ENABLE_BASIC_AUTHENTICATION → ferme, API
  Basic comprise. N'existe que depuis la v10 (ticket amont 7476) ; le rôle
  épingle 10.0.0 et un assert refuse la fermeture en deçà, car le réglage serait
  ignoré sans erreur ;
- Nextcloud hide_login_form → MASQUE seulement : ?direct=1 reste le chemin de
  secours documenté par l'amont. Écrit comme tel, sans prétendre à l'équivalence.

Défaut attrapé par le rendu : la condition Forgejo sans `| bool` n'émettait rien
dans aucune posture — une valeur en chaîne est vraie au sens Jinja, la connexion
locale serait restée ouverte en silence.

docs/authentification.md, décisions D-38 à D-41. ansible-lint (production) sans
échec, 28 preuves OK.

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

5.1 KiB

Authentification : Keycloak devant, LDAP dessous, sudo en secours

Directive d'architecture du 2026-08-03. Trois règles, décidées ensemble et volontairement indissociables — chacune crée le problème que la suivante résout.

  1. Toute authentification web passe par Keycloak. Aucun service ne tient son propre répertoire de comptes.
  2. LDAP est la source de vérité unique des comptes d'un tenant. Keycloak le fédère ; les protocoles qui ne parlent pas OIDC s'y lient directement.
  3. Chaque service garde un accès de secours, atteint par sudo sur l'hôte.

1. Pourquoi les trois vont ensemble

La chaîne est en série : service → Keycloak → LDAP. C'est ce qui donne « une identité, un mot de passe » — et c'est aussi trois points de panne alignés. Si LDAP tombe, plus personne n'entre nulle part, y compris pour réparer.

La règle 3 n'est donc pas une entorse au SSO : c'est ce qui rend les deux premières tenables. Sans elle, la panne d'un maillon devient une exclusion totale.

2. Portée : le web, et seulement le web

Protocole Chemin d'authentification Pourquoi
HTTP(S) — interfaces humaines Keycloak (OIDC natif, ou oauth2-proxy devant) c'est là que la directive s'applique
IMAP / SMTP LDAP direct (Dovecot, Postfix) ces protocoles ne parlent pas OIDC ; le flux est prouvé de bout en bout
SSH clé publique (PasswordAuthentication no) pas de mot de passe du tout, donc rien à fédérer
PostgreSQL, Redis secrets applicatifs en voûte comptes de service, pas d'humains

Ce qui est interdit partout, c'est qu'un service tienne son propre répertoire d'humains. Le chemin varie ; la source ne varie pas.

3. La posture retenue : la porte de secours n'est pas annoncée

Le compte local de chaque service existe — il ne peut pas dépendre de Keycloak, sinon il tomberait avec lui. Mais son formulaire de connexion n'est pas proposé au repos.

Ce n'est pas une préférence esthétique. Un formulaire local ouvert en permanence :

  • contourne la politique de mot de passe et le MFA ;
  • contourne surtout la révocation centrale — désactiver quelqu'un dans LDAP laisserait son compte local valide, sans que rien ne le signale ;
  • offre une cible de bourrage d'identifiants sur admin, en continu, pour un usage qui devrait être exceptionnel.

Le coût de la fermeture est nul depuis qu'on a tranché que sudo suffit : sudo est le mécanisme de réouverture.

Ce que chaque service sait vraiment faire

Vérifié auprès de l'amont le 2026-08-03, puis par rendu réel des gabarits dans les deux postures — pas seulement lu.

Service Réglage Effet réel Secours par sudo
Grafana GF_AUTH_DISABLE_LOGIN_FORM=true ferme le formulaire grafana-cli admin reset-admin-password
Forgejo ≥ 10 ENABLE_INTERNAL_SIGNIN=false + ENABLE_BASIC_AUTHENTICATION=false ferme la connexion interne et l'API en Basic forgejo admin user change-password
Nextcloud hide_login_form=true masque seulement occ user:resetpassword, ou …/login?direct=1

Nextcloud est une exception, et il faut la dire. hide_login_form masque le formulaire ; …/login?direct=1 y accède encore, et l'amont le documente comme voulu — c'est ainsi qu'un administrateur entre. La protection est donc de ne plus l'annoncer, pas de l'interdire. Le présenter comme équivalent à Grafana ou Forgejo donnerait un faux confort.

Le réglage s'appelle <rôle>_connexion_locale dans les trois rôles, et vaut false par défaut. Le passer à true rouvre la porte, explicitement.

Garde de version. ENABLE_INTERNAL_SIGNIN n'existe que depuis Forgejo v10 (suivi amont, ticket 7476 : « This option was added to Forgejo v10 »). Sur une version antérieure il serait ignoré sans erreur — le rôle croirait avoir fermé la porte. Un assert refuse donc connexion_locale: false sous 10.0.0 plutôt que de laisser croire.

4. La chaîne de secours

Trois maillons, aucun ne dépendant d'une porte web ouverte :

1. SSO            Keycloak → LDAP                     ← la voie normale
2. sudo via SSH   occ / grafana-cli / forgejo admin   ← Keycloak ou LDAP en panne
3. console Proxmox de la VM                           ← SSH inaccessible

Un accès de secours qu'on ne sait pas emprunter n'existe pas : les commandes exactes sont dans le tableau ci-dessus, et les mots de passe locaux vivent dans la voûte unique de l'instance.

5. Ce qui reste à faire

  • Prometheus et Loki exposent une interface sans SSO. oauth2-proxy est déjà éprouvé devant Icinga Web 2 : le patron existe, il reste à l'appliquer.
  • Aucune preuve ne garde cette directive. C'est le même risque que les intégrations universelles avant leur inversion : une règle qu'aucune garde ne vérifie finit par ne plus être vraie. Le remède symétrique serait qu'un rôle déclare sa position (web-sso / ldap-direct / sans-auth-humaine, plus son accès de secours) et qu'une preuve refuse une interface humaine sans SSO ni secours déclaré.