Mengumpulkan log Keycloak
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
- Buka Setelan > Pengelolaan Data > Feed. Jika Anda menggunakan platform khusus SIEM, buka Settings > Feeds.
- Klik Tambahkan Feed Berita Baru.
- Di halaman berikutnya, klik Konfigurasi satu feed.
- Di kolom Nama feed, masukkan nama untuk feed (misalnya,
Keycloak Events). - Pilih Webhook sebagai Jenis sumber.
- Pilih Keycloak sebagai Log type.
- Klik Berikutnya.
- Tentukan nilai untuk parameter input berikut:
- Split delimiter (opsional): Masukkan
\nuntuk 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
- Split delimiter (opsional): Masukkan
- Klik Berikutnya.
- 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:
- Di halaman detail feed, klik Buat Kunci Rahasia.
- Dialog akan menampilkan kunci rahasia.
- 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
- Buka tab Detail untuk feed tersebut.
- Di bagian Endpoint Information, salin Feed endpoint URL.
Format URL-nya adalah:
https://{region}-chronicle.googleapis.com/v1/{parent}/logs:importDengan
{region}adalah region instance Google SecOps Anda (misalnya,us,europe, atauasia-southeast1), dan{parent}adalah jalur resource dalam formatprojects/<PROJECT_ID>/locations/<LOCATION>/instances/<INSTANCE_ID>/logTypes/<LOG_TYPE>.Simpan URL ini untuk langkah berikutnya.
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
- Buka halaman Credentials Konsol Google Cloud.
- Pilih project Anda (project yang terkait dengan instance Chronicle Anda).
- Klik Create credentials > kunci API.
- Kunci API akan dibuat dan ditampilkan dalam dialog.
- Klik Edit kunci API untuk membatasi kunci.
Membatasi kunci API
- Di halaman setelan kunci API:
- Name: Masukkan nama deskriptif (misalnya,
Chronicle Webhook API Key)
- Name: Masukkan nama deskriptif (misalnya,
- Di bagian API restrictions:
- Pilih Restrict key.
- Di dropdown Select APIs, telusuri dan pilih Google SecOps API (atau Chronicle API).
- Klik Simpan.
- Salin nilai kunci API dari kolom API key di bagian atas halaman.
- 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
- Login ke Konsol Admin Keycloak.
- Pilih realm yang ingin Anda pantau dari dropdown realm di pojok kiri atas.
- Buka Realm Settings > Events.
- Pilih sub-tab User events settings.
- Aktifkan tombol Simpan acara.
- Tetapkan periode Masa berlaku (minimum yang direkomendasikan: 7 hari).
- Klik Simpan.
Mengaktifkan peristiwa admin
- Di tab Peristiwa yang sama, pilih sub-tab Setelan peristiwa admin.
- Aktifkan tombol Simpan acara.
- Aktifkan tombol Sertakan representasi untuk mengambil detail lengkap objek yang diubah.
- Tetapkan periode Masa berlaku (minimum yang direkomendasikan: 7 hari).
- 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
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 installSalin file fat JAR yang dihasilkan ke direktori
providersKeycloak:cp target/keycloak-events-*.jar /opt/keycloak/providers/Bangun ulang dan mulai ulang Keycloak:
/opt/keycloak/bin/kc.sh build /opt/keycloak/bin/kc.sh start
Mengaktifkan pemroses peristiwa webhook
- Login ke Konsol Admin Keycloak.
- Pilih realm target dari dropdown realm.
- Buka Realm Settings > Events.
- Di dropdown Event listeners, pilih ext-event-webhook.
- 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,masterataumy-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 aksesadmin.*— Mengirim semua peristiwa adminadmin.USER-*— Mengirim semua peristiwa admin yang terkait dengan penggunaadmin-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.
Metode 1: Header kustom (Direkomendasikan)
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.