Recuperación ante fallos en Keycloak: qué se rompe y cómo arreglarlo
Una guía práctica de escenarios de recuperación en Keycloak: split-brain en Infinispan, secuencias de base de datos corruptas, migraciones atascadas, sesiones huérfanas y trust stores rotos.
- Keycloak
- Security
- Operations
- Reliability
Todo el mundo escribe sobre cómo configurar Keycloak HA. Pocos escriben sobre qué ocurre cuando la propia HA se rompe. El cluster se parte, la secuencia de la base de datos salta, una migración se queda atascada, o los certificados expiran por la noche y nadie se da cuenta hasta que los usuarios no pueden iniciar sesión.
Esta es la guía pragmática de recuperación — seis escenarios reales que me he encontrado, cómo se ven en los logs y cómo arreglarlos sin entrar en pánico.
Escenario 1: split-brain en Infinispan
Un split-brain ocurre cuando los nodos del cluster pierden conectividad de red entre sí pero siguen siendo accesibles para los clientes. JGroups detecta la partición y forma clusters separados, cada uno creyéndose el grupo autoritario.
Síntomas:
- Los logs muestran
JGroups: MERGE eventofailed to receive response fromseguido de direcciones de nodo. - Diferentes nodos reportan diferentes tamaños de cluster en los logs de
org.jgroups.protocols. - Los usuarios reportan fallos de autenticación intermitentes — a veces funciona, a veces no, según qué «cluster» maneje la petición.
Recuperación:
- Detén el tráfico de clientes en el balanceador. Bloquea todos los nodos.
- Elige un nodo como «fuente de verdad». Normalmente es el nodo con los datos de sesión más recientes, pero en la práctica la base de datos tiene el estado definitivo.
- Reinicia los nodos restantes uno a uno, permitiendo que cada uno se reúna con el primero limpiamente vía JGroups TCPPing.
- Monitoriza los logs de
viewAcceptedhasta que todos los nodos reporten el mismo ID de vista y el mismo número de miembros. - Restaura el tráfico.
Si las sesiones se sienten obsoletas después de la recuperación, limpia la caché de Infinispan desde la consola de administración de Keycloak. Esto fuerza a todos los nodos a recargar desde la base de datos.
Escenario 2: secuencias de base de datos corruptas
Keycloak usa secuencias de base de datos para EVENT_ENTITY, USER_SESSION y otras tablas de alto tráfico. Si una secuencia se desincroniza — normalmente durante una migración fallida o un reinicio sucio de nodo — las inserciones empiezan a fallar con duplicate key value violates unique constraint.
Síntomas:
- Errores en el log como
ERROR: duplicate key value violates unique constraintdurante login o refresco de token. - La tabla afectada tiene un salto o duplicado en su secuencia de clave primaria.
Recuperación:
Encuentra el max ID actual y reinicia la secuencia. Para Postgres:
SELECT setval(''event_entity_seq'', COALESCE((SELECT MAX(id) FROM event_entity), 1));
Ejecuta esto para cada secuencia que muestre violaciones de restricción. Las secuencias se llaman xxx_seq. Comprueba event_entity_seq, user_session_seq y resource_server_seq como puntos de partida.
Escenario 3: migración atascada
Keycloak usa Flyway para las migraciones de base de datos. En un cluster multi-nodo, solo un nodo debe ejecutar migraciones. Los demás esperan. Si el nodo migrador se cae a mitad de migración, o si todos los nodos arrancan simultáneamente y compiten por los locks de Flyway, la migración se puede atascar.
Síntomas:
- Los nodos fallan al arrancar con
FlywayException: Found non-empty schema without schema history tableoMigration checksum mismatch. - La tabla
flyway_schema_historytiene migraciones aplicadas parcialmente, o una migración marcada como running que nunca completó.
Recuperación:
- Comprueba
flyway_schema_history:SELECT * FROM flyway_schema_history ORDER BY installed_rank; - Si una migración está atascada en estado «running» (
success = 0), verifica manualmente si el SQL se aplicó. Si es así, márcala como exitosa:UPDATE flyway_schema_history SET success = TRUE WHERE version = 'X.Y.Z'; - Si la migración se aplicó parcialmente, puede que necesites revertir los cambios incompletos manualmente.
- Reinicia un solo nodo y verifica que la migración pasa. Luego arranca los nodos restantes.
Escenario 4: sesiones huérfanas y tokens offline huérfanos
Cuando un nodo muere de forma no controlada, sus sesiones en caché se pierden. La base de datos sigue teniendo registros de esas sesiones, pero apuntan a un nodo que ya no existe.
Síntomas:
- Los usuarios reportan errores de «sesión expirada» o «logout fallido» incluso con tokens válidos.
- La tabla
OFFLINE_USER_SESSIONoUSER_SESSIONtiene filas apuntando a un nodo muerto.
Recuperación:
- Usa la API de administración de Keycloak:
DELETE /admin/realms/{realm}/sessions?type=offline - Para una limpieza más profunda, consulta la base de datos directamente. Elimina sesiones huérfanas de
OFFLINE_USER_SESSION. - Después de la limpieza, limpia la caché de Infinispan.
- Los usuarios con tokens válidos necesitarán re-autenticarse la próxima vez que hagan una petición que requiera comprobación de sesión. Es normal tras un fallo no controlado.
Escenario 5: trust store o keystore roto
Keycloak es exigente con TLS. Si un certificado expira, o si un keystore se rota incorrectamente, el nodo puede no arrancar o rechazar conexiones válidas.
Síntomas:
- El nodo no arranca con
java.security.KeyStoreExceptionojavax.net.ssl.SSLHandshakeException. - La federación con proveedores de identidad deja de funcionar con
SSLHandshakeException: PKIX path building failed.
Recuperación:
- Verifica el keystore:
keytool -list -keystore keycloak.jks. Comprueba fechas de expiración y nombres de alias. - Si el certificado expiró, genera uno nuevo y actualiza el keystore. Keycloak necesita reiniciarse para recoger cambios.
- Para certificados de terceros confiados, impórtalos en el trust store de Java:
keytool -import -alias idp -keystore cacerts -file idp-cert.pem. - Prueba con
openssl s_client -connect idp.example.com:443desde el host de Keycloak para descartar problemas de TLS a nivel de red.
Escenario 6: el cluster simplemente no se forma
Este es el escenario más frustrante. Arrancas el segundo nodo, miras los logs, y se queda ahí. Sin cambio de vista, sin transferencia de estado, sin errores — nada.
Causas comunes:
- Bind address incorrecto. JGroups se vincula a la primera interfaz disponible. Si es
127.0.0.1, los nodos no se ven. Configurajboss.bind.address.privatecon la IP correcta. - Firewall bloqueando puertos de JGroups. JGroups usa el puerto 7600 (UDP) o 7800 (TCP) por defecto. En cloud, los grupos de seguridad suelen bloquearlos.
- Multicast deshabilitado. Muchos proveedores cloud no soportan multicast. Si usas UDP multicast y no funciona, cambia a TCPPing o DNS_PING.
- Configuración de Infinispan incompatible. Si los nodos usan configuraciones de caché diferentes, no formarán cluster. Compara
standalone-ha.xmlentre nodos.
Herramientas de diagnóstico:
jgroups-diag— una herramienta de diagnóstico independiente que prueba descubrimiento y membresía fuera de Keycloak.- Infinispan CLI — conéctate a un endpoint de Infinispan vía JMX e inspecciona la vista del cluster.
- API de administración de Keycloak → Server Info → System → muestra los miembros actuales del cluster.
- Kubernetes: usa
kubectl execen cada pod y comprueba los puertos de escucha.
Prevención: el runbook de recuperación
El artefacto más valioso que puedes crear para tu cluster de Keycloak no es otro dashboard de monitorización. Es un runbook de recuperación que cubra cada escenario anterior, con comandos exactos, consultas SQL y llamadas API.
Cosas que incluir:
- Credenciales de base de datos y cadenas de conexión para acceso SQL directo.
- Las consultas
UPDATEySELECTexactas para reparación de secuencias y limpieza de sesiones. - Rutas y contraseñas de keystores.
- Acceso de administración al balanceador para corte de tráfico.
- El orden de reinicio y el tamaño de vista esperado tras cada reinicio.
La HA de Keycloak no es magia. Es entender su modelo de estado y tener un plan para cuando ese modelo se rompa. Los nodos fallarán, la red se partirá y los certificados expirarán. La diferencia entre un mal día y uno catastrófico es si has probado el camino de recuperación antes de necesitarlo.