Coletar registros do Keycloak
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 recursos de logon único (SSO), federação de usuários, corretagem de identidade e login social. Ele oferece suporte aos protocolos OpenID Connect, OAuth 2.0 e SAML 2.0 e rastreia eventos de usuários (login, logout, registro, mudanças de senha) e de administradores (operações de gerenciamento de usuários, clientes, domínios e funções) 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 (recomendamos a versão 20 ou mais recente)
- 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 criação de chaves de API)
Criar um feed de webhook no Google SecOps
Criar o feed
- Acesse Configurações do SIEM > Feeds.
- Clique em Adicionar novo feed.
- Na próxima página, clique em Configurar um único feed.
- No campo Nome do feed, insira um nome para o feed (por exemplo,
Keycloak Events). - Selecione Webhook como o Tipo de origem.
- Selecione Keycloak como o Tipo de registro.
- Clique em Próxima.
- Especifique valores para os seguintes parâmetros de entrada:
- Delimitador de divisão (opcional): insira
\npara dividir eventos de várias linhas. Cada POST de webhook contém um único evento, então esse campo pode ficar vazio. - Namespace do recurso: o namespace do recurso
- Rótulos de ingestão: o rótulo a ser aplicado aos eventos deste feed
- Delimitador de divisão (opcional): insira
- Clique em Próxima.
- Revise a nova configuração do 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:
- Na página de detalhes do feed, clique em Gerar chave secreta.
- Uma caixa de diálogo mostra a chave secreta.
- 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.
Receber o URL do endpoint do feed
- Acesse a guia Detalhes do feed.
- Na seção Informações do endpoint, copie o URL do endpoint do feed.
O formato do URL é:
https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreateou
https://<REGION>-malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreateSalve esse URL para as próximas etapas.
Clique em Concluído.
Criar chave de API do Google Cloud
O Chronicle exige uma chave de API para autenticação. Crie uma chave de API restrita no console do Google Cloud.
Criar a chave de API
- Acesse a página "Credenciais" do console do Google Cloud.
- Selecione seu projeto (o projeto associado à sua instância do Chronicle).
- Clique em Criar credenciais > Chave de API.
- Uma chave de API é criada e mostrada em uma caixa de diálogo.
- Clique em Editar chave de API para restringir a chave.
Restringir a chave de API
- Na página de configurações da chave de API:
- Nome: insira um nome descritivo, por exemplo,
Chronicle Webhook API Key.
- Nome: insira um nome descritivo, por exemplo,
- Em Restrições de API:
- Selecione Restringir chave.
- No menu suspenso Selecionar APIs, pesquise e selecione API Google SecOps (ou API Chronicle).
- Clique em Salvar.
- Copie o valor da chave de API do campo Chave de API na parte de cima da página.
- 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 eles sejam gerados e estejam disponíveis para encaminhamento.
Ativar eventos do usuário
- Faça login no Admin Console do Keycloak.
- Selecione o realm que você quer monitorar no menu suspenso no canto superior esquerdo.
- Acesse Configurações do realm > Eventos.
- Selecione a subguia Configurações de eventos do usuário.
- Ative a opção Salvar eventos.
- Defina o período de Validade (mínimo recomendado: 7 dias).
- Clique em Salvar.
Ativar eventos de administrador
- Na mesma guia Eventos, selecione a subguia Configurações de eventos de administrador.
- Ative a opção Salvar eventos.
- Ative a opção Incluir representação para capturar todos os detalhes dos objetos alterados.
- Defina o período de Validade (mínimo recomendado: 7 dias).
- 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 Fase 2 (p2-inc) para ativar a entrega de webhook.
Baixar e implantar a extensão
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 a partir da fonte:
git clone https://github.com/p2-inc/keycloak-events.git cd keycloak-events mvn clean installCopie o arquivo JAR resultante para o diretório
providersdo Keycloak:cp target/keycloak-events-*.jar /opt/keycloak/providers/Recrie e reinicie o Keycloak:
/opt/keycloak/bin/kc.sh build /opt/keycloak/bin/kc.sh start
Ativar o listener de eventos do webhook
- Faça login no Admin Console do Keycloak.
- Selecione o reino de destino no menu suspenso.
- Acesse Configurações do realm > Eventos.
- No menu suspenso Listeners de eventos, selecione ext-event-webhook.
- 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://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate?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 administração 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 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 domínio 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 Keycloak<REALM_NAME>: o nome do realm a ser monitorado (por exemplo,masteroumy-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 domínio:
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 eventos 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 acessoadmin.*: envia todos os eventos de administrador.admin.USER-*: envia todos os eventos de administrador relacionados aos usuários.admin-USER-CREATE— Enviar apenas eventos de administrador de criação de usuário
Formato do payload do webhook
O webhook envia eventos como solicitações HTTP POST 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 repetição do webhook
A extensão usa espera exponencial automática para novas tentativas quando uma resposta diferente de 2xx é recebida:
| Parâmetro | Valor padrão | Descrição |
|---|---|---|
| backoffInitialInterval | 500 ms | Intervalo inicial de novas tentativas |
| 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 jitter |
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.
Método 1: cabeçalhos personalizados (recomendado)
Se o fornecedor aceitar cabeçalhos HTTP personalizados, use esse método para aumentar 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:
- A chave de API e o secret não estão visíveis no URL
- Mais seguro (cabeçalhos não registrados em registros de acesso ao servidor da Web)
- Método preferido quando o fornecedor oferece suporte
Método 2: parâmetros de consulta
Se o fornecedor não aceitar cabeçalhos personalizados, adicione as credenciais ao URL.
Formato do URL:
<ENDPOINT_URL>?key=<API_KEY>&secret=<SECRET_KEY>Exemplo:
https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate?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 em registros de acesso ao servidor da Web.
- Menos seguro que 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 chave de API:
x-goog-chronicle-auth(recomendado)X-Goog-Chronicle-Auth(sem diferenciação de maiúsculas e minúsculas)
Para chave secreta:
x-chronicle-auth(recomendado)X-Chronicle-Auth(sem diferenciação de maiúsculas e minúsculas)
Limites e práticas recomendadas de webhook
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 repetição | Automático com espera exponencial |
Tabela de mapeamento do UDM
| Campo de registro | Mapeamento do 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 padrões ISO8601 e yyyy-MM-dd'T'HH:mm:ss.SSSZ |
| payload.ip_address | metadata.event_type | Definido como "STATUS_UPDATE" se payload.ip_address não estiver vazio. Caso contrário, "USER_UNCATEGORIZED" se uuid não estiver vazio. Caso contrário, "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 com base em 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 com base em objeto, 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 mudanças |
redirect_uri" from "details_json |
target.url |
Mapeado do registro de mudanças |
realm_id" and "client_id |
additional.fields |
Mapeado do registro de mudanças |
Registro de alterações
Ver o registro de alterações deste analisador
Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais do Google SecOps.