Howto Keycloak

Keycloak est un Logiciel Libre permettant l’authentification unique (SSO) d’utilisateurs à diverses applications. Il supporte notamment le rotocole OpenID.

Installation

Pré-requis :

  • installer PostgreSQL et avoir /home en exec
  • installer Nginx et certbot

On identifie la dernière version de Keycloak sur https://github.com/keycloak/keycloak/releases afin de l’utiliser ci-dessous.

# apt install openjdk-17-jre unzip

# useradd -r -m keycloak
# chmod 700 /home/keycloak
# su - keycloak

$ keycloak_release=26.5.6
$ keycloak_zip=keycloak-${keycloak_release}.zip
$ wget https://github.com/keycloak/keycloak/releases/download/${keycloak_release}/keycloak-${keycloak_release}.zip
$ unzip $keycloak_zip
$ keycloak_folder=${keycloak_zip%".zip"}
$ ln -s "${keycloak_folder}" keycloak

$./keycloak/bin/kc.sh --version
Keycloak 26.5.6
JVM: 17.0.18 (Debian OpenJDK 64-Bit Server VM 17.0.18+8-Debian-1deb12u1)
OS: Linux 6.1.0-42-cloud-amd64 amd64

On crée une configuration minimale dans /home/keycloak/keycloak/conf/keycloak.conf :o

# su - keycloak
$ cp keycloak/conf/keycloak.conf keycloak/conf/keycloak.conf.ori
$ vim keycloak/conf/keycloak.conf

hostname=https://sso.example.com
http-enabled=true
proxy-headers=xforwarded

PostgreSQL

On crée la configuration pour PostgreSQL :

# su - postgres
$ createuser -P keycloak
$ createdb -O keycloak keycloak

Et l’on met la configuration pour PostgreSQL dans /home/keycloak/keycloak/conf/keycloak.conf

# su - keycloak
$ vim keycloak/conf/keycloak.conf

db=postgres
db-username=keycloak
db-password=PASSWORD
db-url=jdbc:postgresql://127.0.0.1/keycloak

On peut alors lancer Keycloak manuellement ce qui va créer les tables / données dans PostgreSQL :

$ ./keycloak/bin/kc.sh start

On peut aussi se connecter sur http://127.0.0.1:8080/ pour créer un identifiant admin et stocker les informations de façon sécurisée.

Une fois l’identifiant créé, on ne pourra plus se connecter sans passer par Nginx, donc on peut couper Keycloak.

Nginx

Il faut ensuite configurer Nginx et certbot, voici une configuration minimale :

server {
  server_name sso.example.com
  listen 80;
  include /etc/nginx/snippets/letsencrypt.conf;
  }
  location / {
    return 301 https://$host$request_uri;
  }
}

server {
  server_name sso.example.com;
  listen 443 ssl http2;

  ssl_certificate /etc/letsencrypt/live/sso.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/sso.example.com/privkey.pem;

  location /  {
      proxy_pass http://127.0.0.1:8080;
      proxy_redirect off;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $remote_addr;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Forwarded-Port 443;
  }
}

Unité Systemd

On crée une unité systemd pour lancer Keycloak :

# cat /etc/systemd/system/keycloak.service

[Unit]
Description=Keycloak server
After=network-online.target
Wants=network-online.target

[Service]
User=keycloak
Group=keycloak
ExecStart=/home/keycloak/keycloak/bin/kc.sh start

# Disable timeout logic and wait until process is stopped
TimeoutStopSec=0

# SIGTERM signal is used to stop the Java process
KillSignal=SIGTERM

# Send the signal only to the JVM rather than its control group
KillMode=process

# Java process is never killed
SendSIGKILL=no

# When a JVM receives a SIGTERM signal it exits with code 143
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

On peut ainsi lancer Keycloak :

# systemctl start keycloak
# systemctl status keycloak
● keycloak.service - Keycloak server
     Loaded: loaded (/etc/systemd/system/keycloak.service; disabled; preset: enabled)
     Active: active (running) since Mon 2026-02-02 11:51:11 CET; 11h ago
   Main PID: 27409 (kc.sh)
      Tasks: 56 (limit: 2328)
     Memory: 510.7M
        CPU: 1min 10.926s
     CGroup: /system.slice/keycloak.service
             ├─27409 /bin/sh /home/keycloak/keycloak/bin/kc.sh start
             └─27481 java -Djava.util.concurrent.ForkJoinPool.common.threadFactory=io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.err.encoding=UTF-8 -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF>

Et l’on peut se connecter avec l’identifiant préalablement créé sur https://sso.example.com/admin/ afin de créer un « realm » et les paramètres souhaités.

Configuration

Le fichier de configuration est /home/keycloak/keycloak/conf/keycloak.conf.

On peut voir la configuration en cours via :

# su - keycloak

$ ./keycloak/bin/kc.sh show-config

La documentation complète de la configuration d’une instance en production : https://www.keycloak.org/server/configuration

Liste exhaustive des options de configuration : https://www.keycloak.org/server/all-config

Voici un exemple de configuration :

# Bdd
db=postgres
db-username=keycloak
db-password=A_CHANGER
db-url=127.0.0.1
                                
# HTTPS
https-certificate-file=/home/keycloak/fullchain.pem
https-certificate-key-file=/home/keycloak/privatekey.key

# Proxy
proxy=reencrypt

# Port
https-port=8443

# Logs
log=console,file
log-level=info
log-file=/var/log/keycloak.log

# Observabilité et Monitoring                                                                   
health-enabled=true
metrics-enabled=true

Hostname

En production, un client doit se connecter en utilisant le hostname indiqué dans la configuration :

# Hostname for the Keycloak server.
hostname=test.example.org

On peut exposer la console d’administration sur un hostname différent de celui utilisé pour les clients :

# Hostname for the Keycloak server.
hostname-admin=adm-test.example.org

Attention : nous avons observé que mettre l’interface d’administration sur un domaine différent peut contrarier le fonctionnement de l’impersonation

reverse proxy

On peut configurer le trafic entre le reverse proxy (Nginx dans notre cas) et Keycloak de différentes façons :

  • edge : Terminaison SSL au niveau du proxy et communication avec keycloak en HTTP
  • reencrypt : La terminaison SSL se fait au niveau du proxy inverse ET au niveau de keycloak, chacun ont une clé et un certificat (différent).
  • passthrough : Terminaison SSL/TLS au niveau de Keycloak uniquement, le trafic HTTPS est forwardé par le proxy, le proxy n’a pas connaissance du contenu du trafic

Logging

Par défaut les logs ne sont pas stocker dans un fichier, on peut l’activer et indiquer un fichier (par défaut dans data/log/keycloak.log dans le dossier de Keycloak) :

log=console,file
log-level=debug
log-file=/var/log/keycloak.log

Mise à jour

Pour mettre à jour on va rejouer l’installation avec la version désirée

$ keycloak_release=26.5.6
$ keycloak_zip=keycloak-${keycloak_release}.zip
$ wget https://github.com/keycloak/keycloak/releases/download/${keycloak_release}/keycloak-${keycloak_release}.zip
$ unzip $keycloak_zip
$ keycloak_folder=${keycloak_zip%".zip"}

On vérifie les différences entre les fichiers de configuration :

$ diff keycloak/conf/keycloak.conf.ori ${keycloak_folder}/conf/keycloak.conf

On copie le fichier original, puis on copie le fichier en intégrant les éventuelles différences :

$ cp ${keycloak_folder}/conf/keycloak.conf ${keycloak_folder}/conf/keycloak.conf.ori
$ cp keycloak/conf/keycloak.conf ${keycloak_folder}/conf/keycloak.conf
$ vim ${keycloak_folder}/conf/keycloak.conf

Puis on fait pointer le lien symbolique vers la nouvelle version et on restart :

$ rm keycloak
$ ln -s "${keycloak_folder}" keycloak

# systemctl restart keycloak

start-dev

Si l’on est pas en production, on peut lancer Keycloak en mode « dev » ainsi :

$ ./keycloak/bin/kc.sh start-dev

Il va alors se lancer sans base de données, sans besoin de SSL/TLS, etc.

On pourra se connecter sur http://127.0.0.1:8080/ pour créer un identifiant.

Attention, les paramètres utilisés ne sont valables que le temps d’un démarrage, si on le relance il faudra re-créer un identifiant et tous les paramètres.

Configuration avancée

Nginx

On conseille de limiter l’exposition des URLs en suivant les recommandations de https://www.keycloak.org/server/reverseproxy#_exposed_path_recommendations.

Voici un exemple de configuration Nginx plus fine :

  location / {
      deny all;
  }

  location ~ (^/realms/(?!master)/.*|^/resources/.*) {
      proxy_pass http://127.0.0.1:8080;
  }

  location ~ (^/realms/master/.*|^/admin/.*|^/health/.*|^/metric/.*) {
      proxy_pass http://127.0.0.1:8080;
      include /etc/nginx/snippets/ipaddr_allowlist;
      deny all;
  }

Si besoin de donner un accès admin uniquement pour un realm en particulier :

  location ~ (^/admin/foo/.*|^/admin/realms/foo|^/admin/serverinfo) {
      proxy_pass http://127.0.0.1:8080;
  }

Monitoring

https://www.keycloak.org/server/health

  • On peut activer les endpoints de health check pour surveiller l’état de Keycloak
health-enabled=true

Cela va activer les endpoints /health, /health/live, /health/ready et /health/started. > Généralement, surveiller health suffit, pour plus de détail : https://quarkus.io/guides/smallrye-health#running-the-health-check

Haute disponibilité (WIP)

Keycloak est conçu pour fonctionner en haute disponibilité avec infinispan (In-Memory Distributed Data Store)

TODO https://www.keycloak.org/server/configuration-production -> https://www.keycloak.org/server/caching

Proxy HTTP sortant

Il faut définir la variable d’environnement HTTP_PROXY ou HTTPS_PROXY. Dans l’unité systemd, avant la ligne ExecStart ajouter ligne : Environment="HTTP_PROXY=http://127.0.0.1:3128/".

Puis exécuter systemctl daemon-reload et redémarrer le service Keycloak.

Référence : https://www.keycloak.org/server/outgoinghttp

Fail2Ban

Voir HowtoFail2Ban

Administration

Options de démarrage

$ ./keycloak/bin/kc.sh start-dev --help
$ ./keycloak/bin/kc.sh start --help

Gestion des realms

Un realm (royaume) est un ensemble isolé d’utilisateurs et d’applications géré par un administrateur.

Le royaume master est utilisé pour gérer Keycloak et ne doit pas être utilisé pour gérer d’autres applications.

Tester le fonctionnement des royaumes voir getting-started-zip

suivre les étapes jusqu’a arriver au message “hello, myuser” sur https://www.keycloak.org/app/

Créer un royaume

Dans le menu déroulant tout en haut à gauche choisir “Create Realm”

Choisir un nom de royaume “Realm name” puis le créer avec “Create”

Créer un utilisateur

ATTENTION : nous allons créer un utilisateur dans le royaume sélectionné dans le menu déroulant tout en haut à gauche.

Créer client

Un client va être une application qui se referera à keycloak pour identifier ses utilisateur

Exemple Nextcloud : https://stackoverflow.com/questions/48400812/sso-with-saml-keycloak-and-nextcloud

User Federation

Connexion à LDAP : https://rob-ferguson.me/keycloak-flowable-and-openldap/

Mails

Chaque realm à une addresse email et une configuration de connexion à un serveur mail. On peut tester l’envoi de mail et utiliser les mails pour les mots de passe oubliés notamment.

Créer un utilisateur administrateur

  1. Depuis la page d’accueil de l’interface d’administration, cliquer sur Users dans le volet à gauche.

  2. Cliquer sur Add user.

  3. Compléter les champs Username, seul obligatoire, et Email puis cliquer sur Create.

  4. Une fois l’utilisateur créé et sélectionné, cliquer sur l’onglet Role mapping.

  5. En haut à gauche de la fenêtre qui vient de s’ouvrir, choisir Filter by realm roles.

  6. Sélectionner le role admin puis cliquer sur Assign.

Restaurer identifiant de l’utilisateur admin temporaire

$ ./keycloak/bin/kc.sh bootstrap-admin user

Le programme demande le nom de l’utilisateur puis son mot de passe.

Exporter et importer les royaumes

https://www.keycloak.org/server/importExport

Export

Il est recommandé d’arrêter tous les nœuds du cluster Keycloak avant de faire un export.

On peut exporter en un seul fichier :

$ ./keycloak/bin/kc.sh export --file dump.json

On peut aussi faire un export par royaume :

$ ./keycloak/bin/kc.sh export --dir dump/

On peut exporter avec des fichiers distincts par utilisateurs :

$ ./keycloak/bin/kc.sh export --dir dump/ --users different_files --users-per-file 100

On peut exporter sans les utilisateurs :

$ ./keycloak/bin/kc.sh export --dir dump/ --users skip

Attention, si vous avez une Federation LDAP, même sans « caching », les utilisateurs seront tout de même exportés et cela peut poser des problèmes à l’import, cf https://github.com/keycloak/keycloak/issues/46537

Import

Il faut arrêter tous les nœuds du cluster Keycloak avant de faire un import.

Pour importer un dump :

$ ./keycloak/bin/kc.sh import --file dump.json

Sauvegarde

Soit on utilise les exports/imports ci-dessus.

On peut aussi faire un dump de la base PostgreSQL et des fichiers tout simplement.

Gestion via CLI

https://www.keycloak.org/docs/latest/server_admin/#admin-cli

On peut faire toutes les opérations que l’on effectue dans l’interface d’admin aussi via l’utilitaire de commande kcadm.sh

Celui-ci va simplement parler localement à l’API REST de Keycloak

Quelques exemples : https://wjw465150.gitbooks.io/keycloak-documentation/content/server_admin/topics/admin-cli.html

Se connecter avec kcadm.sh :

$ ./keycloak/bin/kcadm.sh config credentials --server http://localhost:8080 --realm master --user jdoe --client admin-cli
Logging into http://localhost:8080 as user jdoe of realm master
Enter password:

Récuperer de la configuration et la mettre à jour :

# mettre à jour un client
keycloak@MACHINE:~/keycloak-26.1.1/bin$ ./kcadm.sh get clients/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -r master > master.client
keycloak@MACHINE:~/keycloak-26.1.1/bin$ vim master.client
keycloak@MACHINE:~/keycloak-26.1.1/bin$ ./kcadm.sh update clients/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -r master -f master.client
# realm
keycloak@MACHINE:~/keycloak-26.1.1/bin$ ./kcadm.sh get realms/master

FAQ

Ressources intéressantes

Configurer la durée de vie des sessions

On peux configurer la durée de vie “maximum” et “idle” des session pour un royaume.

  • La durée de vie “idle” correspond à la durée de vie maximum d’une session à partir du moment où il n’y a plus d’activité
  • La durée de vie “max” correspond à maximum de la durée de vie totale d’une session

On peut les configurer dans admin.sso.exemple.com/admin/master/console/#/foorealm/realm-settings/sessions

Remapper un claim de token

On peut remapper sub pour qu’il corresponde a username par exemple

Dans : Client scopes > <nom-client>-dedicated > Configure a new mapper

Mapper type : User Property Name : sub Property : username Token Claim Name : sub Claim JSON Type : String