Mengumpulkan log Keycloak

Didukung di:

Dokumen ini menjelaskan cara mengonfigurasi Keycloak untuk mengirimkan log ke Google Security Operations menggunakan webhook.

Keycloak adalah solusi pengelolaan akses dan identitas (IAM) open source yang menyediakan kemampuan single sign-on (SSO), federasi pengguna, perantara identitas, dan login sosial. Layanan ini mendukung protokol OpenID Connect, OAuth 2.0, dan SAML 2.0 serta melacak peristiwa pengguna (login, logout, pendaftaran, perubahan sandi) dan peristiwa admin (operasi pengelolaan pengguna, klien, realm, dan peran) untuk audit keamanan.

Sebelum memulai

Pastikan Anda memiliki prasyarat berikut:

  • Instance Google SecOps
  • Instance Keycloak yang sedang berjalan (direkomendasikan versi 20 atau yang lebih baru)
  • Akses administrator ke Konsol Admin Keycloak
  • Akses ke sistem file atau container server Keycloak untuk men-deploy ekstensi
  • Akses ke Konsol Google Cloud (untuk pembuatan kunci API)

Membuat feed webhook di Google SecOps

Buat feed

  1. Buka Setelan SIEM > Feed.
  2. Klik Tambahkan Feed Baru.
  3. Di halaman berikutnya, klik Konfigurasi satu feed.
  4. Di kolom Nama feed, masukkan nama untuk feed (misalnya, Keycloak Events).
  5. Pilih Webhook sebagai Jenis sumber.
  6. Pilih Keycloak sebagai Jenis log.
  7. Klik Berikutnya.
  8. Tentukan nilai untuk parameter input berikut:
    • Pemisah pemisahan (opsional): Masukkan \n untuk memisahkan peristiwa multi-baris (setiap POST webhook berisi satu peristiwa, sehingga kolom ini dapat dibiarkan kosong).
    • Namespace aset: Namespace aset
    • Label penyerapan: Label yang akan diterapkan ke peristiwa dari feed ini
  9. Klik Berikutnya.
  10. Tinjau konfigurasi feed baru Anda di layar Selesaikan, lalu klik Kirim.

Buat dan simpan kunci rahasia

Setelah membuat feed, Anda harus membuat kunci rahasia untuk autentikasi:

  1. Di halaman detail feed, klik Buat Kunci Rahasia.
  2. Dialog akan menampilkan kunci rahasia.
  3. Salin dan simpan kunci rahasia dengan aman.

Penting: Kunci rahasia hanya ditampilkan satu kali dan tidak dapat diambil lagi. Jika Anda kehilangan kunci tersebut, Anda harus membuat kunci rahasia baru.

Mendapatkan URL endpoint feed

  1. Buka tab Detail untuk feed tersebut.
  2. Di bagian Endpoint Information, salin Feed endpoint URL.
  3. Format URL-nya adalah:

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

    atau

    https://<REGION>-malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate
    
  4. Simpan URL ini untuk langkah berikutnya.

  5. Klik Done.

Membuat kunci Google Cloud API

Chronicle memerlukan kunci API untuk autentikasi. Buat kunci API yang dibatasi di Konsol Google Cloud.

Buat kunci API

  1. Buka halaman Kredensial Konsol Google Cloud.
  2. Pilih project Anda (project yang terkait dengan instance Chronicle Anda).
  3. Klik Create credentials > API key.
  4. Kunci API dibuat dan ditampilkan dalam dialog.
  5. Klik Edit API key untuk membatasi kunci.

Membatasi kunci API

  1. Di halaman setelan kunci API:
    • Nama: Masukkan nama deskriptif (misalnya, Chronicle Webhook API Key)
  2. Di bagian Pembatasan API:
    1. Pilih Restrict key.
    2. Di drop-down Select APIs, telusuri dan pilih Google SecOps API (atau Chronicle API).
  3. Klik Simpan.
  4. Salin nilai kunci API dari kolom API key di bagian atas halaman.
  5. Simpan kunci API dengan aman.

Mengaktifkan penyimpanan peristiwa di Keycloak

Sebelum mengonfigurasi ekstensi webhook, aktifkan penyimpanan peristiwa di Keycloak agar peristiwa dibuat dan tersedia untuk penerusan.

Mengaktifkan peristiwa pengguna

  1. Login ke Konsol Admin Keycloak.
  2. Pilih realm yang ingin Anda pantau dari dropdown realm di sudut kiri atas.
  3. Buka Setelan Realm > Peristiwa.
  4. Pilih sub-tab Setelan peristiwa pengguna.
  5. Aktifkan tombol Simpan acara.
  6. Tetapkan periode Masa berlaku (minimum yang direkomendasikan: 7 hari).
  7. Klik Simpan.

Mengaktifkan peristiwa admin

  1. Di tab Peristiwa yang sama, pilih sub-tab Setelan peristiwa admin.
  2. Aktifkan tombol Simpan acara.
  3. Aktifkan tombol Sertakan representasi untuk merekam detail lengkap objek yang diubah.
  4. Tetapkan periode Masa berlaku (minimum yang direkomendasikan: 7 hari).
  5. Klik Simpan.

Menginstal ekstensi pemroses peristiwa webhook

Keycloak tidak menyertakan pemroses peristiwa webhook native. Instal ekstensi keycloak-events dari Phase Two (p2-inc) untuk mengaktifkan pengiriman webhook.

Mendownload dan men-deploy ekstensi

  1. Download JAR rilis terbaru dari halaman rilis keycloak-events di Maven Central atau bangun dari sumber:

    git clone https://github.com/p2-inc/keycloak-events.git
    cd keycloak-events
    mvn clean install
    
  2. Salin file JAR gabungan yang dihasilkan ke direktori providers Keycloak:

    cp target/keycloak-events-*.jar /opt/keycloak/providers/
    
  3. Bangun ulang dan mulai ulang Keycloak:

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

Aktifkan pemroses peristiwa webhook

  1. Login ke Konsol Admin Keycloak.
  2. Pilih realm target dari dropdown realm.
  3. Buka Setelan Realm > Peristiwa.
  4. Di dropdown Event listeners, pilih ext-event-webhook.
  5. Klik Simpan.

Mengonfigurasi webhook Keycloak

Buat URL webhook

  • Gabungkan URL endpoint Chronicle dan kunci API:

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

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

Membuat langganan webhook melalui Keycloak REST API

Ekstensi keycloak-events menyediakan endpoint REST untuk mengelola langganan webhook. Gunakan Keycloak Admin REST API untuk membuat webhook.

Langkah 1: Dapatkan token akses

  • Minta token akses dari Keycloak menggunakan akun admin:

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

Ganti kode berikut:

  • <KEYCLOAK_HOST>: Nama host dan port server Keycloak Anda (misalnya, keycloak.example.com:8443)
  • <ADMIN_USERNAME>: Nama pengguna admin Keycloak Anda
  • <ADMIN_PASSWORD>: Sandi admin Keycloak Anda

Langkah 2: Buat webhook

  • Kirim permintaan POST untuk membuat langganan webhook untuk realm target:

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

Ganti kode berikut:

  • <KEYCLOAK_HOST>: Nama host server Keycloak Anda
  • <REALM_NAME>: Nama realm yang akan dipantau (misalnya, master atau my-realm)
  • <ENDPOINT_URL>: URL endpoint feed Chronicle yang disalin sebelumnya
  • <API_KEY>: Kunci Google Cloud API yang dibuat sebelumnya
  • <SECRET_KEY>: Kunci rahasia webhook Chronicle yang dibuat sebelumnya
  • <WEBHOOK_HMAC_SECRET>: String rahasia arbitrer untuk penandatanganan HMAC payload webhook (misalnya, mySecretKey123)

Langkah 3: Verifikasi webhook

  • Pastikan webhook telah dibuat dengan mencantumkan semua webhook untuk realm:

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

Respons menampilkan daftar objek webhook. Verifikasi bahwa webhook Anda muncul dengan "enabled": "true" dan URL yang benar.

Jenis peristiwa webhook

Kolom eventTypes menerima array ekspresi untuk memfilter peristiwa mana yang dikirim:

  • * — Mengirim semua peristiwa (direkomendasikan untuk integrasi SIEM)
  • access.* — Mengirim semua peristiwa akses
  • admin.* — Mengirim semua peristiwa admin
  • admin.USER-* — Mengirim semua peristiwa admin yang terkait dengan pengguna
  • admin-USER-CREATE — Hanya mengirim peristiwa admin pembuatan pengguna

Format payload webhook

  • Webhook mengirim peristiwa sebagai permintaan HTTP POST dengan payload JSON. Contoh payload peristiwa pengguna:

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

Perilaku percobaan ulang webhook

Ekstensi menggunakan backoff eksponensial otomatis untuk percobaan ulang saat respons non-2xx diterima:

Parameter Nilai Default Deskripsi
backoffInitialInterval 500 md Interval percobaan ulang awal
backoffMaxElapsedTime 900000 md (15 menit) Total waktu percobaan ulang maksimum
backoffMaxInterval 180000 md (3 menit) Interval maksimum antara percobaan ulang
backoffMultiplier 5 Pengganda untuk setiap interval percobaan ulang
backoffRandomizationFactor 0,5 Faktor pengacakan untuk jitter

Referensi metode autentikasi

Feed webhook Chronicle mendukung beberapa metode autentikasi. Pilih metode yang didukung vendor Anda.

Jika vendor Anda mendukung header HTTP kustom, gunakan metode ini untuk keamanan yang lebih baik.

  • Format permintaan:

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

Kelebihan:

  • Kunci API dan rahasia tidak terlihat di URL
  • Lebih aman (header tidak dicatat dalam log akses server web)
  • Metode pilihan jika vendor mendukungnya

Metode 2: Parameter kueri

Jika vendor Anda tidak mendukung header kustom, tambahkan kredensial ke URL.

  • Format URL:

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

    https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate?key=AIzaSyD...&secret=abcd1234...
    
  • Format permintaan:

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

Kekurangan:

  • Kredensial terlihat di URL
  • Dapat dicatat dalam log akses server web
  • Kurang aman dibandingkan header

Metode 3: Hybrid (URL + Header)

Beberapa konfigurasi menggunakan kunci API di URL dan kunci rahasia di header.

  • Format permintaan:

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

Nama header autentikasi

Chronicle menerima nama header berikut untuk autentikasi:

Untuk kunci API:

  • x-goog-chronicle-auth (direkomendasikan)
  • X-Goog-Chronicle-Auth (tidak peka huruf besar/kecil)

Untuk kunci rahasia:

  • x-chronicle-auth (direkomendasikan)
  • X-Chronicle-Auth (tidak peka huruf besar/kecil)

Batasan dan praktik terbaik webhook

Batas permintaan

Batas Nilai
Ukuran permintaan maksimum 4 MB
QPS Maks (kueri per detik) 15.000
Waktu tunggu permintaan 30 seconds
Perilaku percobaan ulang Otomatis dengan backoff eksponensial

Tabel pemetaan UDM

Kolom Log Pemetaan UDM Logika
payload.client_id additional.fields Digabungkan dengan kolom yang dibuat dari payload.client_id, payload.realm_id
payload.realm_id additional.fields
source_timestamp metadata.event_timestamp Diuraikan menggunakan filter tanggal dengan pola ISO8601 dan yyyy-MM-dd'T'HH:mm:ss.SSSZ
payload.ip_address metadata.event_type Ditetapkan ke "STATUS_UPDATE" jika payload.ip_address tidak kosong, atau "USER_UNCATEGORIZED" jika uuid tidak kosong, atau "GENERIC_EVENT"
uuid metadata.event_type
payload.type metadata.product_event_type Nilai disalin secara langsung
payload.session_id network.session_id Nilai disalin secara langsung
payload.ip_address principal.ip Nilai disalin secara langsung
source_metadata.schema principal.resource.attribute.labels Digabungkan dengan label yang dibuat dari source_metadata.schema, source_metadata.table, source_metadata.is_deleted (dikonversi menjadi 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 Nilai disalin secara langsung
objek security_result.detection_fields Digabungkan dengan label yang dibuat dari object, read_method, payload.id
read_method security_result.detection_fields
payload.id security_result.detection_fields
redirect_uri target.url Nilai disalin secara langsung
nama pengguna target.user.userid Nilai disalin secara langsung
metadata.product_name metadata.product_name Ditetapkan ke "KEYCLOAK"
metadata.vendor_name metadata.vendor_name Ditetapkan ke "KEYCLOAK"
username" from "details_json target.user.userid Dipetakan dari log perubahan
redirect_uri" from "details_json target.url Dipetakan dari log perubahan
realm_id" and "client_id additional.fields Dipetakan dari log perubahan

Log Perubahan

Melihat Log Perubahan untuk parser ini

Perlu bantuan lain? Dapatkan jawaban dari anggota Komunitas dan profesional Google SecOps.