Aller au contenu

Bonnes pratiques

Haute disponibilité et reprise d'activité

Architecture HA multi-AZ

Pour une disponibilité maximale, déployer les instances Keycloak sur plusieurs zones de disponibilité (AZ) ou plusieurs nœuds physiques distincts.

graph TD
    LB["Load Balancer<br/>(HAProxy / Cloud LB)"] --> KC1["AZ-1<br/>Keycloak #1<br/>Infinispan"]
    LB --> KC2["AZ-2<br/>Keycloak #2<br/>Infinispan"]
    LB --> KC3["AZ-3<br/>Keycloak #3<br/>Infinispan"]
    KC1 <--> KC2 <--> KC3
    KC1 --> PG["PostgreSQL<br/>Primary (AZ-1)<br/>Replica (AZ-2)<br/>Replica (AZ-3)"]
    KC2 --> PG
    KC3 --> PG

Objectifs de disponibilité

Metrique Cible Justification
RTO (Recovery Time Objective) < 5 minutes Failover automatique Infinispan
RPO (Recovery Point Objective) < 1 minute Réplication synchrone PostgreSQL
SLA 99.9% (8.7h d'indisponibilite/an) Service critique transversal

PodDisruptionBudget (Kubernetes)

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: keycloak-pdb
  namespace: keycloak-system
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: keycloak

Backup et restore PostgreSQL

Backup continu avec WAL archiving

# postgresql.conf
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /backup/wal/%f && cp %p /backup/wal/%f'
max_wal_senders = 5

Backup periodique

#!/bin/bash
# Backup complet quotidien
pg_basebackup -h localhost -U replication -D /backup/base/$(date +%Y%m%d) \
  --wal-method=stream --checkpoint=fast --compress=gzip

# Retention : 7 jours de backups complets
find /backup/base -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \;

Procedure de restauration

# 1. Arreter Keycloak
systemctl stop keycloak

# 2. Restaurer le backup de base
rm -rf /var/lib/postgresql/data/*
tar xzf /backup/base/20260416/base.tar.gz -C /var/lib/postgresql/data/

# 3. Configurer la recovery
cat > /var/lib/postgresql/data/recovery.signal << EOF
EOF

cat >> /var/lib/postgresql/data/postgresql.conf << EOF
restore_command = 'cp /backup/wal/%f %p'
recovery_target_time = '2026-04-16 14:00:00'
EOF

# 4. Demarrer PostgreSQL (replay des WAL)
systemctl start postgresql

# 5. Verifier puis redemarrer Keycloak
systemctl start keycloak

Tester la restauration

Planifier un test de restauration trimestriel dans un environnement isole. Documenter la procedure et mesurer le temps de restauration reel.

Failover Infinispan

Le cache distribue Infinispan gère automatiquement le failover :

Scenario Comportement Impact
Perte d'1 nœud Keycloak Infinispan redistribue les sessions Aucun — les sessions sont repliquees
Perte de 2 nœuds sur 3 Le nœud restant detient toutes les sessions Dégradation — plus de HA
Perte totale Toutes les sessions sont perdues Les utilisateurs doivent se reconnecter

Configuration recommandee du cache :

<!-- infinispan.xml (embarque dans Keycloak) -->
<distributed-cache name="sessions" owners="2">
  <!-- 2 copies de chaque session = tolere 1 panne -->
  <state-transfer timeout="60000"/>
</distributed-cache>

<distributed-cache name="authenticationSessions" owners="2">
  <expiration max-idle="1800000"/> <!-- 30 min -->
</distributed-cache>

Nombre d'owners

Le parametre owners définit le nombre de copies de chaque entree de cache. Avec owners=2 et 3 nœuds, chaque session est presente sur 2 nœuds. Augmenter a 3 pour tolérer la perte de 2 nœuds simultanément (au prix de la mémoire).

Migration depuis un LDAP legacy

Stratégie de migration progressive

Ne pas migrer en big bang. Utiliser la fédération Keycloak pour coexister avec l'annuaire existant pendant la transition.

gantt
    title Migration LDAP → Keycloak
    dateFormat  YYYY-MM
    section Phase 1
    Federation LDAP read-only     :a1, 2026-05, 2026-07
    Ajout OIDC service par service :a2, 2026-06, 2026-09
    section Phase 2
    MFA pour tous les utilisateurs :a3, 2026-08, 2026-10
    Migration groupes/roles       :a4, 2026-09, 2026-11
    section Phase 3
    Basculement ecriture Keycloak :a5, 2026-11, 2026-12
    Decommissionnement LDAP       :a6, 2027-01, 2027-02

Étapes détaillées

Phase Action Duree Risque
1. Coexistence Federer le LDAP en read-only dans Keycloak 2 mois Faible
1. Migration OIDC Ajouter OIDC client par client (Gitea, Grafana...) 3 mois Moyen (par service)
2. MFA Activer le MFA pour tous les utilisateurs 2 mois Moyen (resistance utilisateurs)
2. Rôles Migrer les groupes LDAP vers les rôles Keycloak 2 mois Moyen
3. Écriture Basculer Keycloak en mode WRITABLE 1 mois Eleve
3. Decommission Eteindre l'ancien LDAP 1 mois Faible (si phase 3 validee)

Points d'attention

Comptes de service

Les comptes de service LDAP (utilisateurs techniques pour les applications) doivent etre migres vers des service accounts Keycloak avec client credentials grant. Ne pas les oublier lors de l'inventaire.

Upgrade Keycloak (blue/green)

Stratégie blue/green

Ne jamais upgrader Keycloak en place en production. Utiliser un déploiement blue/green.

graph TD
    LB["Load Balancer<br/>(poids: blue=100%, green=0%)"]
    LB --> Blue["BLUE<br/>KC v25.0<br/>(actif)"]
    LB --> Green["GREEN<br/>KC v26.0<br/>(standby)"]
    Blue --> PG["PostgreSQL<br/>(partage)"]
    Green --> PG

Procedure d'upgrade

Étape Action Validation
1 Lire les release notes et changelog Vérifier les breaking changes
2 Backup complet de la base PostgreSQL Vérifier l'intégrité du backup
3 Déployer la nouvelle version (green) Health check OK
4 Migrer la base (Keycloak le fait au demarrage) Logs de migration sans erreur
5 Tester les flux critiques sur green Login OIDC, SAML, LDAP sync
6 Basculer le trafic (blue→green) progressivement 10% → 50% → 100%
7 Surveiller les metriques pendant 24h Pas d'augmentation d'erreurs
8 Decommissionner blue Conserver en standby 48h pour rollback

Migration de base irreversible

Les migrations de schema PostgreSQL effectuees par Keycloak sont irreversibles. Un rollback necessite de restaurer le backup de la base. Toujours sauvegarder avant la migration.

Automatisation avec Helm

# Deployer la nouvelle version en parallele
helm upgrade keycloak-green bitnami/keycloak \
  --namespace keycloak-green \
  --values values-keycloak-v26.yaml \
  --set replicaCount=1  # 1 seul replica pour tester

# Tester
curl -s https://keycloak-green.internal/health/ready

# Basculer le trafic
kubectl patch ingress keycloak -n keycloak-system \
  --type merge \
  -p '{"spec":{"rules":[{"host":"auth.example.com","http":{"paths":[{"path":"/","pathType":"Prefix","backend":{"service":{"name":"keycloak-green","port":{"number":8080}}}}]}}]}}'

Troubleshooting

Token expiry (erreurs 401)

Symptome : les utilisateurs reçoivent des erreurs 401 de manière intermittente.

Causes possibles :

Cause Diagnostic Solution
Access token expire Vérifier accessTokenLifespan (defaut 5 min) Augmenter ou vérifier le refresh token flow
Horloge desynchronisee date sur les nœuds Keycloak et les services Configurer NTP/chrony
Cle de signature changee Vérifier le JWKS endpoint Redemarrer les services pour forcer le rechargement des cles
Token blackliste Vérifier les revocation events dans les logs Vérifier la raison de la revocation
# Decoder un JWT pour diagnostiquer
echo "eyJhbGciOiJS..." | cut -d. -f2 | base64 -d | jq .

# Verifier les cles publiques
curl -s https://auth.example.com/realms/organization/protocol/openid-connect/certs | jq .

Debug des flux OIDC

Symptome : la redirection OIDC échoue ou boucle.

Diagnostic :

# 1. Verifier l'endpoint de discovery
curl -s https://auth.example.com/realms/organization/.well-known/openid-configuration | jq .

# 2. Verifier le client existe
kcadm.sh get clients -r organization -q clientId=svc-gitea

# 3. Verifier les redirect URIs
kcadm.sh get clients/$CLIENT_ID -r organization | jq '.redirectUris'

# 4. Activer le logging debug temporairement
# Dans la console admin : Realm Settings > Events > Config
# Enabled Event Types : ajouter CODE_TO_TOKEN_ERROR

Erreurs courantes :

Erreur Cause Solution
invalid_redirect_uri L'URI de callback ne correspond pas Vérifier les redirectUris du client
invalid_client Client ID incorrect ou client desactive Vérifier la configuration du client
invalid_grant Code d'autorisation expire ou déjà utilise Vérifier les timeouts et la connectivité réseau
access_denied Utilisateur n'a pas les rôles requis Vérifier les rôle mappings et scopes

Problèmes de synchronisation LDAP

Symptome : les utilisateurs LDAP n'apparaissent pas dans Keycloak, ou les modifications ne sont pas refletees.

# Verifier la connectivite LDAP
ldapsearch -H ldaps://ldap.example.com:636 \
  -D "cn=keycloak,ou=services,dc=example,dc=com" \
  -W -b "ou=users,dc=example,dc=com" \
  "(uid=fabien)"

# Lancer une synchronisation manuelle
kcadm.sh create user-storage/$COMPONENT_ID/sync \
  -r organization \
  -s action=triggerFullSync

# Verifier les logs de synchronisation
podman logs keycloak 2>&1 | grep -i "ldap\|sync\|federation"
Problème Cause probable Solution
Aucun utilisateur importe usersDn incorrect Vérifier le DN de base avec ldapsearch
Utilisateurs presents mais login échoue usernameLDAPAttribute incorrect Vérifier l'attribut utilise (uid, sAMAccountName)
Groupes non synchronises Mapper de groupes absent Ajouter un group-ldap-mapper
Sync lente (> 5 min pour 1000 users) Filtre LDAP trop large Ajouter un filtre (objectClass=inetOrgPerson)
Erreur SSL Certificat CA non reconnu Importer le CA dans le truststore Java de Keycloak

Import du certificat CA LDAP

# Copier le certificat CA dans le conteneur
podman cp ca-ldap.crt keycloak:/tmp/ca-ldap.crt

# Importer dans le truststore Java
podman exec keycloak keytool -import -alias ldap-ca \
  -file /tmp/ca-ldap.crt \
  -keystore /opt/keycloak/conf/truststores/ldap-ca.jks \
  -storepass changeit -noprompt

# Redemarrer Keycloak
podman restart keycloak

Metriques a surveiller

Metrique Seuil d'alerte Signification
keycloak_logins (rate) Chute > 50% Problème d'accessibilite
keycloak_login_errors (rate) > 10/min Brute force ou problème de config
keycloak_request_duration_seconds p99 > 2s Performance degradee
jvm_memory_used_bytes > 85% du max Risque d'OOM
pg_stat_activity (connections) > 80% du max Pool de connexions sature
infinispan_cache_size Croissance constante Fuite de sessions, vérifier les expirations

Dashboard Grafana pre-configure

Keycloak expose des metriques Prometheus sur le port 9000. Importer le dashboard officiel (ID: 19659) dans Grafana pour une visibilité immédiate.