Recopila registros de Keycloak

Compatible con:

En este documento, se explica cómo configurar Keycloak para enviar registros a Google Security Operations con webhooks.

Keycloak es una solución de administración de identidades y accesos (IAM) de código abierto que proporciona capacidades de inicio de sesión único (SSO), federación de usuarios, intermediación de identidades y acceso con redes sociales. Admite los protocolos OpenID Connect, OAuth 2.0 y SAML 2.0, y hace un seguimiento de los eventos del usuario (acceso, cierre de sesión, registro, cambios de contraseña) y los eventos del administrador (operaciones de administración de usuarios, clientes, dominios y roles) para la auditoría de seguridad.

Antes de comenzar

Asegúrate de cumplir con los siguientes requisitos previos:

  • Una instancia de Google SecOps
  • Una instancia de Keycloak en ejecución (se recomienda la versión 20 o posterior)
  • Acceso de administrador a la Consola de administración de Keycloak
  • Acceso al sistema de archivos o al contenedor del servidor de Keycloak para implementar extensiones
  • Acceso a la Google Cloud Console (para la creación de claves de API)

Crea un feed de webhook en Google SecOps

Crea el feed

  1. Ve a Configuración de SIEM > Feeds.
  2. Haz clic en Agregar feed nuevo.
  3. En la siguiente página, haz clic en Configurar un solo feed.
  4. En el campo Nombre del feed, ingresa un nombre para el feed (por ejemplo, Keycloak Events).
  5. Selecciona Webhook como el Tipo de origen.
  6. Selecciona Keycloak como el Tipo de registro.
  7. Haz clic en Siguiente.
  8. Especifica valores para los siguientes parámetros de entrada:
    • Delimitador de división (opcional): Ingresa \n para dividir eventos de varias líneas (cada POST de webhook contiene un solo evento, por lo que este campo se puede dejar vacío).
    • Espacio de nombres del recurso: Es el espacio de nombres del recurso.
    • Etiquetas de transferencia: Es la etiqueta que se aplicará a los eventos de este feed.
  9. Haz clic en Siguiente.
  10. Revisa la nueva configuración del feed en la pantalla Finalizar y, luego, haz clic en Enviar.

Genera y guarda la clave secreta

Después de crear el feed, debes generar una clave secreta para la autenticación:

  1. En la página de detalles del feed, haz clic en Generar clave secreta.
  2. Un diálogo muestra la clave secreta.
  3. Copia y guarda la clave secreta de forma segura.

Importante: La clave secreta solo se muestra una vez y no se puede recuperar más adelante. Si la pierdes, deberás generar una nueva.

Obtén la URL del extremo del feed

  1. Ve a la pestaña Detalles del feed.
  2. En la sección Endpoint Information, copia la URL del extremo del feed.
  3. El formato de la URL es el siguiente:

    https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate
    

    o

    https://<REGION>-malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate
    
  4. Guarda esta URL para los próximos pasos.

  5. Haz clic en Listo.

Crea una clave de API de Google Cloud

Chronicle requiere una clave de API para la autenticación. Crea una clave de API restringida en la Google Cloud Console.

Crea la clave de API

  1. Ve a la página Credenciales de la consola de Google Cloud.
  2. Selecciona tu proyecto (el proyecto asociado con tu instancia de Chronicle).
  3. Haz clic en Crear credenciales > Clave de API.
  4. Se creará una clave de API y se mostrará en un diálogo.
  5. Haz clic en Editar clave de API para restringir la clave.

Restringe la clave de API

  1. En la página de configuración de la clave de API, haz lo siguiente:
    • Nombre: Ingresa un nombre descriptivo (por ejemplo, Chronicle Webhook API Key).
  2. En Restricciones de API, haz lo siguiente:
    1. Selecciona Restringir clave.
    2. En el menú desplegable Seleccionar APIs, busca y selecciona Google SecOps API (o Chronicle API).
  3. Haz clic en Guardar.
  4. Copia el valor de la clave de API del campo Clave de API en la parte superior de la página.
  5. Guarda la clave de API de forma segura.

Habilita el almacenamiento de eventos en Keycloak

Antes de configurar la extensión de webhook, habilita el almacenamiento de eventos en Keycloak para que se generen eventos y estén disponibles para el reenvío.

Habilita los eventos de usuario

  1. Accede a la Consola del administrador de Keycloak.
  2. Selecciona el dominio que deseas supervisar en el menú desplegable de dominios que se encuentra en la esquina superior izquierda.
  3. Ve a Configuración del dominio > Eventos.
  4. Selecciona la pestaña secundaria Configuración de eventos de usuario.
  5. Habilita el botón de activación Guardar eventos.
  6. Establece el período de vencimiento (se recomienda un mínimo de 7 días).
  7. Haz clic en Guardar.

Habilita los eventos de administrador

  1. En la misma pestaña Eventos, selecciona la subpestaña Configuración de eventos de administrador.
  2. Habilita el botón de activación Guardar eventos.
  3. Habilita el botón de activación Incluir representación para capturar todos los detalles de los objetos modificados.
  4. Establece el período de vencimiento (se recomienda un mínimo de 7 días).
  5. Haz clic en Guardar.

Instala la extensión del objeto de escucha de eventos de webhook

Keycloak no incluye un objeto de escucha de eventos de webhook nativo. Instala la extensión keycloak-events de Phase Two (p2-inc) para habilitar la entrega de webhooks.

Descarga e implementa la extensión

  1. Descarga el archivo JAR de la versión más reciente desde la página de versiones de keycloak-events en Maven Central o compílalo desde la fuente:

    git clone https://github.com/p2-inc/keycloak-events.git
    cd keycloak-events
    mvn clean install
    
  2. Copia el archivo JAR grueso resultante en el directorio providers de Keycloak:

    cp target/keycloak-events-*.jar /opt/keycloak/providers/
    
  3. Vuelve a compilar y reiniciar Keycloak:

    /opt/keycloak/bin/kc.sh build
    /opt/keycloak/bin/kc.sh start
    

Habilita el objeto de escucha de eventos de webhook

  1. Accede a la Consola del administrador de Keycloak.
  2. Selecciona el dominio objetivo en el menú desplegable.
  3. Ve a Configuración del dominio > Eventos.
  4. En el menú desplegable Event listeners, selecciona ext-event-webhook.
  5. Haz clic en Guardar.

Configura el webhook de Keycloak

Construye la URL del webhook

  • Combina la URL del extremo de Chronicle y la clave de API:

    <ENDPOINT_URL>?key=<API_KEY>
    
  • Ejemplo:

    https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate?key=AIzaSyD...
    

Crea una suscripción a webhook a través de la API de REST de Keycloak

La extensión keycloak-events proporciona extremos de REST para administrar suscripciones a webhooks. Usa la API de REST de administrador de Keycloak para crear un webhook.

Paso 1: Obtén un token de acceso

  • Solicita un token de acceso a Keycloak con una cuenta de administrador:

    TOKEN=$(curl -sS -X POST "https://<KEYCLOAK_HOST>/realms/master/protocol/openid-connect/token" \
      -H "Content-Type: application/x-www-form-urlencoded" \
      --data-urlencode "grant_type=password" \
      --data-urlencode "client_id=admin-cli" \
      --data-urlencode "username=<ADMIN_USERNAME>" \
      --data-urlencode "password=<ADMIN_PASSWORD>" \
      | sed -n 's/.*"access_token":"\([^"]*\)".*/\1/p')
    

Reemplaza lo siguiente:

  • <KEYCLOAK_HOST>: El nombre de host y el puerto de tu servidor Keycloak (por ejemplo, keycloak.example.com:8443)
  • <ADMIN_USERNAME>: Tu nombre de usuario de administrador de Keycloak
  • <ADMIN_PASSWORD>: Tu contraseña de administrador de Keycloak

Paso 2: Crea el webhook

  • Envía una solicitud POST para crear la suscripción al webhook del dominio objetivo:

    curl -sS -X POST "https://<KEYCLOAK_HOST>/realms/<REALM_NAME>/webhooks" \
      -H "Authorization: Bearer ${TOKEN}" \
      -H "Content-Type: application/json" \
      -d '{
        "enabled": "true",
        "url": "<ENDPOINT_URL>?key=<API_KEY>&secret=<SECRET_KEY>",
        "secret": "<WEBHOOK_HMAC_SECRET>",
        "eventTypes": ["*"]
      }'
    

Reemplaza lo siguiente:

  • <KEYCLOAK_HOST>: Es el nombre de host de tu servidor Keycloak.
  • <REALM_NAME>: Es el nombre del dominio que se supervisará (por ejemplo, master o my-realm).
  • <ENDPOINT_URL>: Es la URL del extremo del feed de Chronicle que copiaste antes.
  • <API_KEY>: La clave de API de Google Cloud que creaste antes
  • <SECRET_KEY>: Es la clave secreta del webhook de Chronicle que se generó anteriormente.
  • <WEBHOOK_HMAC_SECRET>: Es una cadena secreta arbitraria para la firma HMAC de cargas útiles de webhook (por ejemplo, mySecretKey123).

Paso 3: Verifica el webhook

  • Para confirmar que se creó el webhook, enumera todos los webhooks del dominio:

    curl -sS -X GET "https://<KEYCLOAK_HOST>/realms/<REALM_NAME>/webhooks" \
      -H "Authorization: Bearer ${TOKEN}" \
      -H "Accept: application/json"
    

La respuesta devuelve una lista de objetos de webhook. Verifica que tu webhook aparezca con "enabled": "true" y la URL correcta.

Tipos de eventos de webhook

El campo eventTypes acepta un array de expresiones para filtrar los eventos que se envían:

  • *: Envía todos los eventos (recomendado para la integración de SIEM).
  • access.*: Envía todos los eventos de acceso
  • admin.*: Envía todos los eventos de administrador.
  • admin.USER-*: Envía todos los eventos de administrador relacionados con los usuarios.
  • admin-USER-CREATE: Envía solo eventos de administrador de creación de usuarios

Formato de la carga útil del webhook

  • El webhook envía eventos como solicitudes POST de HTTP con cargas útiles de JSON. Ejemplo de carga útil de evento del usuario:

    {
      "id": "987865-1a2b-3c4d-9876-654321abc",
      "time": 1767799710612,
      "type": "LOGIN",
      "realmId": "12345abcde-1a2b-4d3c-9876-abcd456",
      "clientId": "account-console",
      "userId": "abcd456-1234-5678-abc9-987gfed654",
      "sessionId": "efghij-9876-abcd-456-11223344",
      "ipAddress": "203.0.113.45",
      "details": {
        "auth_method": "openid-connect",
        "auth_type": "code",
        "redirect_uri": "https://app.example.com/callback",
        "consent": "no_consent_required",
        "username": "jdoe"
      }
    }
    

Comportamiento de reintentos de webhook

La extensión usa la retirada exponencial automática para los reintentos cuando se recibe una respuesta que no es 2xx:

Parámetro Valor predeterminado Descripción
backoffInitialInterval 500 ms Intervalo de reintento inicial
backoffMaxElapsedTime 900,000 ms (15 min) Tiempo total máximo de reintentos
backoffMaxInterval 180,000 ms (3 min) Intervalo máximo entre reintentos
backoffMultiplier 5 Multiplicador para cada intervalo de reintento
backoffRandomizationFactor 0.5 Factor de aleatorización para la fluctuación

Referencia de métodos de autenticación

Los feeds de webhook de Chronicle admiten varios métodos de autenticación. Elige el método que admite tu proveedor.

Si tu proveedor admite encabezados HTTP personalizados, usa este método para mejorar la seguridad.

  • Formato de la solicitud:

    POST <ENDPOINT_URL> HTTP/1.1
    Content-Type: application/json
    x-goog-chronicle-auth: <API_KEY>
    x-chronicle-auth: <SECRET_KEY>
    
    {
            "event": "data",
            "timestamp": "2025-01-15T10:30:00Z"
    }
    

Ventajas:

  • La clave y el secreto de la API no son visibles en la URL
  • Más seguro (los encabezados no se registran en los registros de acceso al servidor web)
  • Método preferido cuando el proveedor lo admite

Método 2: Parámetros de consulta

Si tu proveedor no admite encabezados personalizados, agrega credenciales a la URL.

  • Formato de URL:

    <ENDPOINT_URL>?key=<API_KEY>&secret=<SECRET_KEY>
    
  • Ejemplo:

    https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate?key=AIzaSyD...&secret=abcd1234...
    
  • Formato de la solicitud:

    POST <ENDPOINT_URL>?key=<API_KEY>&secret=<SECRET_KEY> HTTP/1.1
    Content-Type: application/json
    
    {
            "event": "data",
            "timestamp": "2025-01-15T10:30:00Z"
    }
    

Desventajas:

  • Credenciales visibles en la URL
  • Es posible que se registren en los registros de acceso del servidor web
  • Menos seguro que los encabezados

Método 3: Híbrido (URL + encabezado)

Algunas configuraciones usan la clave de API en la URL y la clave secreta en el encabezado.

  • Formato de la solicitud:

    POST <ENDPOINT_URL>?key=<API_KEY> HTTP/1.1
    Content-Type: application/json
    x-chronicle-auth: <SECRET_KEY>
    
    {
            "event": "data",
            "timestamp": "2025-01-15T10:30:00Z"
    }
    

Nombres de encabezados de autenticación

Chronicle acepta los siguientes nombres de encabezado para la autenticación:

Para la clave de API:

  • x-goog-chronicle-auth (recomendada)
  • X-Goog-Chronicle-Auth (no distingue mayúsculas de minúsculas)

Para la clave secreta, haz lo siguiente:

  • x-chronicle-auth (recomendada)
  • X-Chronicle-Auth (no distingue mayúsculas de minúsculas)

Límites y prácticas recomendadas para los Webhooks

Límites de solicitudes

Límite Valor
Tamaño máximo de la solicitud 4 MB
QPS máx. (consultas por segundo) 15,000
Tiempo de espera de la solicitud 30 segundos
Comportamiento de reintento Automática con retirada exponencial

Tabla de asignación de UDM

Campo de registro Asignación de UDM Lógica
payload.client_id additional.fields Se combinó con los campos creados a partir de payload.client_id y payload.realm_id.
payload.realm_id additional.fields
source_timestamp metadata.event_timestamp Se analizó con el filtro de fecha con los patrones ISO8601 y aaaa-MM-dd'T'HH:mm:ss.SSSZ.
payload.ip_address metadata.event_type Se establece en "STATUS_UPDATE" si payload.ip_address no está vacío; de lo contrario, se establece en "USER_UNCATEGORIZED" si uuid no está vacío o en "GENERIC_EVENT".
uuid metadata.event_type
payload.type metadata.product_event_type Valor copiado directamente
payload.session_id network.session_id Valor copiado directamente
payload.ip_address principal.ip Valor copiado directamente
source_metadata.schema principal.resource.attribute.labels Se fusionó con las etiquetas creadas a partir de source_metadata.schema, source_metadata.table, source_metadata.is_deleted (convertido a cadena), source_metadata.change_type, source_metadata.tx_id y source_metadata.lsn.
source_metadata.table principal.resource.attribute.labels
source_metadata.is_deleted principal.resource.attribute.labels
source_metadata.change_type principal.resource.attribute.labels
source_metadata.tx_id principal.resource.attribute.labels
source_metadata.lsn principal.resource.attribute.labels
uuid principal.user.userid Valor copiado directamente
objeto security_result.detection_fields Se combinó con las etiquetas creadas a partir de object, read_method y payload.id.
read_method security_result.detection_fields
payload.id security_result.detection_fields
redirect_uri target.url Valor copiado directamente
nombre de usuario target.user.userid Valor copiado directamente
metadata.product_name metadata.product_name Se establece en "KEYCLOAK".
metadata.vendor_name metadata.vendor_name Se establece en "KEYCLOAK".
username" from "details_json target.user.userid Se asignó desde el registro de cambios
redirect_uri" from "details_json target.url Se asignó desde el registro de cambios
realm_id" and "client_id additional.fields Se asignó desde el registro de cambios

Registro de cambios

Consulta el registro de cambios de este analizador

¿Necesitas más ayuda? Obtén respuestas de miembros de la comunidad y profesionales de Google SecOps.