Saltar a contenido

Incident Response

Este runbook define el proceso de respuesta a incidentes de la plataforma de identidad. Un incidente es cualquier evento que afecte la disponibilidad, integridad o seguridad de la plataforma.

Severidades

Severidad Descripción Ejemplos Tiempo de respuesta
P1 — Crítico Plataforma completamente inaccesible o compromiso de seguridad activo Keycloak caído, DB corrompida, credenciales comprometidas 15 minutos
P2 — Alto Funcionalidad parcial degradada, sin workaround Logins fallando intermitentemente, latencia >5s 1 hora
P3 — Medio Funcionalidad reducida con workaround disponible Admin Console inaccesible, backup fallido 4 horas (horario laboral)
P4 — Bajo Impacto mínimo, cosmético o de rendimiento Slow queries, dashboard sin datos Próximo sprint

Checklist de primera respuesta (P1/P2)

1. [ ] Confirmar el incidente (no es una alerta falsa)
2. [ ] Notificar al equipo (Slack #incidents + responsable de guardia)
3. [ ] Abrir un ticket con: hora inicio, síntomas, impacto estimado
4. [ ] Comenzar diagnóstico (ver árbol de decisión)
5. [ ] Actualizar el ticket cada 15 minutos con el estado
6. [ ] Resolver o escalar según el árbol de decisión
7. [ ] Confirmar resolución con smoke tests
8. [ ] Notificar resolución al equipo
9. [ ] Programar post-mortem (P1) o registrar lecciones (P2)

Árbol de diagnóstico

flowchart TD
    A[Incidente detectado] --> B{Health checks}
    B -->|Keycloak /health/ready falla| C[Problema en Keycloak]
    B -->|PostgreSQL no responde| D[Problema en DB]
    B -->|Traefik no responde| E[Problema de red/edge]
    B -->|Todo OK pero logins fallan| F[Problema de configuración]

    C --> C1{Logs de Keycloak}
    C1 -->|OOM / OutOfMemory| C2[Aumentar memory limits\n ver compose.yml]
    C1 -->|DB connection failed| D
    C1 -->|Startup crash| C3[Ver error en logs\n docker logs keycloak]

    D --> D1{Estado del contenedor}
    D1 -->|Running pero no acepta conexiones| D2[pg_isready falla\n Revisar logs postgres]
    D1 -->|Crashed / Restarting| D3[Restaurar desde backup\n ver restore.md]

    E --> E1{Certificados TLS}
    E1 -->|Expirado| E2[Renovar certificado\n docker restart traefik]
    E1 -->|OK| E3[Revisar reglas UFW\n Revisar Traefik logs]

    F --> F1[Revisar eventos de Keycloak\n Admin Console → Events]

Comandos de diagnóstico rápido

# Estado general de todos los contenedores
docker compose ps

# Logs de Keycloak (últimas 100 líneas)
docker compose logs --tail=100 keycloak

# Logs de PostgreSQL
docker compose logs --tail=50 postgres

# Logs de Traefik
docker compose logs --tail=50 traefik

# Health checks
curl -sf http://localhost:8080/health/ready | jq .
curl -sf http://localhost:8080/health/live | jq .

# Verificar conectividad DB desde Keycloak
docker compose exec keycloak \
  /bin/sh -c "nc -zv postgres 5432 && echo 'DB alcanzable'"

# Uso de recursos
docker stats --no-stream

# Espacio en disco
df -h /var/lib/docker

Escenarios comunes y solución

Keycloak no arranca

# Ver el error específico
docker compose logs keycloak | grep -E "ERROR|FATAL|Exception"

# Problema frecuente: DB no disponible al arrancar
docker compose up -d postgres
sleep 10
docker compose up -d keycloak

# Problema: puerto 8080 ocupado
netstat -tlnp | grep 8080

Logins fallan — error de certificado

# Verificar fecha de expiración del certificado
echo | openssl s_client -connect auth.example.com:443 2>/dev/null | \
  openssl x509 -noout -dates

# Forzar renovación de Let's Encrypt
docker compose restart traefik
# Traefik renueva automáticamente si el cert expira en < 30 días

Logins fallan — error de credenciales de usuario

# Verificar en Admin Console → Events → LOGIN_ERROR
# O via API:
ADMIN_TOKEN=$(curl -s -X POST "http://localhost:8080/realms/master/protocol/openid-connect/token" \
  -d "grant_type=password&client_id=admin-cli&username=${KC_ADMIN}&password=${KC_ADMIN_PASSWORD}" | \
  jq -r '.access_token')

curl -s -H "Authorization: Bearer ${ADMIN_TOKEN}" \
  "http://localhost:8080/admin/realms/realm-internal/events?type=LOGIN_ERROR&max=10" | \
  jq '.[] | {time: .time, error: .error, username: .details.username}'

Base de datos llena

# Verificar espacio
df -h /var/lib/docker/volumes/

# Tamaño de la DB de Keycloak
docker compose exec postgres \
  psql -U "${KC_DB_USER}" -c "\l+"

# Limpiar sesiones expiradas (Keycloak lo hace automáticamente, pero se puede forzar)
docker compose exec postgres \
  psql -U "${KC_DB_USER}" -d "${KC_DB_NAME}" \
  -c "DELETE FROM offline_client_session WHERE expiration < EXTRACT(EPOCH FROM NOW())::bigint;"

Post-mortem (para P1)

El post-mortem se realiza dentro de las 48 horas siguientes a la resolución de un P1.

Estructura: - Fecha y duración del incidente - Impacto (usuarios afectados, servicios degradados) - Timeline (cuándo se detectó, cuándo se notificó, cuándo se resolvió) - Causa raíz (Root Cause Analysis — 5 Whys) - Acciones correctivas (qué se hará para prevenir la recurrencia) - Acciones de mejora (qué se hará para detectar/responder más rápido)

Sin culpables en el post-mortem

El post-mortem es un ejercicio de aprendizaje, no de culpabilización. El objetivo es mejorar los sistemas y procesos, no señalar a personas.