Aller au contenu principal

Ressources

Keycloak en haute disponibilité sur Kubernetes : caches, sessions, tests de panne et restauration

Keycloak Kubernetes en haute disponibilité : où vit l'état, cluster unique ou multi-cluster, pannes à tester et restauration de la base, version 26.7.4.

Par , publié le · 25 min de lecture

Base d'expérience : Méthode et documentation officielle de Keycloak 26.7.4 et de Kubernetes ; architecture et exploitation de déploiements Keycloak distribués sur Kubernetes, sans rattachement client.

Relecture factuelle : Claude Code (revue indépendante déléguée par Corentin Mas, 28/09/2026), le

Trois pods Keycloak prêts derrière un répartiteur ne prouvent pas que l'authentification survivra à une panne. La disponibilité se joue dans les caches Infinispan embarqués qui portent les connexions en cours, dans la base qui porte les royaumes et, par défaut, les sessions, dans le transport JGroups entre pods, et dans la manière dont le répartiteur retire un membre qui s'arrête. Une topologie se juge à ce qu'elle perd et à ce qu'elle rétablit quand un pod, une zone, un site, la base ou le cache externe disparaît.

Faits datés

Cet article situe l'état de Keycloak, compare les trois architectures documentées, puis détaille les essais de panne à conduire et une procédure de restauration à éprouver. Cette lecture est établie sur Keycloak 26.7.4, publiée le 16 septembre 2026, et sur les guides High Availability de cette version ; les sources citées ont été vérifiées le . Manifestes et commandes sont des références synthétiques paramétrées, jamais une configuration prête à déployer ni une sortie client.

Vérifié le

Où vit l'état : caches locaux, caches distribués et sessions persistées

Keycloak 26.7.4 embarque Infinispan 16.0.14 dans chaque processus. La commande start active les caches distribués ; start-dev force --cache=local, si bien qu'un poste de développement ne révèle aucun des comportements décrits ici. Trois familles de caches coexistent, avec trois frontières de persistance.

Les caches locaux realms, users, authorization, keys et crl évitent des allers-retours vers la base ou vers des fournisseurs externes, jusqu'à 10 000 entrées par défaut pour les trois premiers. Ils se reconstruisent depuis leur source : ce n'est jamais une copie de sauvegarde. Le cache répliqué work diffuse les invalidations qui obligent chaque membre à abandonner une copie devenue fausse.

Les caches distribués confient chaque entrée à un nombre limité de propriétaires au lieu de la copier sur chaque pod. La fonctionnalité persistent-user-sessions, activée par défaut, stocke les sessions utilisateur en base et ne les charge dans les caches sessions et clientSessions qu'à la demande, dans la limite de 10 000 entrées par nœud et avec un seul propriétaire par entrée, puisque la base fait foi. Les sessions hors ligne suivent la même logique. Un redémarrage complet ne déconnecte donc personne, mais la base est sur le chemin critique des rafraîchissements de jetons.

Trois caches n'ont pas d'autre source de vérité qu'eux-mêmes : authenticationSessions (connexions en cours), loginFailures (compteurs de la détection de force brute) et actionTokens (jetons d'action). Le guide du cluster unique est explicite : la défaillance d'un nombre de nœuds au moins égal au nombre de propriétaires, deux par défaut, fait perdre des entrées de ces trois caches.

Deux variantes déplacent cette frontière, et aucune n'est un réglage de performance :

  • Sessions volatiles. --features-disabled=persistent-user-sessions fait du cache la source de vérité des sessions. Keycloak augmente le nombre de copies, mais un redémarrage de tous les nœuds perd toutes les sessions et la mémoire consommée augmente. Ce mode est impossible avec la fonctionnalité multi-site.
  • Instances sans état. La fonctionnalité stateless, en préversion, persiste en base sessions d'authentification, jetons d'action et échecs de connexion, et ne met plus en cache les données utilisateur. La charge de la base augmente d'autant ; c'est le socle du multi-cluster v2.
Type de chaque cache Keycloak 26.7.4, sa source de vérité par défaut et l'effet d'une perte de tous ses propriétaires
Cache ou étatTypeSource de vérité en 26.7.4 (défauts)Effet d'une perte de tous les propriétaires
realms, users, authorizationLocalBaseRepeuplé depuis la base
keys, crlLocalFournisseurs externes, listes de révocationRechargé à la demande
workRépliquéAucune : messages d'invalidationSans objet : présent sur chaque membre
sessions, clientSessionsDistribué, 1 propriétaireBase (persistent-user-sessions actif)Relues depuis la base ; perdues en mode volatile
offlineSessions, offlineClientSessionsDistribuéBaseRelues depuis la base
authenticationSessionsDistribué, 2 propriétairesCache (base avec stateless)Connexions en cours à recommencer
loginFailuresDistribué, 2 propriétairesCache (base avec stateless)Compteurs de détection de force brute perdus
actionTokensDistribué, 2 propriétairesCache (base avec stateless)État des jetons d'action perdu

Où vit l'état d'un cluster Keycloak

Deux membres Keycloak, leurs quatre ensembles de caches, la base partagée et le répartiteur piloté par les sondes : ce qui se repeuple depuis la base et ce qui se perd avec ses propriétaires.

Schéma défilable horizontalement ; sa version textuelle complète suit.

Lire le schéma sous forme textuelle
  1. Le répartiteur n'admet que les membres dont la sonde ready, sur le port de management 9000, répond positivement ; le cookie AUTH_SESSION_ID lui permet de favoriser le membre propriétaire de la connexion.
  2. Chaque membre porte quatre ensembles de caches : caches locaux, cache répliqué work pour les invalidations, caches de sessions chargés à la demande depuis la base avec un seul propriétaire, et caches distribués authenticationSessions, loginFailures et actionTokens, confiés à deux propriétaires.
  3. Les membres échangent leurs données par JGroups en TCP sur le port 7800, en TLS mutuel par défaut, et détectent la panne d'un pair sur le port 57800.
  4. La base porte la table de découverte jgroups_ping, les données persistantes (royaumes, clients, utilisateurs, sessions en ligne et hors ligne) et les clés du transport chiffré, partagées par tous les membres.
  5. Les caches de sessions se repeuplent depuis la base ; les entrées des trois caches distribués sont perdues si tous leurs propriétaires tombent, comme les sessions en mode volatile.
Modèle explicatif, sans donnée client, d'après les guides Keycloak 26.7.4 sur les caches distribués, le cluster unique et le répartiteur cités en fin d'article.

Former et exploiter le cluster sur Kubernetes

Découverte par la base, transport direct entre pods

La pile par défaut jdbc-ping sépare deux fonctions que les incidents confondent. La découverte passe par la base : chaque membre s'inscrit dans la table jgroups_ping via le protocole JDBC_PING2. Les données circulent directement de pod à pod en TCP sur le port 7800, et le protocole FD_SOCK2 détecte la fermeture brutale d'un pair sur le port 57800. Une politique réseau qui autorise la base mais pas ces deux ports laisse chaque membre découvrir les autres sans former de vue stable. L'opérateur crée lui-même une NetworkPolicy qui n'ouvre ces deux ports qu'aux pods de la même instance Keycloak ; toute politique ajoutée doit préserver ces flux entre membres.

Le transport est chiffré par défaut en TLS mutuel (mTLS) : certificat RSA 2048 bits autosigné, TLS 1.3, clés stockées en base pour être partagées, validité de 60 jours et rotation tous les 30 jours. Dans un maillage de services comme Istio, la documentation propose soit une PeerAuthentication en mode PERMISSIVE sur le port 7800, soit cache-embedded-mtls-enabled=false en confiant chiffrement et autorisation au maillage. Changer cette option, comme changer de pile, impose une recréation plutôt qu'une mise à jour progressive. Les piles kubernetes (DNS_PING), tcp, udp et jdbc-ping-udp sont marquées dépréciées : une configuration héritée qui force --cache-stack=kubernetes est à migrer.

Dernier piège, le nom de cluster, ISPN par défaut. Deux déploiements qui partagent la même base se rejoignent, sauf noms distincts ; mais des noms distincts coupent les invalidations et produisent des caches périmés. La documentation réserve donc spi-cache-embedded--default--cluster-name à la fonctionnalité stateless. Règle de méthode : une base, ou un schéma, par cluster Keycloak.

Répartir les pods sans perdre les deux copies

L'opérateur pose par défaut deux contraintes de répartition, par zone et par nœud, avec maxSkew: 1 et whenUnsatisfiable: ScheduleAnyway : faute de place, plusieurs pods peuvent partager un nœud ou une zone, dont la perte peut emporter toutes les copies d'une connexion en cours. L'opérateur renseigne bien le nom de machine d'après le nœud Kubernetes, mais le guide du cluster unique maintient ce risque parmi ses limites connues, rappelle qu'Infinispan ne tient pas compte de la topologie réseau en répartissant ses entrées, propose DoNotSchedule au risque de pods non planifiables, et recommande au moins autant de réplicas que de zones. Un PodDisruptionBudget (PDB) limite les arrêts simultanés dus à des interruptions volontaires, comme un kubectl drain, mais pas une panne de nœud ; l'opérateur n'en crée pas, et sa présence se vérifie avec kubectl get pdb.

# Référence synthétique d'après les guides Keycloak 26.7.4, à adapter
apiVersion: k8s.keycloak.org/v2beta1
kind: Keycloak
metadata:
  name: keycloak
spec:
  instances: <N_AU_MOINS_EGAL_AU_NOMBRE_DE_ZONES>
  image: <IMAGE_PAR_DIGEST>
  update:
    strategy: Auto
  db:
    vendor: postgres
    host: <HOTE_ECRIVAIN>
    poolInitialSize: <P>
    poolMinSize: <P>
    poolMaxSize: <P>
  scheduling:
    # déclarer ces contraintes remplace celles posées par défaut par l'opérateur
    topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: keycloak
            app.kubernetes.io/instance: <NOM>
      - maxSkew: 1
        topologyKey: kubernetes.io/hostname
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: keycloak
            app.kubernetes.io/instance: <NOM>
  readinessProbe:
    periodSeconds: <PERIODE>
    failureThreshold: <SEUIL>
  additionalOptions:
    - name: metrics-enabled
      value: "true"
    - name: http-max-queued-requests
      value: "<FILE_MAX>"
    - name: shutdown-delay
      value: "<DELAI_DE_RETRAIT>"
    - name: shutdown-timeout
      value: "<DELAI_REQUETES_ET_CACHES>"

Vérifier la vue, puis les sondes

La vue du cluster est la première preuve : Infinispan journalise ISPN000094 à chaque arrivée ou départ, avec le nombre de membres ; la métrique vendor_cluster_size doit égaler le nombre d'instances attendu ; la console d'administration expose le même état sous le fournisseur connectionsInfinispan. Aucune de ces preuves ne valide seule un parcours.

Les sondes sont servies sur le port de management 9000 : /health/started pour le démarrage, /health/live dont l'échec justifie le remplacement du processus, /health/ready qui seule doit autoriser le trafic. Activer les contrôles de santé active l'amorçage asynchrone : les ports HTTP s'ouvrent pendant l'initialisation, raison de plus pour ne router que sur ready. Quatre contrôles sont documentés : base (avec les métriques), cluster (avec jdbc-ping, pour les partitions réseau), arrêt gracieux, qui passe à DOWN dès le pré-arrêt, et initialisation. D'après l'interface ClusterHealth, un membre hors de la partition gagnante doit se déclarer non sain. /health et /metrics ne doivent pas être exposés par le mandataire public.

# Référence synthétique, lecture seule
kubectl -n <ESPACE> wait --for=condition=Ready keycloaks.k8s.keycloak.org/<NOM>
kubectl -n <ESPACE> wait --for=condition=RollingUpdate=False keycloaks.k8s.keycloak.org/<NOM>
kubectl -n <ESPACE> logs -l app=keycloak --since=<FENETRE> | grep 'ISPN000094'
kubectl -n <ESPACE> port-forward pod/<POD> 9000:9000 &
curl --head -fsS <http_ou_https>://localhost:9000/health/ready
kubectl -n <ESPACE> get pod <POD> -o jsonpath='{.spec.terminationGracePeriodSeconds}'

Budgéter la base, délester, puis sortir proprement

Le maximum du pool de connexions, 100 par défaut, est une limite par processus. Les guides recommandent des tailles initiale, minimale et maximale identiques pour conserver les connexions et le cache d'instructions préparées qui leur est lié. Le budget doit couvrir le pic de pods simultanés pendant une mise à jour :

N_pods_max × P_max + C_hors_Keycloak + C_reserve ≤ C_autorisées_par_la_base

Le délestage borne la file : avec http-max-queued-requests, les requêtes en excès reçoivent un HTTP 503 au lieu de s'accumuler, ce qui rend un essai de saturation observable.

L'arrêt se déroule en deux temps. Pendant shutdown-delay, 1 s par défaut, ready répond « non prêt » pour que le répartiteur cesse d'admettre ; pendant shutdown-timeout, 10 s par défaut, Keycloak termine les requêtes en cours puis laisse les caches se rééquilibrer. Un répartiteur qui sonde périodiquement appelle un délai plus long que le défaut ; le guide du mandataire inverse en détaille le calcul. Côté Kubernetes, la période de grâce d'un pod vaut 30 s par défaut, puis le kubelet envoie le signal KILL aux processus restants. D'où la règle de la documentation Keycloak : terminationGracePeriodSeconds doit dépasser shutdown-delay + shutdown-timeout.

L'affinité repose sur le cookie AUTH_SESSION_ID, de la forme <identifiant>.<nœud propriétaire>. La documentation la présente comme une optimisation, non comme une obligation : chaque essai de panne doit donc réussir sans elle.

Cluster unique, multi-cluster v1 ou v2 : ce que chaque topologie tolère

Le cluster unique est l'architecture la plus simple : pas de dépendance externe, un cluster Kubernetes ou des machines virtuelles à réseau transparent, réparti si besoin sur plusieurs zones. Il exige moins de 10 ms aller-retour entre instances et, en multi-zone, une base qui tolère la perte d'une zone par réplication synchrone. Le projet le teste sur OpenShift réparti sur trois zones AWS avec Aurora PostgreSQL ; un guide équivalent existe pour CloudNativePG. Sa faiblesse est nommée par la documentation : le cluster Kubernetes, plan de contrôle compris, reste un point unique de défaillance, et les montées de version, hors correctifs d'une même branche, interrompent le service.

Le multi-cluster v1 relie deux clusters Keycloak, par exemple dans deux clusters Kubernetes situés dans deux zones. Chaque site exécute un cluster Infinispan externe, en version 16.0.14 ou correctif ultérieur, qui porte actionTokens, authenticationSessions, loginFailures et work avec une réplication intersite synchrone ; la base est répliquée de façon synchrone. La fonctionnalité multi-site expose /lb-check, que le répartiteur externe interroge sur chaque site. La latence entre sites doit rester sous 10 ms, 5 ms suggérées, et seuls deux sites sont supportés. Le prix est opérationnel : si la liaison intersite tombe, une automatisation de mise à l'écart retire un site du répartiteur et désactive la réplication ; le site écarté n'est pas réintégré automatiquement et une resynchronisation manuelle, par transfert d'état complet, précède son retour. La configuration supportée est précise (deux clusters mono-zone dans une même région AWS, Aurora PostgreSQL, Global Accelerator, fonction Lambda de bascule), et la documentation annonce jusqu'à 5 minutes d'interruption dans certains scénarios.

Le multi-cluster v2, introduit en préversion avec Keycloak 26.7.0, supprime l'Infinispan externe et relie deux clusters ou plus. Il repose sur la fonctionnalité stateless et sur un nom de cluster distinct par déploiement. Les invalidations de royaume passent par une table de la base selon un motif outbox, interrogée toutes les 100 ms par défaut, et les données de royaume en cache expirent par défaut au bout d'une heure pour éviter des caches durablement désynchronisés. La documentation annonce environ deux fois plus de consommation processeur et d'opérations d'écriture par seconde (IOPS) sur la base, et des interruptions de plusieurs minutes dans certains scénarios. Au , ce guide reste une préversion, que la documentation soumet aux retours des utilisateurs.

Statut, latence, état partagé et pannes tolérées du cluster unique, du multi-cluster v1 et du multi-cluster v2 en Keycloak 26.7.4
CritèreCluster uniqueMulti-cluster v1Multi-cluster v2
Statut en 26.7.4Documenté, configuration testéeSupporté, configuration AWS précisePréversion
Latence documentéeMoins de 10 ms entre instances, 5 ms suggéréesMoins de 10 ms entre sites, 5 ms suggéréesMoins de 10 ms dans chaque cluster et vers la base, 5 ms suggérées
État partagéBase et Infinispan embarquéBase synchrone et Infinispan externe par siteBase synchrone ; état de session en base
ToléréPerte d'un pod, d'un nœud, d'une zonePerte d'une zone ou d'un cluster KubernetesPerte d'une zone ou d'un cluster
Non toléré ou dégradéPerte du cluster Kubernetes, montée de version hors correctifPlus de deux sites ; retour d'un site sans resynchronisationCharge de base accrue ; statut de préversion

Aucune de ces architectures n'assure une continuité entre régions éloignées : c'est le terrain d'un plan de reprise d'activité, distinct d'une politique de sauvegarde. Pour cadrer la topologie avec l'équipe qui opérera la plateforme, la page Mise en production Kubernetes : ouvrir par étapes décrit notre périmètre d'intervention.

Tester les pannes : pod, zone, partition, base, cache externe et site

Les tableaux de reprise de Keycloak annoncent, pour ses configurations testées, aucune perte de données (sous réserve, en v1, des opérations manuelles de resynchronisation) et des délais allant de moins de 30 secondes pour la perte d'un pod à quelques secondes ou quelques minutes pour la base ou la connectivité ; la perte d'un site en v1 est rétablie en moins de deux minutes, et la documentation v1 admet jusqu'à 5 minutes d'interruption dans certains scénarios. Ce sont des constats sur un environnement de référence, pas des engagements : chaque plateforme mesure les siens. Une campagne se prépare en quatre points :

  1. Préconditions. Aucune dégradation en cours (la documentation v1 subordonne une bascule réussie à un système non dégradé), sauvegarde récente vérifiée, journaux et métriques actifs.
  2. Parcours de contrôle. Connexion, rafraîchissement, déconnexion, modification d'un client puis lecture de son effet sur un autre membre, lien d'action sur un compte de test ; en continu pendant l'injection, sans donnée personnelle.
  3. Registre de preuves. Action, horodatage, membre visé, vues ISPN000094, sondes, cibles du répartiteur, état de la base, parcours, décision.
  4. Conditions d'arrêt. Fixées avant l'essai : état divergent servi, donnée persistée perdue, vue instable au-delà de la fenêtre approuvée, requête routée vers une cible non prête.

Une partition ne s'injecte pas en ajoutant une NetworkPolicy : les politiques s'additionnent, et celle de l'opérateur autorise déjà les ports 7800 et 57800 entre membres. Il faut un outil d'injection réseau ou une règle de refus propre au plugin réseau (CNI).

Essais de panne, injection, comportement attendu d'après la documentation, preuves à rapprocher et conditions d'arrêt
EssaiInjectionAttendu d'après la documentationPreuves à rapprocherArrêt si
Perte d'un podSuppression forcée, sans drainageErreurs ou retards de quelques secondes, puis service rétabliVue réduite, vendor_cluster_size, cible retirée, parcours réussisRoutage résiduel vers le pod perdu
Perte d'un nœudArrêt du nœud portant un ou plusieurs podsIdem ; perte de connexions en cours si tous leurs propriétaires y étaientPlacement des pods avant l'essai, vue, parcoursPods bloqués sans remplaçant
Perte d'une zoneIsolement de tous les nœuds d'une zoneReprise en quelques secondes si réplicas au moins égaux aux zonesRépartition par zone, promotion éventuelle de la baseService interrompu hors fenêtre
Partition du transportBlocage de 7800 et 57800 entre deux groupes de podsMembres hors de la partition gagnante non sains/health/ready de chaque côté, cibles routéesDeux groupes admis simultanément
Bascule de la basePromotion d'un réplica, ou arrêt du primaireReprise en secondes à minutes selon la basePool, contrôle de santé de la base, erreurs de parcours, heure du nouveau primaireÉcrivain ambigu, intégrité douteuse
Saturation de la baseCharge bornée sur le pool503 de délestage plutôt qu'une file sans finPool, file HTTP, taux de 503Saturation hors périmètre
Perte du cache externe (v1)Arrêt du cluster Infinispan d'un site/lb-check en erreur, trafic vers l'autre site, site dégradé jusqu'à resynchronisationSanté Infinispan, cibles, procédure de resynchronisationSite réadmis sans resynchronisation
Liaison intersite (v1)Coupure du réseau entre sitesSite marqué hors ligne, un site retiré du répartiteurDéclenchement de la mise à l'écart, statut des sitesDeux sites servant sans réplication
Perte d'un siteArrêt de tous les membres d'un siteBascule du répartiteur, moins de deux minutes dans la configuration testée v1Heure de détection, parcours sur le site survivantSite survivant déjà dégradé
Redémarrage completArrêt de tous les membresSessions persistées relues ; connexions en cours perduesNouvelle vue, sessions actives avant et aprèsSession persistée absente

Trois essais appellent une précision. La base : le guide CloudNativePG provoque la bascule par kubectl cnpg promote, note que les connexions vers le primaire sont coupées et annonce un retour attendu en moins d'une minute ; le contrôle de santé de la base, disponible avec les métriques, rend compte de l'état du pool, et l'essai vérifie que le répartiteur retire puis réadmet les membres. Le cache externe : en v1, la resynchronisation arrête Keycloak sur le site hors ligne, y coupe la réplication vers le site actif, vide les quatre caches, transfère l'état depuis le site actif, puis redémarre Keycloak ; elle se chronomètre en préproduction, car le transfert d'état complet charge le système. Le site rétabli : une modification de sécurité faite pendant son absence (client désactivé, secret tourné) doit y être vérifiée ; en v2, les données de royaume en cache n'expirent par défaut qu'au bout d'une heure.

Une campagne se rejoue après chaque changement de topologie, de version ou de base : un essai réussi ne vaut que pour la configuration testée.

Séquence d'un essai de panne et de ses preuves

Une référence mesurée avant l'injection, quatre familles de pannes, puis les mêmes parcours rejoués à travers le répartiteur et consignés pour décider d'accepter ou d'arrêter l'essai.

Schéma défilable horizontalement ; sa version textuelle complète suit.

Lire le schéma sous forme textuelle
  1. Avant toute injection, les parcours de contrôle établissent une référence horodatée dans le registre de preuves.
  2. Perte d'un pod ou d'un nœud : l'opérateur supprime un pod sans drainage ; la vue réduite (ISPN000094, vendor_cluster_size) et le retrait de la cible par le répartiteur sont consignés.
  3. Bascule ou perte de la base : l'opérateur promeut un réplica ou arrête le primaire ; le contrôle de santé de la base, les erreurs du pool, le nouveau primaire et l'heure de reprise sont consignés.
  4. Perte du cache externe en multi-cluster v1 : l'opérateur arrête le cluster Infinispan du site A ; /lb-check y passe en erreur ; le répartiteur dirige le trafic vers le site B ; les caches sont resynchronisés avant la réadmission du site A.
  5. Perte d'un site : l'opérateur arrête tous les membres du site A ; la bascule vers le site B et son heure de détection sont consignées.
  6. Dans tous les cas, les parcours sont rejoués à travers le répartiteur, qui ne doit répondre que par des membres prêts ; le registre permet alors d'accepter l'essai ou de l'arrêter selon les conditions fixées à l'avance.
Modèle explicatif, sans donnée client, d'après les tableaux de reprise et les procédures des guides High Availability de Keycloak 26.7.4.

Sauvegarder et restaurer : une procédure à éprouver

Ce qui se sauvegarde, et où

Les guides de Keycloak 26.7.4 confient la sauvegarde à la base de données ; l'export de royaume, dont les limites sont détaillées plus bas, n'en tient pas lieu. La base porte l'essentiel ; le reste vit dans d'autres systèmes de référence, qu'une restauration doit réunir dans le même état de version.

Éléments d'un déploiement Keycloak, système qui les porte et mode de sauvegarde
ÉlémentOù il vitMode de sauvegarde
Royaumes, clients, rôles, utilisateurs locaux, identifiants, sessions en ligne et hors ligneBaseSauvegarde physique et archivage continu des journaux de transactions, chiffrés
Registre de découverte jgroups_ping, clés et certificat du transport chiffréBaseInclus dans la sauvegarde de base, à traiter à la restauration
Image, extensions et thèmesRegistre d'images, dépôt de codeImage référencée par digest, extensions comprises
Options de démarrage, ressource Keycloak, déclarations de royaumeDépôt GitVersionnés ; voir l'article sur la configuration Keycloak pilotée en GitOps
Secrets de base, certificats TLS, coffreGestionnaire de secretsSauvegarde propre au gestionnaire
Annuaires fédérés, fournisseurs d'identité externesLeurs propres systèmesHors périmètre Keycloak
Caches embarqués ou externesMémoireAucune : état transitoire par nature

Le guide de base de données le rappelle : journaux de transactions (WAL) et sauvegardes contiennent les mêmes données sensibles que les fichiers principaux et doivent être chiffrés. Le blueprint CloudNativePG de Keycloak 26.7.4 illustre la chaîne : greffon Barman Cloud, stockage objet S3, chiffrement côté serveur AES256 des journaux et des données, sauvegarde planifiée dont la fréquence se règle sur l'objectif de point de reprise (RPO). Le même guide précise que cette configuration ne chiffre pas elle-même les sauvegardes et que le compartiment S3 doit l'être. Le guide de supervision associé expose l'horodatage de la dernière sauvegarde disponible et le premier point de restauration : deux métriques à alerter.

Procédure de restauration à éprouver

La procédure reprend les guides CloudNativePG de Keycloak 26.7.4 et y ajoute des contrôles propres à Keycloak. Elle s'exerce d'abord dans un espace de noms isolé.

  1. Fixer le point visé. Avant toute opération risquée, dont une montée de version, le guide recommande de noter l'horodatage UTC (date -u +"%Y-%m-%dT%H:%M:%SZ") ou l'identifiant de transaction visé.
  2. Restaurer la base. Créer un nouveau cluster amorcé depuis la sauvegarde, avec une cible temporelle ; comme dans le blueprint, il archive sous un nouveau nom de serveur pour ne pas écraser les sauvegardes d'origine. Restaurer sous le même nom de cluster impose de supprimer d'abord le cluster existant : c'est une décision de production, pas une étape d'exercice.
  3. Garder Keycloak arrêté jusqu'aux deux nettoyages suivants.
  4. Purger la découverte. La table jgroups_ping restaurée référence des instances disparues et retarde le démarrage, jusqu'à 20 secondes par défaut : le guide recommande de la vider.
  5. Trancher le sort des sessions. La restauration ressuscite les sessions ouvertes au point visé, y compris celles d'utilisateurs déconnectés depuis, ce que le guide qualifie de risque de sécurité. Trois options : vider les tables de sessions, supprimer les seules sessions ordinaires, ou accepter leur expiration naturelle.
  6. Redémarrer à l'identique. Même digest d'image, mêmes extensions, mêmes options ; vérifier la condition Ready, une vue ISPN000094 complète et ready sur chaque membre.
  7. Valider. Parcours de contrôle ; inventaire comparé des royaumes, clients et fournisseurs d'identité par l'API d'administration ; identifiants kid publiés par le point certs du royaume comparés à ceux d'avant l'incident, pour repérer une rotation de clés annulée par la restauration.
  8. Mesurer la durée réelle de reprise et la perte réelle de données : ce sont les chiffres du plan de reprise.
# Référence synthétique d'après le guide de restauration CloudNativePG, Keycloak 26.7.4
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: <CLUSTER_RESTAURE>
  namespace: <ESPACE_ISOLE>
spec:
  instances: 3
  storage:
    size: <TAILLE>
  bootstrap:
    recovery:
      source: source
      recoveryTarget:
        targetTime: "<HORODATAGE_UTC_RFC3339>"
  plugins:
    - name: barman-cloud.cloudnative-pg.io
      isWALArchiver: true
      parameters:
        barmanObjectName: <OBJECTSTORE_EXERCICE>
        serverName: <NOUVEAU_NOM_DE_SERVEUR>
  externalClusters:
    - name: source
      plugin:
        name: barman-cloud.cloudnative-pg.io
        parameters:
          barmanObjectName: <OBJECTSTORE_SOURCE>
          serverName: <SERVEUR_SOURCE>
-- Avant le premier démarrage de Keycloak sur la base restaurée
TRUNCATE jgroups_ping;

-- Option A : invalider toutes les sessions restaurées
TRUNCATE offline_client_session;
TRUNCATE offline_user_session;

-- Option B : supprimer les seules sessions ordinaires, garder les sessions hors ligne
DELETE FROM offline_client_session WHERE offline_flag = '0';
DELETE FROM offline_user_session WHERE offline_flag = '0';

Tout ce qui a changé après le point visé disparaît : compte désactivé, secret client tourné, fournisseur d'identité retiré. Des événements d'administration conservés hors de la base permettent de rejouer ces changements de sécurité. Les clés du transport chiffré, stockées en base, reviennent avec elle : un exercice sur la plus ancienne sauvegarde conservée vérifie aussi que le cluster se reforme avec ces clés.

Ce qu'il ne faut pas prendre pour une sauvegarde

  • Les caches. Ni l'Infinispan embarqué ni l'externe ne persistent quoi que ce soit ; en v1, un cache externe perdu se reconstruit par resynchronisation depuis l'autre site.
  • Les réplicas synchrones. Ils protègent de la perte d'un nœud de base, pas d'une écriture erronée, qu'ils répliquent aussitôt.
  • L'export de royaume. kc.sh export exclut les événements utilisateur et d'administration, les sessions persistées, l'état des workflows et les jetons révoqués, et sa cohérence n'est garantie que nœuds arrêtés. L'export partiel de la console omet les utilisateurs et masque les secrets. L'import avec --override, vrai par défaut, exige l'arrêt de tous les nœuds, car la commande ne rejoint pas le cluster de caches. L'export transporte une configuration ; il ne reprend pas une production.
  • Le dépôt Git. Il ne contient que les champs déclarés, jamais les utilisateurs, sessions ou secrets générés par le serveur.

Avant une montée de version

Les correctifs d'une même branche major.minor peuvent être déployés en mise à jour progressive : rolling-updates:v2 est actif par défaut et la stratégie Auto de l'opérateur lance une tâche de vérification de compatibilité, alors que la stratégie par défaut, RecreateOnImageChange, arrête le déploiement à chaque changement d'image. Sans opérateur, kc.sh update-compatibility check renvoie 0 si la mise à jour progressive est possible, 3 si une recréation est nécessaire, 4 si la fonctionnalité est désactivée. Un changement de version mineure reste une recréation. Le point de restauration se note avant l'opération ; la méthode complète d'une montée de version dépasse le cadre de cet article.

Sources officielles et limites de lecture

Les comportements décrits ont été vérifiés le contre les guides de Keycloak 26.7.4 (High Availability, serveur, opérateur, observabilité), contre les sources du serveur et de l'opérateur au tag 26.7.4, et contre la documentation Kubernetes pour l'arrêt des pods, les interruptions et les politiques réseau. Les manifestes sont dérivés des blueprints officiels et paramétrés.

Cette lecture a trois limites. Les délais de reprise et l'absence de perte de données cités viennent des configurations testées par le projet Keycloak (OpenShift sur AWS, Aurora PostgreSQL, Global Accelerator) : ni engagement ni prévision pour un autre environnement, qui doit produire ses propres mesures. Le multi-cluster v2 et la fonctionnalité stateless sont en préversion et peuvent changer d'une version à l'autre. Les charts Helm communautaires, les autres répartiteurs et les bases autres que PostgreSQL ne sont pas couverts, pas plus que les extensions, la méthode de montée de version ou le plan de reprise.

Si l'image, l'opérateur ou la base installés diffèrent de la version 26.7.4, les guides de cette version font foi et la matrice d'essais doit être rejouée. Pour organiser ces essais sur une plateforme existante, voir la page Mise en production Kubernetes : ouvrir par étapes.

Sources

  1. Keycloak 26.7.4, page de publication du 16/09/2026, GitHub keycloak/keycloak, https://github.com/keycloak/keycloak/releases/tag/26.7.4, consulté le 28/09/2026.
  2. Notes de version Keycloak 26.7.0, multi-cluster v2 en préversion, GitHub keycloak/keycloak, https://github.com/keycloak/keycloak/blob/26.7.4/docs/documentation/release_notes/topics/26_7_0.adoc, consulté le 28/09/2026.
  3. pom.xml au tag 26.7.4, propriété infinispan.version, GitHub keycloak/keycloak, https://github.com/keycloak/keycloak/blob/26.7.4/pom.xml, consulté le 28/09/2026.
  4. High availability overview, keycloak.org, https://www.keycloak.org/high-availability/introduction, consulté le 28/09/2026.
  5. Single-cluster deployments, keycloak.org, https://www.keycloak.org/high-availability/single-cluster/introduction, consulté le 28/09/2026.
  6. Concepts for single-cluster deployments, keycloak.org, https://www.keycloak.org/high-availability/single-cluster/concepts, consulté le 28/09/2026.
  7. Deploying Keycloak across multiple availability-zones with the Operator, keycloak.org, https://www.keycloak.org/high-availability/single-cluster/deploy-keycloak, consulté le 28/09/2026.
  8. Concepts for database connection pools, keycloak.org, https://www.keycloak.org/high-availability/single-cluster/concepts-database-connections, consulté le 28/09/2026.
  9. Deploying CloudNativePG with scheduled backups to S3, keycloak.org, https://www.keycloak.org/high-availability/single-cluster/deploy-cnpg-with-backup, consulté le 28/09/2026.
  10. Recovering a CloudNativePG cluster from an S3 backup, keycloak.org, https://www.keycloak.org/high-availability/single-cluster/deploy-cnpg-recovery, consulté le 28/09/2026.
  11. CloudNativePG switchover procedure, keycloak.org, https://www.keycloak.org/high-availability/single-cluster/operate-cnpg-switchover, consulté le 28/09/2026.
  12. Monitoring CloudNativePG, keycloak.org, https://www.keycloak.org/high-availability/single-cluster/monitoring-cnpg, consulté le 28/09/2026.
  13. Multi-cluster deployments (v1), keycloak.org, https://www.keycloak.org/high-availability/multi-cluster/introduction, consulté le 28/09/2026.
  14. Concepts for multi-cluster deployments, keycloak.org, https://www.keycloak.org/high-availability/multi-cluster/concepts, consulté le 28/09/2026.
  15. Building blocks multi-cluster deployments, keycloak.org, https://www.keycloak.org/high-availability/multi-cluster/building-blocks, consulté le 28/09/2026.
  16. Deploying Infinispan for HA with the Infinispan Operator, keycloak.org, https://www.keycloak.org/high-availability/multi-cluster/deploy-infinispan-kubernetes-crossdc, consulté le 28/09/2026.
  17. Deploying Keycloak for HA with the Operator (multi-cluster v1), keycloak.org, https://www.keycloak.org/high-availability/multi-cluster/deploy-keycloak-kubernetes, consulté le 28/09/2026.
  18. Deploying an AWS Lambda to disable a non-responding site, keycloak.org, https://www.keycloak.org/high-availability/multi-cluster/deploy-aws-accelerator-fencing-lambda, consulté le 28/09/2026.
  19. Synchronizing sites, keycloak.org, https://www.keycloak.org/high-availability/multi-cluster/operate-synchronize, consulté le 28/09/2026.
  20. Multi-cluster deployments (v2), keycloak.org, https://www.keycloak.org/high-availability/multi-cluster-v2/introduction, consulté le 28/09/2026.
  21. Concepts for multi-cluster deployments (v2), keycloak.org, https://www.keycloak.org/high-availability/multi-cluster-v2/concepts, consulté le 28/09/2026.
  22. Configuring distributed caches, keycloak.org, https://www.keycloak.org/server/caching, consulté le 28/09/2026.
  23. Enabling and disabling features, keycloak.org, https://www.keycloak.org/server/features, consulté le 28/09/2026.
  24. All configuration, option db-pool-max-size, keycloak.org, https://www.keycloak.org/server/all-config, consulté le 28/09/2026.
  25. Configuring a reverse proxy, keycloak.org, https://www.keycloak.org/server/reverseproxy, consulté le 28/09/2026.
  26. Tracking instance status with health checks, keycloak.org, https://www.keycloak.org/observability/health, consulté le 28/09/2026.
  27. Interface ClusterHealth au tag 26.7.4, GitHub keycloak/keycloak, https://github.com/keycloak/keycloak/blob/26.7.4/model/infinispan/src/main/java/org/keycloak/infinispan/health/ClusterHealth.java, consulté le 28/09/2026.
  28. Configuring the database, keycloak.org, https://www.keycloak.org/server/db, consulté le 28/09/2026.
  29. Importing and exporting realms, keycloak.org, https://www.keycloak.org/server/importExport, consulté le 28/09/2026.
  30. Checking if rolling updates are possible, keycloak.org, https://www.keycloak.org/server/update-compatibility, consulté le 28/09/2026.
  31. Avoiding downtime with rolling updates (Operator), keycloak.org, https://www.keycloak.org/operator/rolling-updates, consulté le 28/09/2026.
  32. Advanced configuration (Operator), keycloak.org, https://www.keycloak.org/operator/advanced-configuration, consulté le 28/09/2026.
  33. NetworkPolicy créée par l'opérateur au tag 26.7.4, GitHub keycloak/keycloak, https://github.com/keycloak/keycloak/blob/26.7.4/operator/src/main/java/org/keycloak/operator/controllers/KeycloakNetworkPolicyDependentResource.java, consulté le 28/09/2026.
  34. Ressources dépendantes du contrôleur de l'opérateur au tag 26.7.4, GitHub keycloak/keycloak, https://github.com/keycloak/keycloak/blob/26.7.4/operator/src/main/java/org/keycloak/operator/controllers/KeycloakController.java, consulté le 28/09/2026.
  35. Pod Lifecycle, termination of Pods, kubernetes.io, https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/, consulté le 28/09/2026.
  36. Disruptions, kubernetes.io, https://kubernetes.io/docs/concepts/workloads/pods/disruptions/, consulté le 28/09/2026.
  37. Network Policies, kubernetes.io, https://kubernetes.io/docs/concepts/services-networking/network-policies/, consulté le 28/09/2026.

Parlons de votre contexte.

Cet article expose une pratique générale ; votre situation a ses propres contraintes. Décrivez-la, nous répondons avec un périmètre.

Ouvrir le formulaire