Raccogli i log di Keycloak

Supportato in:

Questo documento spiega come configurare Keycloak per inviare i log a Google Security Operations utilizzando i webhook.

Keycloak è una soluzione di gestione di identità e accessi (IAM) open source che fornisce funzionalità di Single Sign-On (SSO), federazione degli utenti, intermediazione delle identità e accesso social. Supporta i protocolli OpenID Connect, OAuth 2.0 e SAML 2.0 e tiene traccia degli eventi utente (accesso, disconnessione, registrazione, modifiche della password) e degli eventi amministratore (operazioni di gestione di utenti, client, realm e ruoli) per il controllo della sicurezza.

Prima di iniziare

Assicurati di soddisfare i seguenti prerequisiti:

  • Un'istanza Google SecOps
  • Un'istanza Keycloak in esecuzione (è consigliata la versione 20 o successive)
  • Accesso amministratore alla Console di amministrazione Keycloak
  • Accesso al file system o al container del server Keycloak per il deployment delle estensioni
  • Accesso alla Google Cloud Console (per la creazione della chiave API)

Crea un feed webhook in Google SecOps

Crea il feed

  1. Vai a Impostazioni SIEM > Feed.
  2. Fai clic su Aggiungi nuovo feed di notizie.
  3. Nella pagina successiva, fai clic su Configura un singolo feed.
  4. Nel campo Nome feed, inserisci un nome per il feed (ad esempio Keycloak Events).
  5. Seleziona Webhook come Tipo di origine.
  6. Seleziona Keycloak come Tipo di log.
  7. Fai clic su Avanti.
  8. Specifica i valori per i seguenti parametri di input:
    • Delimitatore di suddivisione (facoltativo): inserisci \n per suddividere gli eventi su più righe (ogni POST del webhook contiene un singolo evento, quindi questo campo può essere lasciato vuoto).
    • Spazio dei nomi dell'asset: lo spazio dei nomi dell'asset
    • Etichette di importazione: l'etichetta da applicare agli eventi di questo feed
  9. Fai clic su Avanti.
  10. Controlla la nuova configurazione del feed di notizie nella schermata Finalizza e poi fai clic su Invia.

Genera e salva la chiave segreta

Dopo aver creato il feed, devi generare una chiave segreta per l'autenticazione:

  1. Nella pagina dei dettagli del feed, fai clic su Genera chiave segreta.
  2. Viene visualizzata una finestra di dialogo con la chiave segreta.
  3. Copia e salva la chiave segreta in modo sicuro.

Importante: la chiave segreta viene visualizzata una sola volta e non può essere recuperata in un secondo momento. Se la perdi, devi generare una nuova chiave segreta.

Recuperare l'URL dell'endpoint del feed

  1. Vai alla scheda Dettagli del feed.
  2. Nella sezione Endpoint Information (Informazioni sull'endpoint), copia l'Feed endpoint URL (URL endpoint del feed).
  3. Il formato dell'URL è:

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

    Dove {region} è la regione dell'istanza Google SecOps (ad esempio us, europe o asia-southeast1) e {parent} è il percorso della risorsa nel formato projects/<PROJECT_ID>/locations/<LOCATION>/instances/<INSTANCE_ID>/logTypes/<LOG_TYPE>.

  4. Salva questo URL per i passaggi successivi.

  5. Fai clic su Fine.

Creare una chiave API Google Cloud

Chronicle richiede una chiave API per l'autenticazione. Crea una chiave API con limitazioni nella Google Cloud Console.

Crea la chiave API

  1. Vai alla pagina Credenziali della console Google Cloud.
  2. Seleziona il tuo progetto (quello associato alla tua istanza Chronicle).
  3. Fai clic su Crea credenziali > Chiave API.
  4. Viene creata una chiave API, che viene visualizzata in una finestra di dialogo.
  5. Fai clic su Modifica chiave API per limitare la chiave.

Limita la chiave API

  1. Nella pagina delle impostazioni della chiave API:
    • Nome: inserisci un nome descrittivo (ad esempio Chronicle Webhook API Key)
  2. In Restrizioni API:
    1. Seleziona Limita chiave.
    2. Nel menu a discesa Seleziona API, cerca e seleziona API Google SecOps (o API Chronicle).
  3. Fai clic su Salva.
  4. Copia il valore della chiave API dal campo Chiave API nella parte superiore della pagina.
  5. Salva la chiave API in modo sicuro.

Abilita l'archiviazione degli eventi in Keycloak

Prima di configurare l'estensione del webhook, attiva l'archiviazione degli eventi in Keycloak in modo che gli eventi vengano generati e siano disponibili per l'inoltro.

Abilitare gli eventi utente

  1. Accedi alla Console di amministrazione Keycloak.
  2. Seleziona il realm che vuoi monitorare dal menu a discesa dei realm nell'angolo in alto a sinistra.
  3. Vai a Impostazioni del regno > Eventi.
  4. Seleziona la scheda secondaria Impostazioni eventi utente.
  5. Attiva il pulsante di attivazione/disattivazione Salva eventi.
  6. Imposta il periodo di scadenza (minimo consigliato: 7 giorni).
  7. Fai clic su Salva.

Attiva eventi amministratore

  1. Nella stessa scheda Eventi, seleziona la scheda secondaria Impostazioni eventi amministrativi.
  2. Attiva il pulsante di attivazione/disattivazione Salva eventi.
  3. Attiva il pulsante di attivazione/disattivazione Includi rappresentazione per acquisire i dettagli completi degli oggetti modificati.
  4. Imposta il periodo di Scadenza (minimo consigliato: 7 giorni).
  5. Fai clic su Salva.

Installa l'estensione del listener di eventi webhook

Keycloak non include un listener di eventi webhook nativo. Installa l'estensione keycloak-events di Phase Two (p2-inc) per attivare l'invio dei webhook.

Scaricare ed eseguire il deployment dell'estensione

  1. Scarica l'ultima release JAR dalla pagina delle release di keycloak-events su Maven Central o compila dal codice sorgente:

    git clone https://github.com/p2-inc/keycloak-events.git
    cd keycloak-events
    mvn clean install
    
  2. Copia il file fat JAR risultante nella directory Keycloak providers:

    cp target/keycloak-events-*.jar /opt/keycloak/providers/
    
  3. Ricrea e riavvia Keycloak:

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

Attiva il listener di eventi webhook

  1. Accedi alla Console di amministrazione Keycloak.
  2. Seleziona il realm di destinazione dal menu a discesa Realm.
  3. Vai a Impostazioni del regno > Eventi.
  4. Nel menu a discesa Listener di eventi, seleziona ext-event-webhook.
  5. Fai clic su Salva.

Configura il webhook Keycloak

Crea l'URL webhook

  • Combina l'URL dell'endpoint Chronicle e la chiave API:

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

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

Crea un abbonamento webhook tramite l'API REST di Keycloak

L'estensione keycloak-events fornisce endpoint REST per la gestione delle iscrizioni webhook. Utilizza l'API REST Keycloak Admin per creare un webhook.

Passaggio 1: ottieni un token di accesso

  • Richiedi un token di accesso da Keycloak utilizzando un account amministratore:

    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')
    

Sostituisci quanto segue:

  • <KEYCLOAK_HOST>: il nome host e la porta del server Keycloak (ad esempio, keycloak.example.com:8443)
  • <ADMIN_USERNAME>: il tuo nome utente amministratore di Keycloak
  • <ADMIN_PASSWORD>: la password amministratore di Keycloak

Passaggio 2: crea il webhook

  • Invia una richiesta POST per creare l'abbonamento al webhook per il realm di destinazione:

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

Sostituisci quanto segue:

  • <KEYCLOAK_HOST>: Il nome host del server Keycloak
  • <REALM_NAME>: il nome del realm da monitorare (ad esempio master o my-realm)
  • <ENDPOINT_URL>: l'URL dell'endpoint del feed di Chronicle copiato in precedenza
  • <API_KEY>: la chiave API Google Cloud creata in precedenza
  • <SECRET_KEY>: la chiave secret del webhook Chronicle generata in precedenza
  • <WEBHOOK_HMAC_SECRET>: una stringa secret arbitraria per la firma HMAC dei payload del webhook (ad esempio, mySecretKey123)

Passaggio 3: verifica il webhook

  • Verifica che il webhook sia stato creato elencando tutti i webhook per il realm:

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

La risposta restituisce un elenco di oggetti webhook. Verifica che il webhook venga visualizzato con "enabled": "true" e l'URL corretto.

Tipi di evento webhook

Il campo eventTypes accetta un array di espressioni per filtrare gli eventi inviati:

  • *: invia tutti gli eventi (opzione consigliata per l'integrazione SIEM)
  • access.*: invia tutti gli eventi di accesso
  • admin.*: invia tutti gli eventi amministrativi
  • admin.USER-*: invia tutti gli eventi amministrativi relativi agli utenti
  • admin-USER-CREATE: invia solo gli eventi amministrativi di creazione degli utenti

Formato payload webhook

  • Il webhook invia gli eventi come richieste POST HTTP con payload JSON. Esempio di payload di un evento utente:

    {
      "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 di ripetizione dei webhook

L'estensione utilizza il backoff esponenziale automatico per i nuovi tentativi quando riceve una risposta diversa da 2xx:

Parametro Valore predefinito Descrizione
backoffInitialInterval 500 ms Intervallo di ripetizione iniziale
backoffMaxElapsedTime 900.000 ms (15 min) Tempo totale massimo per i nuovi tentativi
backoffMaxInterval 180.000 ms (3 minuti) Intervallo massimo tra i tentativi
backoffMultiplier 5 Moltiplicatore per ogni intervallo di nuovi tentativi
backoffRandomizationFactor 0,5 Fattore di randomizzazione per il jitter

Riferimento ai metodi di autenticazione

I feed webhook di Chronicle supportano più metodi di autenticazione. Scegli il metodo supportato dal tuo fornitore.

Se il tuo fornitore supporta le intestazioni HTTP personalizzate, utilizza questo metodo per una maggiore sicurezza.

  • Formato della richiesta:

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

Vantaggi:

  • Chiave API e secret non visibili nell'URL
  • Più sicuro (le intestazioni non vengono registrate nei log di accesso del server web)
  • Metodo preferito quando il fornitore lo supporta

Metodo 2: parametri di query

Se il tuo fornitore non supporta le intestazioni personalizzate, aggiungi le credenziali all'URL.

  • Formato dell'URL:

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

    https://{region}-chronicle.googleapis.com/v1/{parent}/logs:import?key=AIzaSyD...&secret=abcd1234...
    
  • Formato della richiesta:

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

Svantaggi:

  • Credenziali visibili nell'URL
  • Potrebbero essere registrati nei log di accesso del server web
  • Meno sicuro delle intestazioni

Metodo 3: ibrido (URL + intestazione)

Alcune configurazioni utilizzano la chiave API nell'URL e la chiave segreta nell'intestazione.

  • Formato della richiesta:

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

Nomi delle intestazioni di autenticazione

Chronicle accetta i seguenti nomi di intestazione per l'autenticazione:

Per la chiave API:

  • x-goog-chronicle-auth (consigliata)
  • X-Goog-Chronicle-Auth (senza distinzione tra maiuscole e minuscole)

Per la chiave secret:

  • x-chronicle-auth (consigliata)
  • X-Chronicle-Auth (senza distinzione tra maiuscole e minuscole)

Limiti e best practice dei webhook

Limiti per le richieste

Limite Valore
Dimensioni massime della richiesta 4 MB
QPS (query al secondo) max 15.000
Timeout richieste 30 secondi
Comportamento dei nuovi tentativi Automatico con backoff esponenziale

Tabella di mappatura UDM

Campo log Mappatura UDM Logica
payload.client_id additional.fields Unito ai campi creati da payload.client_id, payload.realm_id
payload.realm_id additional.fields
source_timestamp metadata.event_timestamp Analizzato utilizzando il filtro per data con i pattern ISO8601 e AAAA-MM-GG'T'HH:mm:ss.SSSZ
payload.ip_address metadata.event_type Impostato su "STATUS_UPDATE" se payload.ip_address non è vuoto, altrimenti "USER_UNCATEGORIZED" se uuid non è vuoto, altrimenti "GENERIC_EVENT"
uuid metadata.event_type
payload.type metadata.product_event_type Valore copiato direttamente
payload.session_id network.session_id Valore copiato direttamente
payload.ip_address principal.ip Valore copiato direttamente
source_metadata.schema principal.resource.attribute.labels Unito alle etichette create da source_metadata.schema, source_metadata.table, source_metadata.is_deleted (convertito in stringa), 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 Valore copiato direttamente
oggetto security_result.detection_fields Unito alle etichette create da object, read_method, payload.id
read_method security_result.detection_fields
payload.id security_result.detection_fields
redirect_uri target.url Valore copiato direttamente
nome utente target.user.userid Valore copiato direttamente
metadata.product_name metadata.product_name Impostalo su "KEYCLOAK"
metadata.vendor_name metadata.vendor_name Impostato su "KEYCLOAK"
username" from "details_json target.user.userid Mappato dal log delle modifiche
redirect_uri" from "details_json target.url Mappato dal log delle modifiche
realm_id" and "client_id additional.fields Mappato dal log delle modifiche

Log delle modifiche

Visualizza il log delle modifiche per questo parser

Hai bisogno di ulteriore assistenza? Ricevi risposte dai membri della community e dai professionisti di Google SecOps.