Coletar registros do Keycloak

Compatível com:

Este documento explica como configurar o Keycloak para enviar registros ao Google Security Operations usando webhooks.

O Keycloak é uma solução de gerenciamento de identidade e acesso (IAM) de código aberto que oferece logon único (SSO), federação de usuários, intermediação de identidade e recursos de login social. Ele é compatível com os protocolos OpenID Connect, OAuth 2.0 e SAML 2.0 e rastreia eventos de usuário (login, logout, registro, mudanças de senha) e de administrador (operações de gerenciamento de usuários, clientes, realms e papéis) para auditoria de segurança.

Antes de começar

Verifique se você atende aos seguintes pré-requisitos:

  • Uma instância do Google SecOps
  • Uma instância do Keycloak em execução (versão 20 ou mais recente recomendada)
  • Acesso de administrador ao Admin Console do Keycloak
  • Acesso ao sistema de arquivos ou contêiner do servidor Keycloak para implantar extensões
  • Acesso ao console do Google Cloud (para criar chaves de API)

Criar feed de webhook no Google SecOps

Criar o feed

  1. Acesse Configurações > Gerenciamento de dados > Feeds. Se você estiver em uma plataforma somente SIEM, acesse Configurações > Feeds.
  2. Clique em Adicionar novo feed.
  3. Na página seguinte, clique em Configurar um único feed.
  4. No campo Nome do feed, insira um nome para o feed (por exemplo, Keycloak Events).
  5. Selecione Webhook como o Tipo de origem.
  6. Selecione Keycloak como o Tipo de registro.
  7. Clique em Próxima.
  8. Especifique valores para os seguintes parâmetros de entrada:
    • Delimitador de divisão (opcional): insira \n para dividir eventos de várias linhas (cada POST de webhook contém um único evento, então esse campo pode ser deixado em branco).
    • Namespace do recurso: o namespace do recurso
    • Rótulos de ingestão: o rótulo que será aplicado aos eventos desse feed.
  9. Clique em Próxima.
  10. Revise a configuração do novo feed na tela Finalizar e clique em Enviar.

Gerar e salvar a chave secreta

Depois de criar o feed, gere uma chave secreta para autenticação:

  1. Na página de detalhes do feed, clique em Gerar chave secreta.
  2. Uma caixa de diálogo mostra a chave secreta.
  3. Copie e salve a chave secreta com segurança.

Importante: a chave secreta é exibida apenas uma vez e não pode ser recuperada depois. Se você perder a chave, será necessário gerar outra.

Encontrar o URL do endpoint do feed

  1. Acesse a guia Detalhes do feed.
  2. Na seção Informações do endpoint, copie o URL do endpoint do feed.
  3. O formato do URL é:

    https://{region}-chronicle.googleapis.com/v1/{parent}/logs:import
    

    Em que {region} é a região da sua instância do Google SecOps (por exemplo, us, europe ou asia-southeast1) e {parent} é o caminho do recurso no formato projects/<PROJECT_ID>/locations/<LOCATION>/instances/<INSTANCE_ID>/logTypes/<LOG_TYPE>.

  4. Salve esse URL para as próximas etapas.

  5. Clique em Concluído.

Criar uma chave de API do Google Cloud

O Chronicle requer uma chave de API para autenticação. Crie uma chave de API restrita no console do Google Cloud.

Criar a chave de API

  1. Acesse a página "Credenciais" do console do Google Cloud.
  2. Selecione seu projeto (associado à instância do Chronicle).
  3. Clique em Criar credenciais > Chave de API.
  4. Uma chave de API é criada e exibida em uma caixa de diálogo.
  5. Clique em Editar chave de API para restringir a chave.

Restringir a chave de API

  1. Na página de configurações da chave de API:
    • Nome: insira um nome descritivo (por exemplo, Chronicle Webhook API Key).
  2. Em Restrições de API:
    1. Selecione Restringir chave.
    2. No menu suspenso Selecionar APIs, pesquise e selecione API Google SecOps (ou API Chronicle).
  3. Clique em Salvar.
  4. Copie o valor da chave de API do campo Chave de API na parte de cima da página.
  5. Salve a chave de API com segurança.

Ativar o armazenamento de eventos no Keycloak

Antes de configurar a extensão de webhook, ative o armazenamento de eventos no Keycloak para que os eventos sejam gerados e disponibilizados para encaminhamento.

Ativar eventos de usuário

  1. Faça login no Admin Console do Keycloak.
  2. Selecione o realm que você quer monitorar no menu suspenso no canto superior esquerdo.
  3. Acesse Realm Settings > Events.
  4. Selecione a subguia Configurações de eventos do usuário.
  5. Ative a opção Salvar eventos.
  6. Defina o período de Validade (mínimo recomendado: 7 dias).
  7. Clique em Salvar.

Ativar eventos de administrador

  1. Na mesma guia Eventos, selecione a subguia Configurações de eventos de administrador.
  2. Ative a opção Salvar eventos.
  3. Ative a opção Incluir representação para capturar todos os detalhes dos objetos alterados.
  4. Defina o período de Validade (mínimo recomendado: 7 dias).
  5. Clique em Salvar.

Instalar a extensão do listener de eventos de webhook

O Keycloak não inclui um listener de eventos de webhook nativo. Instale a extensão keycloak-events da Phase Two (p2-inc) para ativar a entrega de webhooks.

Fazer o download e implantar a extensão

  1. Faça o download do JAR da versão mais recente na página de versões do keycloak-events no Maven Central ou crie usando o código-fonte:

    git clone https://github.com/p2-inc/keycloak-events.git
    cd keycloak-events
    mvn clean install
    
  2. Copie o arquivo JAR fat resultante para o diretório providers do Keycloak:

    cp target/keycloak-events-*.jar /opt/keycloak/providers/
    
  3. Recrie e reinicie o Keycloak:

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

Ativar o listener de eventos do webhook

  1. Faça login no Admin Console do Keycloak.
  2. Selecione o realm de destino no menu suspenso.
  3. Acesse Realm Settings > Events.
  4. No menu suspenso Listeners de eventos, selecione ext-event-webhook.
  5. Clique em Salvar.

Configurar o webhook do Keycloak

Criar o URL do webhook

  • Combine o URL do endpoint do Chronicle e a chave de API:

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

    https://{region}-chronicle.googleapis.com/v1/{parent}/logs:import?key=AIzaSyD...
    

Criar uma assinatura de webhook usando a API REST do Keycloak

A extensão keycloak-events fornece endpoints REST para gerenciar assinaturas de webhook. Use a API REST de administrador do Keycloak para criar um webhook.

Etapa 1: receber um token de acesso

  • Solicite um token de acesso do Keycloak usando uma conta 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')
    

Substitua:

  • <KEYCLOAK_HOST>: o nome do host e a porta do servidor do Keycloak (por exemplo, keycloak.example.com:8443)
  • <ADMIN_USERNAME>: seu nome de usuário de administrador do Keycloak
  • <ADMIN_PASSWORD>: sua senha de administrador do Keycloak

Etapa 2: criar o webhook

  • Envie uma solicitação POST para criar a assinatura do webhook para o realm de destino:

    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": ["*"]
      }'
    

Substitua:

  • <KEYCLOAK_HOST>: o nome do host do servidor do Keycloak.
  • <REALM_NAME>: o nome do realm a ser monitorado (por exemplo, master ou my-realm)
  • <ENDPOINT_URL>: o URL do endpoint do feed do Chronicle copiado anteriormente.
  • <API_KEY>: a chave de API do Google Cloud criada anteriormente.
  • <SECRET_KEY>: a chave secreta do webhook do Chronicle gerada anteriormente.
  • <WEBHOOK_HMAC_SECRET>: uma string secreta arbitrária para assinatura HMAC de payloads de webhook (por exemplo, mySecretKey123)

Etapa 3: verificar o webhook

  • Confirme se o webhook foi criado listando todos os webhooks do realm:

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

A resposta retorna uma lista de objetos de webhook. Verifique se o webhook aparece com "enabled": "true" e o URL correto.

Tipos de evento de webhook

O campo eventTypes aceita uma matriz de expressões para filtrar quais eventos são enviados:

  • *: envia todos os eventos (recomendado para integração com SIEM)
  • access.*: envia todos os eventos de acesso.
  • admin.*: envia todos os eventos de administrador.
  • admin.USER-*: envia todos os eventos de administrador relacionados aos usuários.
  • admin-USER-CREATE: envia apenas eventos de administrador de criação de usuários.

Formato do payload do webhook

  • O webhook envia eventos como solicitações POST HTTP com payloads JSON. Exemplo de payload de evento do usuário:

    {
      "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"
      }
    }
    

Comportamento de nova tentativa do webhook

A extensão usa a espera exponencial automática para novas tentativas quando uma resposta não 2xx é recebida:

Parâmetro Valor padrão Descrição
backoffInitialInterval 500 ms Intervalo inicial de nova tentativa
backoffMaxElapsedTime 900.000 ms (15 min) Tempo total máximo de novas tentativas
backoffMaxInterval 180.000 ms (3 min) Intervalo máximo entre novas tentativas
backoffMultiplier 5 Multiplicador para cada intervalo de nova tentativa
backoffRandomizationFactor 0,5 Fator de randomização para instabilidade

Referência de métodos de autenticação

Os feeds de webhook do Chronicle são compatíveis com vários métodos de autenticação. Escolha o método compatível com seu fornecedor.

Se o fornecedor for compatível com cabeçalhos HTTP personalizados, use esse método para melhorar a segurança.

  • Formato da solicitação:

    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"
    }
    

Vantagens:

  • Chave de API e secret não visíveis no URL
  • Mais seguro (os cabeçalhos não são registrados nos registros de acesso do servidor da Web)
  • Método preferencial quando o fornecedor oferece suporte

Método 2: parâmetros de consulta

Se o fornecedor não for compatível com cabeçalhos personalizados, adicione as credenciais ao final do URL.

  • Formato do URL:

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

    https://{region}-chronicle.googleapis.com/v1/{parent}/logs:import?key=AIzaSyD...&secret=abcd1234...
    
  • Formato da solicitação:

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

Desvantagens:

  • Credenciais visíveis no URL
  • Podem ser registrados nos registros de acesso do servidor da Web
  • Menos seguro do que os cabeçalhos

Método 3: híbrido (URL + cabeçalho)

Algumas configurações usam a chave de API no URL e a chave secreta no cabeçalho.

  • Formato da solicitação:

    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"
    }
    

Nomes dos cabeçalhos de autenticação

O Chronicle aceita os seguintes nomes de cabeçalho para autenticação:

Para a chave de API:

  • x-goog-chronicle-auth (recomendado)
  • X-Goog-Chronicle-Auth (não diferencia maiúsculas de minúsculas)

Para a chave secreta:

  • x-chronicle-auth (recomendado)
  • X-Chronicle-Auth (não diferencia maiúsculas de minúsculas)

Limites e práticas recomendadas de webhooks

Limites de solicitações

Limite Valor
Tamanho máximo da solicitação 4 MB
QPS máximo (consultas por segundo) 15.000
Tempo limite da solicitação 30 segundos
Comportamento de nova tentativa Automática com espera exponencial

Tabela de mapeamento de UDM

Campo de registro Mapeamento de UDM Lógica
payload.client_id additional.fields Mesclado com campos criados de payload.client_id, payload.realm_id
payload.realm_id additional.fields
source_timestamp metadata.event_timestamp Analisado usando o filtro de data com os padrões ISO8601 e yyyy-MM-dd'T'HH:mm:ss.SSSZ
payload.ip_address metadata.event_type Defina como "STATUS_UPDATE" se payload.ip_address não estiver vazio. Caso contrário, defina como "USER_UNCATEGORIZED" se uuid não estiver vazio. Caso contrário, defina como "GENERIC_EVENT".
uuid metadata.event_type
payload.type metadata.product_event_type Valor copiado diretamente
payload.session_id network.session_id Valor copiado diretamente
payload.ip_address principal.ip Valor copiado diretamente
source_metadata.schema principal.resource.attribute.labels Mesclado com rótulos criados de source_metadata.schema, source_metadata.table, source_metadata.is_deleted (convertido em string), source_metadata.change_type, source_metadata.tx_id, 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 diretamente
objeto security_result.detection_fields Mesclado com rótulos criados de object, read_method, payload.id
read_method security_result.detection_fields
payload.id security_result.detection_fields
redirect_uri target.url Valor copiado diretamente
nome de usuário target.user.userid Valor copiado diretamente
metadata.product_name metadata.product_name Defina como "KEYCLOAK".
metadata.vendor_name metadata.vendor_name Defina como "KEYCLOAK".
username" from "details_json target.user.userid Mapeado do registro de alterações
redirect_uri" from "details_json target.url Mapeado do registro de alterações
realm_id" and "client_id additional.fields Mapeado do registro de alterações

Registro de alterações

Confira o registro de alterações deste analisador

Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais do Google SecOps.