L'infrastructure NYM-IT héberge plusieurs services internes : Nextcloud (collaboration), GLPI (gestion de parc et ticketing), Portainer, UrBackup et Vaultwarden. Avant ce projet, chaque application maintenait sa propre connexion LDAP vers l'Active Directory, ce qui posait plusieurs problèmes concrets :
La solution retenue est Keycloak 26.5.2, une plateforme IAM open source maintenue par Red Hat, déployée comme point central d'authentification. Contrairement à Azure AD (SaaS), Keycloak permet un hébergement on-premise : les données restent dans l'infrastructure.
IdP centralisé — image quay.io, mode production, SSL direct
Conteneurisation avec healthcheck pg_isready et depends_on
Virtual hosts HTTPS pour GLPI et le portail SSO (port 443)
SAML pour Nextcloud et GLPI — OIDC pour le portail d'accès
Active Directory NYM-IT.local — compte Sync_keycloack READ_ONLY
Debian 13 (VM Proxmox) — réseau Docker 192.168.20.0/24
Keycloak est placé au centre de tous les flux d'authentification. Il est accessible directement
sur le port 8449 en HTTPS (sans passer par Nginx) pour éviter les problèmes
de redirections SAML liés aux en-têtes X-Forwarded-*.
Les applications (GLPI, Nextcloud, portail) sont elles accessibles via Nginx.
AD (NYM-IT.local)
└── Fédération LDAP (READ_ONLY)
└── Keycloak IdP (port 8449, HTTPS direct)
├── SAML 2.0 ──► Nextcloud (nextcloud.nym-it.local:443)
├── SAML 2.0 ──► GLPI (glpi.nym-it.local:443 via Nginx)
└── OIDC ──► Portail SSO (portal.nym-it.local:443 via Nginx)
Plan d'adressage : contrôleur de domaine 192.168.1.1, SRV-NYMIT 192.168.20.2,
Nextcloud VM 192.168.1.205. Les services Docker sont isolés sur le réseau 192.168.20.0/24.
Keycloak est démarré en mode production avec terminaison SSL directe via des certificats montés en volume. PostgreSQL 17 dispose d'un healthcheck pg_isready pour garantir que la base est prête avant le démarrage de Keycloak.
Variable critique : KC_HOSTNAME doit correspondre exactement au FQDN utilisé par les navigateurs — une valeur incorrecte provoque des boucles de redirection infinies (ERR_TOO_MANY_REDIRECTS). En environnement lab, KC_HOSTNAME_STRICT=false est également nécessaire.
Un compte de service dédié Sync_keycloack est créé dans l'OU Connecteurs avec des droits READ_ONLY. Le mode READ_ONLY garantit que l'AD reste la source de vérité unique : toute modification (mot de passe, groupe) dans l'AD est automatiquement reflétée dans Keycloak.
L'attribut username est configuré sur sAMAccountName (plutôt que UserPrincipalName) pour obtenir des logins courts — ex : yanis.rjiba au lieu de yanis.rjiba@NYM-IT.local. La synchronisation initiale a importé 14 utilisateurs depuis l'AD. 8 mappers LDAP assurent la correspondance des attributs (username, email, prénom, nom, groupes, contrôles MSAD).
Nextcloud utilise le plugin natif user_saml. Un client SAML est créé dans Keycloak avec le champ IDP-Initiated SSO URL name à nextcloud. L'option multi-authentification est activée pour conserver un accès administrateur local en cas de panne du SSO.
Le certificat auto-signé de Keycloak est copié dans le trust store du conteneur Nextcloud via docker cp + update-ca-certificates pour valider la signature des assertions SAML.
GLPI 11 ne dispose pas de support SAML natif mature. Le plugin samlSSO 1.2.5 est installé manuellement dans /var/glpi/marketplace/ (chemin non standard dans l'image Docker). Particularités critiques non documentées :
https://glpi.nym-it.local/)role_list et saml_organization doivent être supprimés pour éviter les attributs en doublonglpi_plugin_samlsso_loginstates toutes les minutes pour éviter les erreurs de race conditionUn portail d'accès unifié en HTML/CSS/JavaScript statique est développé et servi par Nginx. Il utilise l'Authorization Code Flow OIDC pour authentifier l'utilisateur auprès de Keycloak, puis propose des liens IdP-initiated SAML vers Nextcloud et GLPI. Le token d'accès JWT est stocké en sessionStorage (suppression automatique à la fermeture de l'onglet).
Un script bash vérifie la disponibilité de Keycloak toutes les 5 minutes via l'endpoint /health/ready. En cas de non-réponse, le conteneur est redémarré automatiquement (self-healing). Portainer assure le monitoring visuel des conteneurs (CPU, mémoire ~600 MB pour Keycloak, logs JVM).
STATUS=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 10 "$KEYCLOAK_URL")
if [ "$STATUS" != "200" ]; then docker restart keycloak_app; fi
19 incidents documentés au total, répartis sur le déploiement, la fédération LDAP, les intégrations SAML et le portail.
Keycloak rejetait les accès via IP/localhost. Résolution : KC_HOSTNAME_STRICT=false
Logins au format UPN (user@NYM-IT.local). Résolution : passer à sAMAccountName + resync
Caractères parasites lors du copier-coller depuis le metadata XML. Toujours extraire depuis Realm settings > Keys
Client ID sans slash final → client_not_found. Spécificité non documentée de GLPI.