Aller au contenu

Déployer Keycloak 26 et protéger une application par SSO sur Debian 13

Monter un serveur d’identité, c’est facile. Le monter de telle sorte que les jetons qu’il émet soient acceptés, que la console d’administration ne parte pas en boucle de redirection et que les clients fassent confiance à son certificat, c’est une autre affaire. Voici la procédure complète, avec les six endroits où j’ai réellement buté.

Keycloak est un serveur d’identité. Il centralise les comptes, les mots de passe et les règles d’accès, puis délivre aux applications des jetons prouvant qui est l’utilisateur. Les applications ne voient plus jamais de mot de passe : elles font confiance à Keycloak.

Deux bénéfices concrets pour une PME. L’utilisateur s’authentifie une fois pour toutes ses applications. Et le jour d’un départ, désactiver un compte dans Keycloak ferme instantanément tous les accès, au lieu de courir après douze bases d’utilisateurs.

Cet article monte le serveur, puis démontre le SSO deux fois : d’abord en déroulant le protocole à la main pour comprendre ce qui se passe, ensuite en plaçant une application existante derrière une authentification, sans toucher à son code.

Navigateur
|
v 443/tcp
nginx .................. terminaison TLS, unique point d'entree
| |
| 127.0.0.1:8080 | 127.0.0.1:4180
v v
Keycloak oauth2-proxy
| |
| 5432/tcp | verifie la session, sinon renvoie vers Keycloak
v v
PostgreSQL /var/www/protege <- site statique protege

Deux noms d’hôte, un seul certificat :

Nom Rôle
sso.lab.internal Keycloak, console d’administration et points d’accès OIDC
protege.lab.internal l’application à protéger, servie par nginx

Machine de test : 4 vCPU, 1,9 Go de RAM, 40 Go libres, adresse fixe 192.168.1.76.

Fenêtre de terminal
sudo apt update
sudo apt install -y openjdk-21-jre-headless postgresql curl unzip jq nginx

Keycloak 26 exige Java 17 ou 21. Debian 13 ne propose plus OpenJDK 17, donc 21 s’impose, ce qui tombe bien puisque c’est la version supportée la plus récente.

Fenêtre de terminal
java -version # openjdk version "21.0.12.1"
psql --version # psql (PostgreSQL) 17.11

Keycloak sait fonctionner avec une base H2 embarquée, réservée au développement. Pour tout le reste, PostgreSQL.

Fenêtre de terminal
sudo -u postgres psql -c "CREATE USER keycloak WITH PASSWORD 'Trixie2026-Keycloak';"
sudo -u postgres createdb -O keycloak -E UTF8 keycloak

Contrôle de la connexion par TCP, celle qu’utilisera Keycloak :

Fenêtre de terminal
PGPASSWORD=Trixie2026-Keycloak psql -h 127.0.0.1 -U keycloak -d keycloak -c 'SELECT version();'
Fenêtre de terminal
cd /tmp
wget https://github.com/keycloak/keycloak/releases/download/26.7.3/keycloak-26.7.3.tar.gz
sudo tar xzf keycloak-26.7.3.tar.gz -C /opt
sudo ln -sfn /opt/keycloak-26.7.3 /opt/keycloak

Le lien symbolique n’est pas cosmétique : il permet de déposer la version suivante à côté et de basculer en une commande, avec un retour arrière tout aussi rapide.

Compte de service dédié, sans shell :

Fenêtre de terminal
sudo groupadd -r keycloak
sudo useradd -r -g keycloak -d /opt/keycloak -s /usr/sbin/nologin keycloak
sudo chown -R keycloak:keycloak /opt/keycloak-26.7.3
Fenêtre de terminal
sudo -u keycloak /opt/keycloak/bin/kc.sh --version
Keycloak 26.7.3
JVM: 21.0.12.1 (Debian OpenJDK 64-Bit Server VM)
OS: Linux 6.12.107+deb13-amd64 amd64

Deux fichiers, une règle : aucun secret dans le fichier de configuration principal.

/opt/keycloak/conf/keycloak.conf :

# ---- Base de donnees ----
db=postgres
db-url=jdbc:postgresql://localhost:5432/keycloak
db-username=keycloak
# ---- Identite publique ----
# Depuis Keycloak 26, hostname attend une URL complete. C'est elle qui
# figure dans l'issuer des jetons et dans les metadonnees OIDC.
hostname=https://sso.lab.internal
# ---- Terminaison TLS deleguee a nginx ----
# proxy-headers remplace l'ancien parametre proxy=edge.
proxy-headers=xforwarded
http-enabled=true
http-host=127.0.0.1
http-port=8080
# ---- Exploitation ----
health-enabled=true
metrics-enabled=true

/etc/keycloak/keycloak.env, en 640 root:keycloak :

KC_DB_PASSWORD=Trixie2026-Keycloak
JAVA_OPTS_KC_HEAP=-Xms256m -Xmx512m

Trois points méritent d’être compris plutôt que recopiés.

hostname est la décision structurante. Toute URL fabriquée par Keycloak en découle, à commencer par l’issuer des jetons. Se tromper ici, c’est voir les clients rejeter des jetons pourtant valides.

http-host=127.0.0.1 interdit tout accès direct : seul nginx parle à Keycloak.

proxy-headers=xforwarded fait lire à Keycloak les en-têtes du proxy. Sans lui, il fabrique des URL en http derrière un proxy https et la console d’administration part en boucle de redirection.

Keycloak distingue les options de construction, figées dans l’image, des options d’exécution. Le choix du moteur de base en fait partie.

Fenêtre de terminal
sudo -u keycloak /opt/keycloak/bin/kc.sh build
INFO: The following run time options were found, but will be ignored during
build time: kc.db-username, kc.http-host, kc.http-enabled, kc.proxy-headers,
kc.http-port, kc.db-url, kc.hostname
Quarkus augmentation completed in 10183ms
Server configuration updated and persisted.
real 0m12.731s

Ce message n’est pas une erreur : il énumère les paramètres qui seront lus au démarrage et non gelés maintenant. La construction permet ensuite start --optimized, qui évite de reconstruire à chaque lancement.

/etc/systemd/system/keycloak.service
[Unit]
Description=Keycloak Identity and Access Management
After=network-online.target postgresql.service
Wants=network-online.target
Requires=postgresql.service
[Service]
Type=exec
User=keycloak
Group=keycloak
EnvironmentFile=/etc/keycloak/keycloak.env
ExecStart=/opt/keycloak/bin/kc.sh start --optimized
Restart=on-failure
RestartSec=10
TimeoutStartSec=180
LimitNOFILE=65536
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/keycloak-26.7.3/data
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictSUIDSGID=true
[Install]
WantedBy=multi-user.target
Fenêtre de terminal
sudo install -d -o keycloak -g keycloak -m 750 /opt/keycloak-26.7.3/data

Premier démarrage, avec un administrateur temporaire ajouté provisoirement au fichier d’environnement :

KC_BOOTSTRAP_ADMIN_USERNAME=admin
KC_BOOTSTRAP_ADMIN_PASSWORD=Trixie2026-Admin
Fenêtre de terminal
sudo systemctl daemon-reload
sudo systemctl enable --now keycloak
Keycloak 26.7.3 on JVM (powered by Quarkus 3.33.3.1) started in 6.973s.
Listening on: http://127.0.0.1:8080.
Management interface listening on http://127.0.0.1:9000.
Profile prod activated.
Initializing database schema. Using changelog META-INF/jpa-changelog-master.xml
KC-SERVICES0077: Created temporary admin user with username admin
Fenêtre de terminal
curl -s http://127.0.0.1:9000/health/ready
{ "status": "UP", "checks": [
{ "name": "Keycloak Initialized", "status": "UP" },
{ "name": "Keycloak database connections async health check", "status": "UP" }
] }

Retirez ensuite les deux lignes KC_BOOTSTRAP_ADMIN_* du fichier d’environnement : elles n’ont d’effet qu’à la création.

7. TLS et autorité de certification de laboratoire

Section intitulée « 7. TLS et autorité de certification de laboratoire »

Un réflexe répandu consiste à générer un certificat auto-signé et à le déposer dans le magasin de confiance du système. Cela ne fonctionne pas avec les clients écrits en Go, dont oauth2-proxy :

tls: failed to verify certificate: x509: certificate signed by unknown authority
(possibly because of "x509: invalid signature: parent certificate cannot sign
this kind of certificate")

Un certificat feuille ne porte pas basicConstraints=CA:TRUE et ne peut donc pas servir d’ancre de confiance. OpenSSL tolère historiquement ce raccourci, Go le refuse, à juste titre. La bonne réponse est de monter une petite autorité, ce qui est de toute façon ce qu’on fait dans un vrai réseau interne.

Fenêtre de terminal
cd /etc/nginx/tls
sudo openssl req -x509 -nodes -newkey rsa:4096 -days 3650 \
-keyout lab-ca.key -out lab-ca.crt \
-subj "/C=FR/O=PANDIT Lab/CN=PANDIT Lab Root CA" \
-addext "basicConstraints=critical,CA:TRUE,pathlen:0" \
-addext "keyUsage=critical,keyCertSign,cRLSign"
Fenêtre de terminal
sudo openssl req -nodes -newkey rsa:2048 -keyout sso.key -out sso.csr \
-subj "/C=FR/O=PANDIT Lab/CN=sso.lab.internal"
Fenêtre de terminal
cat > /tmp/serveur.ext <<'EOF'
basicConstraints=CA:FALSE
keyUsage=critical,digitalSignature,keyEncipherment
extendedKeyUsage=serverAuth
subjectAltName=DNS:sso.lab.internal,DNS:protege.lab.internal,IP:192.168.1.76
EOF
sudo openssl x509 -req -in sso.csr -CA lab-ca.crt -CAkey lab-ca.key \
-CAcreateserial -out sso.crt -days 825 -sha256 -extfile /tmp/serveur.ext

On approuve l’autorité, jamais la feuille :

Fenêtre de terminal
sudo cp lab-ca.crt /usr/local/share/ca-certificates/pandit-lab-ca.crt
sudo update-ca-certificates
openssl verify -CAfile lab-ca.crt sso.crt # sso.crt: OK

Le bloc nginx devant Keycloak :

server {
listen 443 ssl;
http2 on;
server_name sso.lab.internal;
ssl_certificate /etc/nginx/tls/sso.crt;
ssl_certificate_key /etc/nginx/tls/sso.key;
ssl_protocols TLSv1.2 TLSv1.3;
# Keycloak emet des cookies volumineux, les tampons par defaut suffisent
# rarement des que l'on ajoute des fournisseurs d'identite.
proxy_buffer_size 16k;
proxy_buffers 8 16k;
large_client_header_buffers 4 16k;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_http_version 1.1;
}
# L'interface de gestion n'a rien a faire sur le reseau.
location /health { return 404; }
location /metrics { return 404; }
}

Contrôle immédiat, avant même de créer quoi que ce soit :

Fenêtre de terminal
curl -s https://sso.lab.internal/realms/master/.well-known/openid-configuration | jq -r .issuer
https://sso.lab.internal/realms/master

Si l’issuer sort en http ou avec une autre adresse, le problème est dans hostname ou dans les en-têtes transmis, et rien de ce qui suit ne fonctionnera.

Tout se fait dans la console web, mais la ligne de commande a le mérite d’être reproductible et versionnable.

Fenêtre de terminal
KC=/opt/keycloak/bin/kcadm.sh
$KC config credentials --server http://127.0.0.1:8080 \
--realm master --user admin --password Trixie2026-Admin

Un royaume est un espace étanche : ses utilisateurs, ses clients, ses règles. Le royaume master sert à administrer Keycloak, jamais à héberger vos utilisateurs.

Fenêtre de terminal
$KC create realms -s realm=pandit -s enabled=true -s displayName="PANDIT Lab"
Fenêtre de terminal
$KC create users -r pandit -s username=alice -s [email protected] \
-s firstName=Alice -s lastName=Martin -s enabled=true -s emailVerified=true
$KC set-password -r pandit --username alice --new-password 'Trixie2026-Alice'
Fenêtre de terminal
$KC create clients -r pandit -s clientId=demo-oidc -s enabled=true \
-s publicClient=false -s standardFlowEnabled=true \
-s 'redirectUris=["http://127.0.0.1:8081/callback"]'
Notion Ce que c’est
Royaume espace étanche : utilisateurs, clients et règles ne franchissent pas la frontière
Client une application qui délègue son authentification à Keycloak
Client confidentiel peut garder un secret, donc un serveur. Un client public est une application mobile ou du JavaScript
URI de redirection liste blanche des adresses de retour. C’est ce qui empêche un attaquant de détourner le code d’autorisation

Plutôt qu’un client jouet, autant dérouler le protocole en curl. On voit exactement ce qui circule, et cela se rejoue à volonté.

Fenêtre de terminal
curl -s -c cookies.txt "https://sso.lab.internal/realms/pandit/protocol/openid-connect/auth?client_id=demo-oidc&redirect_uri=http%3A%2F%2F127.0.0.1%3A8081%2Fcallback&response_type=code&scope=openid%20profile%20email&state=$STATE&nonce=$NONCE"

Keycloak répond par la page de connexion et pose un cookie de session. Le formulaire pointe vers une URL contenant un session_code à usage unique.

state protège contre la falsification de requête : on le tire au hasard et on vérifie qu’il revient identique. nonce lie le jeton d’identité à cette demande précise et interdit le rejeu.

Fenêtre de terminal
curl -s -b cookies.txt -c cookies.txt -D - -o /dev/null -X POST "$ACTION" \
--data-urlencode "username=alice" \
--data-urlencode "password=Trixie2026-Alice" \
--data-urlencode "credentialId="
HTTP/2 302
location: http://127.0.0.1:8081/callback?state=b78f9438b23e4e31&session_state=uTAF0DM...
&code=1d012608-6104-7e23-69b2-d482f726270b.uTAF0DM...

Le mot de passe n’est allé qu’à Keycloak. L’application ne recevra qu’un code à usage unique, inutilisable sans le secret du client.

Fenêtre de terminal
curl -s -X POST "https://sso.lab.internal/realms/pandit/protocol/openid-connect/token" \
-d grant_type=authorization_code \
-d client_id=demo-oidc -d client_secret="$SECRET" \
-d code="$CODE" --data-urlencode "redirect_uri=http://127.0.0.1:8081/callback" | jq
{
"token_type": "Bearer",
"expires_in": 300,
"refresh_expires_in": 1800,
"scope": "openid profile email",
"jetons": [ "access_token", "id_token", "refresh_token" ]
}

Cinq minutes pour le jeton d’accès, trente pour le jeton de rafraîchissement. Un jeton volé a donc une durée de nuisance courte.

Un JWT se lit sans clef, il suffit de décoder la charge utile. C’est important à comprendre : un jeton n’est pas chiffré, il est signé. N’y mettez rien de confidentiel.

Fenêtre de terminal
echo "$ID_TOKEN" | cut -d. -f2 | tr '_-' '/+' | base64 -d | jq
{
"iss": "https://sso.lab.internal/realms/pandit",
"aud": "demo-oidc",
"sub": "ded44813-32c8-4866-aaa8-39a9ebc15f9e",
"preferred_username": "alice",
"email": "[email protected]",
"email_verified": true,
"nonce": "7c60064f5596b4a6",
"exp": 1788704991,
"iat": 1788704691
}

Une application qui reçoit ce jeton doit vérifier la signature, puis iss, aud, exp et nonce. Sauter l’une de ces vérifications, c’est accepter n’importe quel jeton.

Le sub est l’identifiant stable de l’utilisateur. C’est sur lui qu’une application doit s’appuyer, jamais sur le nom ni sur l’adresse, qui changent.

Fenêtre de terminal
curl -s "https://sso.lab.internal/realms/pandit/protocol/openid-connect/userinfo" \
-H "Authorization: Bearer $ACCESS_TOKEN" | jq
{
"sub": "ded44813-32c8-4866-aaa8-39a9ebc15f9e",
"preferred_username": "alice",
"email": "[email protected]",
"given_name": "Alice",
"family_name": "Martin"
}

Voilà le cas d’usage le plus rentable en clientèle : mettre du SSO devant une application qui n’en a pas, sans toucher à son code. oauth2-proxy s’intercale, nginx l’interroge à chaque requête.

oauth2-proxy n’est pas dans Debian, on prend le binaire amont :

Fenêtre de terminal
cd /tmp
wget https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v7.15.4/oauth2-proxy-v7.15.4.linux-amd64.tar.gz
tar xzf oauth2-proxy-v7.15.4.linux-amd64.tar.gz
sudo install -m 755 oauth2-proxy-v7.15.4.linux-amd64/oauth2-proxy /usr/local/bin/

Un client dédié dans Keycloak :

Fenêtre de terminal
$KC create clients -r pandit -s clientId=oauth2-proxy -s enabled=true \
-s publicClient=false -s standardFlowEnabled=true \
-s 'redirectUris=["https://protege.lab.internal/oauth2/callback"]'

/etc/oauth2-proxy/oauth2-proxy.cfg :

http_address = "127.0.0.1:4180"
# Indispensable derriere nginx, sinon oauth2-proxy prend l'adresse du proxy
# pour celle du client et fabrique des URL de retour en http.
reverse_proxy = true
provider = "keycloak-oidc"
oidc_issuer_url = "https://sso.lab.internal/realms/pandit"
client_id = "oauth2-proxy"
redirect_url = "https://protege.lab.internal/oauth2/callback"
# Sans email_domains, oauth2-proxy refuse toute session, meme authentifiee.
# C'est la cause la plus frequente de boucle de connexion.
email_domains = ["*"]
cookie_secure = true
cookie_httponly = true
cookie_samesite = "lax"
cookie_expire = "8h"
skip_provider_button = true
set_xauthrequest = true
# PKCE : le fournisseur l'annonce, autant s'en servir.
code_challenge_method = "S256"
# Sans cette liste, tout client peut forger X-Forwarded-For et usurper une adresse.
trusted_proxy_ips = ["127.0.0.1/32", "::1/128"]

Les deux secrets vont dans /etc/oauth2-proxy/oauth2-proxy.env, lu par systemd :

Fenêtre de terminal
printf 'OAUTH2_PROXY_CLIENT_SECRET=%s\nOAUTH2_PROXY_COOKIE_SECRET=%s\n' "$SECRET_CLIENT" "$(openssl rand -base64 32 | tr -d '\n' | tr '+/' '-_')" | sudo tee /etc/oauth2-proxy/oauth2-proxy.env

Le bloc nginx du site protégé :

server {
listen 443 ssl;
server_name protege.lab.internal;
ssl_certificate /etc/nginx/tls/sso.crt;
ssl_certificate_key /etc/nginx/tls/sso.key;
location /oauth2/ {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
}
# Sous-requete d'autorisation. Le corps est retire : nginx n'en a pas
# besoin et le transmettre casse les POST volumineux.
location = /oauth2/auth {
internal;
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header Content-Length "";
proxy_pass_request_body off;
}
location / {
auth_request /oauth2/auth;
error_page 401 = /oauth2/start?rd=$scheme://$host$request_uri;
auth_request_set $utilisateur $upstream_http_x_auth_request_user;
auth_request_set $courriel $upstream_http_x_auth_request_email;
add_header X-Utilisateur $utilisateur always;
add_header X-Courriel $courriel always;
root /var/www/protege;
index index.html;
}
}
===== 1. Acces sans session =====
statut 302
https://sso.lab.internal/realms/pandit/protocol/openid-connect/auth?approval_prompt=force
&client_id=oauth2-proxy
&code_challenge=4ki6LFcrYLGRVvgIey3lc3tk2Sxd4FZ1rnnMPK4FDcw
&code_challenge_method=S256
===== 2. Redirection suivie jusqu a Keycloak =====
titre : Sign in to PANDIT Lab
===== 3. Authentification d alice =====
cookie de session depose :
_oauth2_proxy #HttpOnly_protege.lab.internal
===== 4. Acces avec la session =====
statut 200
contenu servi :
Zone protegee
Si vous lisez ceci, Keycloak vous a authentifie.
identite transmise a nginx :
x-utilisateur: ded44813-32c8-4866-aaa8-39a9ebc15f9e
x-courriel: [email protected]
===== 5. Deconnexion =====
sign_out : 302
acces apres deconnexion : 302

Le test a été joué sans l’option -k de curl : le TLS est réellement vérifié, ce qui prouve au passage que l’autorité du lab est bien approuvée.

La même pile en Docker Compose, exécutée et vérifiée elle aussi.

Fenêtre de terminal
sudo apt install -y docker.io docker-compose
services:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: ${KC_DB_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U keycloak -d keycloak"]
interval: 10s
retries: 10
restart: unless-stopped
keycloak:
image: quay.io/keycloak/keycloak:26.7.3
command: start
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: ${KC_DB_PASSWORD}
KC_HOSTNAME: https://sso.lab.internal
KC_PROXY_HEADERS: xforwarded
KC_HTTP_ENABLED: "true"
KC_HEALTH_ENABLED: "true"
KC_BOOTSTRAP_ADMIN_USERNAME: ${KC_ADMIN_USER}
KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_ADMIN_PASSWORD}
JAVA_OPTS_KC_HEAP: -Xms256m -Xmx512m
depends_on:
postgres:
condition: service_healthy
# Publie uniquement sur la boucle locale : nginx reste le seul point
# d'entree, exactement comme en installation native.
ports:
- "127.0.0.1:8080:8080"
restart: unless-stopped
volumes:
pgdata:
Container keycloak-docker-postgres-1 Healthy
Container keycloak-docker-keycloak-1 Started
real 0m27.712s
Keycloak 26.7.3 on JVM (powered by Quarkus 3.33.3.1) started in 6.789s.
Critère Natif Conteneurs
Mise en place une dizaine de commandes un fichier, une commande
Mémoire mesurée 681 Mo Keycloak 587 Mo Keycloak, 51 Mo PostgreSQL
Mise à jour archive, kc.sh build, redémarrage changer l’étiquette d’image
Sauvegarde base et /opt/keycloak/conf volume et fichier compose
Durcissement directives systemd isolation du moteur de conteneurs
Symptôme Cause Correction
status=226/NAMESPACE au démarrage ReadWritePaths pointe un répertoire inexistant créer data avant le premier lancement
Unable to find matching target resource method sur /health l’interface de gestion est sur 9000 depuis Keycloak 26 interroger 127.0.0.1:9000/health/ready
Boucle de redirection sur la console X-Forwarded-Proto absent ou proxy-headers non posé vérifier les en-têtes nginx et proxy-headers=xforwarded
issuer en http ou mauvaise adresse hostname incorrect URL complète en https dans hostname
parent certificate cannot sign this kind of certificate certificat feuille placé dans le magasin de confiance monter une autorité et approuver l’autorité
Boucle de connexion sans fin sur le site protégé email_domains absent email_domains = ["*"], puis restreindre
oauth2-proxy refuse de démarrer secret de cookie de taille invalide exactement 16, 24 ou 32 octets
Avertissement no --trusted-proxy-ip configured tout client peut forger X-Forwarded-For trusted_proxy_ips limité au proxy
Jetons rejetés par les clients horloge décalée timedatectl, resynchroniser
Signatures APT invalides après restauration horloge revenue en arrière systemctl restart systemd-timesyncd
--optimized échoue en conteneur image non bâtie avec kc.sh build command: start, ou Dockerfile en deux étages
Le tueur de mémoire arrête Keycloak tas Java non plafonné JAVA_OPTS_KC_HEAP=-Xms256m -Xmx512m

Mise à jour, en tirant parti du lien symbolique :

Fenêtre de terminal
cd /tmp && wget https://github.com/keycloak/keycloak/releases/download/26.x.y/keycloak-26.x.y.tar.gz
sudo tar xzf keycloak-26.x.y.tar.gz -C /opt
sudo cp /opt/keycloak/conf/keycloak.conf /opt/keycloak-26.x.y/conf/
sudo chown -R keycloak:keycloak /opt/keycloak-26.x.y
sudo install -d -o keycloak -g keycloak -m 750 /opt/keycloak-26.x.y/data
sudo -u keycloak /opt/keycloak-26.x.y/bin/kc.sh build
sudo systemctl stop keycloak
sudo ln -sfn /opt/keycloak-26.x.y /opt/keycloak
sudo sed -i 's|keycloak-26.7.3|keycloak-26.x.y|' /etc/systemd/system/keycloak.service
sudo systemctl daemon-reload && sudo systemctl start keycloak

Retour arrière : repointer le lien et l’unité sur l’ancienne version. Attention toutefois, une migration de schéma de base n’est pas réversible. Sauvegardez avant.

Fenêtre de terminal
sudo -u postgres pg_dump -Fc keycloak > keycloak-$(date +%F).dump

Ce qu’il faut sauvegarder tient en deux lignes : la base PostgreSQL, qui contient tout, et /opt/keycloak/conf plus /etc/keycloak. Les binaires se retéléchargent.

Supervision :

Fenêtre de terminal
curl -s http://127.0.0.1:9000/health/ready | jq
sudo journalctl -u keycloak -f
  • Fédération LDAP ou Active Directory, pour adosser Keycloak à l’annuaire existant plutôt qu’à des comptes locaux
  • Rôles et groupes, pour passer de l’authentification à l’autorisation, avec allowed_groups côté oauth2-proxy
  • Double facteur, OTP ou WebAuthn, activable par royaume en quelques clics
  • Haute disponibilité, plusieurs instances en cluster derrière le même proxy