Mengumpulkan log Keycloak

Didukung di:

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

Keycloak adalah solusi pengelolaan akses dan identitas (IAM) open source yang menyediakan kemampuan single sign-on (SSO), penggabungan pengguna, perantara identitas, dan login dengan akun media sosial. Keycloak 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 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

Membuat feed

  1. Buka Setelan > Pengelolaan Data > Feed. Jika Anda menggunakan platform khusus SIEM, buka Settings > Feeds.
  2. Klik Tambahkan Feed Berita 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 Log type.
  7. Klik Berikutnya.
  8. Tentukan nilai untuk parameter input berikut:
    • Split delimiter (opsional): Masukkan \n untuk memisahkan peristiwa multibaris (setiap POST webhook berisi satu peristiwa, sehingga 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 berita baru Anda di layar Finalize, lalu klik Submit.

Membuat dan menyimpan 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 sekali 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://{region}-chronicle.googleapis.com/v1/{parent}/logs:import
    

    Dengan {region} adalah region instance Google SecOps Anda (misalnya, us, europe, atau asia-southeast1), dan {parent} adalah jalur resource dalam format projects/<PROJECT_ID>/locations/<LOCATION>/instances/<INSTANCE_ID>/logTypes/<LOG_TYPE>.

  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.

Membuat kunci API

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

Membatasi kunci API

  1. Di halaman setelan kunci API:
    • Name: Masukkan nama deskriptif (misalnya, Chronicle Webhook API Key)
  2. Di bagian API restrictions:
    1. Pilih Restrict key.
    2. Di dropdown 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 diteruskan.

Mengaktifkan peristiwa pengguna

  1. Login ke Konsol Admin Keycloak.
  2. Pilih realm yang ingin Anda pantau dari dropdown realm di pojok kiri atas.
  3. Buka Realm Settings > Events.
  4. Pilih sub-tab User events settings.
  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 mengambil 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 build dari sumber:

    git clone https://github.com/p2-inc/keycloak-events.git
    cd keycloak-events
    mvn clean install
    
  2. Salin file fat JAR 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
    

Mengaktifkan pemroses peristiwa webhook

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

Mengonfigurasi webhook Keycloak

Membuat URL webhook

  • Gabungkan URL endpoint Chronicle dan kunci API:

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

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

Membuat langganan webhook melalui Keycloak REST API

Ekstensi keycloak-events menyediakan endpoint REST untuk mengelola langganan webhook. Gunakan REST API Admin Keycloak 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 akan menampilkan daftar objek webhook. Pastikan webhook Anda muncul dengan "enabled": "true" dan URL yang benar.

Jenis peristiwa webhook

Kolom eventTypes menerima array ekspresi untuk memfilter peristiwa yang dikirim:

  • * — Kirim 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 mengirimkan peristiwa sebagai permintaan POST HTTP 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 ini menggunakan backoff eksponensial otomatis untuk percobaan ulang saat menerima respons non-2xx:

Parameter Nilai Default Deskripsi
backoffInitialInterval 500 md Interval percobaan ulang awal
backoffMaxElapsedTime 900.000 md (15 mnt) Total waktu percobaan ulang maksimum
backoffMaxInterval 180.000 md (3 mnt) 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 yang lebih disukai 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://{region}-chronicle.googleapis.com/v1/{parent}/logs:import?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 (kueri per detik) maks. 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 Diurai menggunakan filter tanggal dengan pola ISO8601 dan yyyy-MM-dd'T'HH:mm:ss.SSSZ
payload.ip_address metadata.event_type Tetapkan 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 langsung
payload.session_id network.session_id Nilai disalin langsung
payload.ip_address principal.ip Nilai disalin 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 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 langsung
nama pengguna target.user.userid Nilai disalin langsung
metadata.product_name metadata.product_name Tetapkan ke "KEYCLOAK"
metadata.vendor_name metadata.vendor_name Tetapkan 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.