Keycloak-Logs erfassen
In diesem Dokument wird beschrieben, wie Sie Keycloak so konfigurieren, dass Logs mithilfe von Webhooks an Google Security Operations gesendet werden.
Keycloak ist eine Open-Source-Lösung für die Identitäts- und Zugriffsverwaltung (Identity and Access Management, IAM), die Funktionen für die Einmalanmeldung (Single Sign-On, SSO), die Nutzerföderation, das Identitäts-Brokering und die Anmeldung über soziale Netzwerke bietet. Es unterstützt die Protokolle OpenID Connect, OAuth 2.0 und SAML 2.0 und erfasst Nutzerereignisse (Anmeldung, Abmeldung, Registrierung, Passwortänderungen) und Administratorereignisse (Nutzer-, Client-, Realm- und Rollenverwaltungsoperationen) für Sicherheitsprüfungen.
Hinweis
Folgende Voraussetzungen müssen erfüllt sein:
- Eine Google SecOps-Instanz
- Eine laufende Keycloak-Instanz (Version 20 oder höher empfohlen)
- Administratorzugriff auf die Keycloak Admin-Konsole
- Zugriff auf das Keycloak-Serverdateisystem oder den Container zum Bereitstellen von Erweiterungen
- Zugriff auf die Google Cloud Console (zum Erstellen von API-Schlüsseln)
Webhook-Feed in Google SecOps erstellen
Feed erstellen
- Rufen Sie die SIEM-Einstellungen > Feeds auf.
- Klicken Sie auf Neuen Feed hinzufügen.
- Klicken Sie auf der nächsten Seite auf Einen einzelnen Feed konfigurieren.
- Geben Sie im Feld Feedname einen Namen für den Feed ein, z. B.
Keycloak Events. - Wählen Sie Webhook als Quelltyp aus.
- Wählen Sie Keycloak als Logtyp aus.
- Klicken Sie auf Weiter.
- Geben Sie Werte für die folgenden Eingabeparameter an:
- Trennzeichen für Aufteilung (optional): Geben Sie
\nein, um mehrzeilige Ereignisse aufzuteilen. Da jeder Webhook-POST ein einzelnes Ereignis enthält, kann dieses Feld leer gelassen werden. - Asset-Namespace: Der Asset-Namespace
- Labels für Datenaufnahme: Das Label, das auf die Ereignisse aus diesem Feed angewendet werden soll
- Trennzeichen für Aufteilung (optional): Geben Sie
- Klicken Sie auf Weiter.
- Prüfen Sie die neue Feedkonfiguration auf dem Bildschirm Abschließen und klicken Sie dann auf Senden.
Secret-Schlüssel generieren und speichern
Nachdem Sie den Feed erstellt haben, müssen Sie einen geheimen Schlüssel für die Authentifizierung generieren:
- Klicken Sie auf der Feed-Detailseite auf Secret Key generieren.
- In einem Dialogfeld wird der geheime Schlüssel angezeigt.
- Kopieren und speichern Sie den geheimen Schlüssel sicher.
Wichtig: Der geheime Schlüssel wird nur einmal angezeigt und kann später nicht mehr abgerufen werden. Wenn Sie den Schlüssel verlieren, müssen Sie einen neuen geheimen Schlüssel generieren.
Feed-Endpunkt-URL abrufen
- Rufen Sie den Tab Details des Feeds auf.
- Kopieren Sie im Abschnitt Endpoint Information (Endpunktinformationen) die Feed endpoint URL (Feed-Endpunkt-URL).
Das URL-Format lautet:
https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreateoder
https://<REGION>-malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreateSpeichern Sie diese URL für die nächsten Schritte.
Klicken Sie auf Fertig.
Google Cloud API-Schlüssel erstellen
Für die Authentifizierung in Chronicle ist ein API-Schlüssel erforderlich. Erstellen Sie in der Google Cloud Console einen eingeschränkten API-Schlüssel.
API-Schlüssel erstellen
- Rufen Sie die Seite „Anmeldedaten“ in der Google Cloud Console auf.
- Wählen Sie Ihr Projekt aus (das Projekt, das mit Ihrer Chronicle-Instanz verknüpft ist).
- Klicken Sie auf Anmeldedaten erstellen > API-Schlüssel.
- Ein API-Schlüssel wird erstellt und in einem Dialogfeld angezeigt.
- Klicken Sie auf API-Schlüssel bearbeiten, um den Schlüssel einzuschränken.
API-Schlüssel einschränken
- Auf der Seite mit den API-Schlüssel-Einstellungen:
- Name: Geben Sie einen aussagekräftigen Namen ein, z. B.
Chronicle Webhook API Key.
- Name: Geben Sie einen aussagekräftigen Namen ein, z. B.
- Gehen Sie unter API-Einschränkungen so vor:
- Wählen Sie Schlüssel einschränken aus.
- Suchen Sie im Drop-down-Menü APIs auswählen nach Google SecOps API (oder Chronicle API) und wählen Sie die API aus.
- Klicken Sie auf Speichern.
- Kopieren Sie den API-Schlüsselwert aus dem Feld API-Schlüssel oben auf der Seite.
- Speichern Sie den API-Schlüssel sicher.
Ereignisspeicher in Keycloak aktivieren
Bevor Sie die Webhook-Erweiterung konfigurieren, müssen Sie die Ereignisspeicherung in Keycloak aktivieren, damit Ereignisse generiert und zur Weiterleitung verfügbar sind.
Nutzerereignisse aktivieren
- Melden Sie sich in der Keycloak Admin-Konsole an.
- Wählen Sie links oben im Drop-down-Menü den Bereich aus, den Sie beobachten möchten.
- Rufen Sie die Realm-Einstellungen > Ereignisse auf.
- Wählen Sie den Tab Einstellungen für Nutzerereignisse aus.
- Aktivieren Sie den Ein/Aus-Button Termine speichern.
- Legen Sie den Ablaufzeitraum fest (empfohlenes Minimum: 7 Tage).
- Klicken Sie auf Speichern.
Admin-Ereignisse aktivieren
- Wählen Sie auf demselben Tab Ereignisse den Untertab Einstellungen für Administratorereignisse aus.
- Aktivieren Sie den Ein/Aus-Button Termine speichern.
- Aktivieren Sie die Ein/Aus-Schaltfläche Include representation (Darstellung einbeziehen), um alle Details der geänderten Objekte zu erfassen.
- Legen Sie den Ablaufzeitraum fest (empfohlenes Minimum: 7 Tage).
- Klicken Sie auf Speichern.
Webhook-Event-Listener-Erweiterung installieren
Keycloak enthält keinen nativen Webhook-Event-Listener. Installieren Sie die keycloak-events-Erweiterung aus Phase 2 (p2-inc), um die Webhook-Übermittlung zu aktivieren.
Erweiterung herunterladen und bereitstellen
Laden Sie die JAR-Datei der neuesten Version von der Seite „keycloak-events releases“ auf Maven Central herunter oder erstellen Sie sie aus dem Quellcode:
git clone https://github.com/p2-inc/keycloak-events.git cd keycloak-events mvn clean installKopieren Sie die resultierende Fat JAR-Datei in das Keycloak-Verzeichnis
providers:cp target/keycloak-events-*.jar /opt/keycloak/providers/Erstellen Sie Keycloak neu und starten Sie es neu:
/opt/keycloak/bin/kc.sh build /opt/keycloak/bin/kc.sh start
Webhook-Event-Listener aktivieren
- Melden Sie sich in der Keycloak Admin-Konsole an.
- Wählen Sie im Drop-down-Menü „Realm“ den Ziel-Realm aus.
- Rufen Sie die Realm-Einstellungen > Ereignisse auf.
- Wählen Sie im Drop-down-Menü Event-Listener die Option ext-event-webhook aus.
- Klicken Sie auf Speichern.
Keycloak-Webhook konfigurieren
Webhook-URL erstellen
Kombinieren Sie die Chronicle-Endpunkt-URL und den API-Schlüssel:
<ENDPOINT_URL>?key=<API_KEY>Beispiel:
https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate?key=AIzaSyD...
Webhook-Abo über die Keycloak REST API erstellen
Die keycloak-events-Erweiterung bietet REST-Endpunkte für die Verwaltung von Webhook-Abos. Verwenden Sie die Keycloak Admin REST API, um einen Webhook zu erstellen.
Schritt 1: Zugriffstoken abrufen
Fordern Sie mit einem Administratorkonto ein Zugriffstoken von Keycloak an:
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')
Ersetzen Sie Folgendes:
<KEYCLOAK_HOST>: Der Hostname und Port Ihres Keycloak-Servers, z. B.keycloak.example.com:8443<ADMIN_USERNAME>: Ihr Keycloak-Administratornutzername<ADMIN_PASSWORD>: Ihr Keycloak-Administratorpasswort
Schritt 2: Webhook erstellen
Senden Sie eine POST-Anfrage, um das Webhook-Abo für den Zielbereich zu erstellen:
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": ["*"] }'
Ersetzen Sie Folgendes:
<KEYCLOAK_HOST>: Der Hostname Ihres Keycloak-Servers<REALM_NAME>: Der Name des zu überwachenden Bereichs, z. B.masterodermy-realm.<ENDPOINT_URL>: Die zuvor kopierte Chronicle-Feed-Endpunkt-URL<API_KEY>: Der zuvor erstellte Google Cloud API-Schlüssel<SECRET_KEY>: Der zuvor generierte geheime Schlüssel für Chronicle-Webhooks<WEBHOOK_HMAC_SECRET>: Ein beliebiger geheimer String für die HMAC-Signierung von Webhook-Nutzlasten (z. B.mySecretKey123)
Schritt 3: Webhook bestätigen
Prüfen Sie, ob der Webhook erstellt wurde, indem Sie alle Webhooks für den Bereich auflisten:
curl -sS -X GET "https://<KEYCLOAK_HOST>/realms/<REALM_NAME>/webhooks" \ -H "Authorization: Bearer ${TOKEN}" \ -H "Accept: application/json"
Die Antwort gibt eine Liste von Webhook-Objekten zurück. Prüfen Sie, ob Ihr Webhook mit "enabled": "true" und der richtigen URL angezeigt wird.
Webhook-Ereignistypen
Im Feld eventTypes wird ein Array von Ausdrücken akzeptiert, mit denen gefiltert wird, welche Ereignisse gesendet werden:
*– Alle Ereignisse senden (empfohlen für die SIEM-Integration)access.*: Alle Zugriffsereignisse sendenadmin.*: Alle Administratorereignisse sendenadmin.USER-*: Alle Administratorereignisse, die sich auf Nutzer beziehen, sendenadmin-USER-CREATE: Nur Administratorereignisse zur Nutzererstellung senden
Format der Webhook-Nutzlast
Der Webhook sendet Ereignisse als HTTP-POST-Anfragen mit JSON-Nutzlasten. Beispielnutzlast für Nutzerereignis:
{ "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" } }
Wiederholungsverhalten bei Webhooks
Die Erweiterung verwendet für Wiederholungsversuche einen automatischen exponentiellen Backoff, wenn eine Antwort empfangen wird, die nicht im 2xx-Bereich liegt:
| Parameter | Standardwert | Beschreibung |
|---|---|---|
| backoffInitialInterval | 500 ms | Erstes Wiederholungsintervall |
| backoffMaxElapsedTime | 900.000 ms (15 Minuten) | Maximale Gesamtwiederholungszeit |
| backoffMaxInterval | 180.000 ms (3 Minuten) | Maximales Intervall zwischen Wiederholungsversuchen |
| backoffMultiplier | 5 | Multiplikator für jedes Wiederholungsintervall |
| backoffRandomizationFactor | 0,5 | Zufallsfaktor für Jitter |
Referenz zu Authentifizierungsmethoden
Chronicle-Webhook-Feeds unterstützen mehrere Authentifizierungsmethoden. Wählen Sie die Methode aus, die von Ihrem Anbieter unterstützt wird.
Methode 1: Benutzerdefinierte Header (empfohlen)
Wenn Ihr Anbieter benutzerdefinierte HTTP-Header unterstützt, sollten Sie diese Methode verwenden, um die Sicherheit zu erhöhen.
Anfrageformat:
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" }
Vorteile:
- API-Schlüssel und Secret sind in der URL nicht sichtbar
- Sicherer (Header werden nicht in Webserver-Zugriffslogs protokolliert)
- Bevorzugte Methode, wenn der Anbieter sie unterstützt
Methode 2: Abfrageparameter
Wenn Ihr Anbieter keine benutzerdefinierten Headern unterstützt, hängen Sie die Anmeldedaten an die URL an.
URL-Format:
<ENDPOINT_URL>?key=<API_KEY>&secret=<SECRET_KEY>Beispiel:
https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate?key=AIzaSyD...&secret=abcd1234...Anfrageformat:
POST <ENDPOINT_URL>?key=<API_KEY>&secret=<SECRET_KEY> HTTP/1.1 Content-Type: application/json { "event": "data", "timestamp": "2025-01-15T10:30:00Z" }
Nachteile:
- Anmeldedaten in der URL sichtbar
- Möglicherweise in Webserver-Zugriffsprotokollen protokolliert
- Weniger sicher als Header
Methode 3: Hybrid (URL + Header)
Bei einigen Konfigurationen wird der API-Schlüssel in der URL und der geheime Schlüssel im Header verwendet.
Anfrageformat:
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" }
Namen von Authentifizierungsheadern
Chronicle akzeptiert die folgenden Headernamen für die Authentifizierung:
Für API-Schlüssel:
x-goog-chronicle-auth(empfohlen)X-Goog-Chronicle-Auth(keine Unterscheidung zwischen Groß- und Kleinschreibung)
Geheimer Schlüssel:
x-chronicle-auth(empfohlen)X-Chronicle-Auth(keine Unterscheidung zwischen Groß- und Kleinschreibung)
Webhook-Limits und Best Practices
Anfragelimits
| Limit | Wert |
|---|---|
| Maximale Anfragengröße | 4 MB |
| Maximale Abfragen pro Sekunde | 15.000 |
| Zeitlimit für Anfragen | 30 Sekunden |
| Wiederholungsverhalten | Automatisch mit exponentiellem Backoff |
UDM-Zuordnungstabelle
| Logfeld | UDM-Zuordnung | Logik |
|---|---|---|
| payload.client_id | additional.fields | Zusammengeführt mit Feldern, die aus payload.client_id und payload.realm_id erstellt wurden |
| payload.realm_id | additional.fields | |
| source_timestamp | metadata.event_timestamp | Geparsed mit Datumsfilter mit den Mustern ISO8601 und yyyy-MM-dd'T'HH:mm:ss.SSSZ |
| payload.ip_address | metadata.event_type | Auf „STATUS_UPDATE“ gesetzt, wenn payload.ip_address nicht leer ist, andernfalls „USER_UNCATEGORIZED“, wenn uuid nicht leer ist, andernfalls „GENERIC_EVENT“ |
| uuid | metadata.event_type | |
| payload.type | metadata.product_event_type | Wert direkt kopiert |
| payload.session_id | network.session_id | Wert direkt kopiert |
| payload.ip_address | principal.ip | Wert direkt kopiert |
| source_metadata.schema | principal.resource.attribute.labels | Zusammengeführt mit Labels, die aus source_metadata.schema, source_metadata.table, source_metadata.is_deleted (in String konvertiert), source_metadata.change_type, source_metadata.tx_id, source_metadata.lsn erstellt wurden |
| 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 | Wert direkt kopiert |
| Objekt | security_result.detection_fields | Zusammengeführt mit Labels, die aus „object“, „read_method“ und „payload.id“ erstellt wurden |
| read_method | security_result.detection_fields | |
| payload.id | security_result.detection_fields | |
| redirect_uri | target.url | Wert direkt kopiert |
| Nutzername | target.user.userid | Wert direkt kopiert |
| metadata.product_name | metadata.product_name | Auf „KEYCLOAK“ festgelegt |
| metadata.vendor_name | metadata.vendor_name | Auf „KEYCLOAK“ festgelegt |
username" from "details_json |
target.user.userid |
Aus dem Änderungsprotokoll zugeordnet |
redirect_uri" from "details_json |
target.url |
Aus dem Änderungsprotokoll zugeordnet |
realm_id" and "client_id |
additional.fields |
Aus dem Änderungsprotokoll zugeordnet |
Änderungsprotokoll
Änderungsprotokoll für diesen Parser ansehen
Benötigen Sie weitere Hilfe? Antworten von Community-Mitgliedern und Google SecOps-Experten erhalten