收集 Keycloak 記錄

支援:

本文說明如何設定 Keycloak,透過 Webhook 將記錄檔推送至 Google Security Operations。

Keycloak 是開放原始碼的身分與存取權管理 (IAM) 解決方案,提供單一登入 (SSO)、使用者聯合、身分代理和社群媒體登入功能。Keycloak 支援 OpenID Connect、OAuth 2.0 和 SAML 2.0 通訊協定,並會追蹤使用者事件 (登入、登出、註冊、密碼變更) 和管理員事件 (使用者、用戶端、領域和角色管理作業),以便進行安全性稽核。

事前準備

請確認您已完成下列事前準備事項:

  • Google SecOps 執行個體
  • 正在執行的 Keycloak 執行個體 (建議使用 20 以上版本)
  • Keycloak 管理控制台的管理員存取權
  • 可存取 Keycloak 伺服器檔案系統或容器,以便部署擴充功能
  • 可存取 Google Cloud 控制台 (用於建立 API 金鑰)

在 Google SecOps 中建立 Webhook 動態饋給

建立動態饋給

  1. 依序前往「SIEM 設定」>「動態饋給」。
  2. 按一下「新增動態饋給」。
  3. 在下一頁,點按「設定單一動態饋給」。
  4. 在「動態饋給名稱」欄位中輸入動態饋給名稱 (例如 Keycloak Events)。
  5. 「Source type」(來源類型) 請選取「Webhook」。
  6. 選取「Keycloak」做為「記錄類型」。
  7. 點選「下一步」。
  8. 指定下列輸入參數的值:
    • 分割分隔符號 (選填):輸入 \n 分割多行事件 (每個 Webhook POST 都包含單一事件,因此可以留空)。
    • 資產命名空間:資產命名空間
    • 擷取標籤:要套用至這個動態饋給事件的標籤
  9. 點選「下一步」。
  10. 在「Finalize」(完成) 畫面中檢查新的新聞動態消息設定,然後按一下「Submit」(提交)。

產生並儲存密鑰

建立動態饋給後,您必須產生用於驗證的密鑰:

  1. 在動態饋給詳細資料頁面,按一下「產生 Secret Key」。
  2. 對話方塊會顯示密鑰。
  3. 複製並妥善儲存密鑰。

重要事項:密鑰只會顯示一次,之後便無法擷取。如果遺失,就必須產生新的密鑰。

取得動態饋給端點網址

  1. 前往動態消息的「詳細資料」分頁。
  2. 在「端點資訊」部分,複製「動態消息端點網址」。
  3. 網址格式如下:

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

    其中 {region} 是 Google SecOps 執行個體的區域 (例如 us、europe 或 asia-southeast1),而 {parent} 是 projects/<PROJECT_ID>/locations/<LOCATION>/instances/<INSTANCE_ID>/logTypes/<LOG_TYPE> 格式的資源路徑。

  4. 請儲存這個網址,以利進行後續步驟。

  5. 按一下「完成」。

建立 Google Cloud API 金鑰

Chronicle 需要 API 金鑰才能進行驗證。在 Google Cloud 控制台中建立受限制的 API 金鑰。

建立 API 金鑰

  1. 前往 Google Cloud 控制台憑證頁面。
  2. 選取專案 (與 Chronicle 執行個體相關聯的專案)。
  3. 依序點選「建立憑證」 > 「API 金鑰」。
  4. 系統會建立 API 金鑰,並在對話方塊中顯示。
  5. 按一下「編輯 API 金鑰」即可限制金鑰。

限制 API 金鑰

  1. 在「API 金鑰」設定頁面中:
    • 名稱:輸入描述性名稱 (例如 Chronicle Webhook API Key)
  2. 在「API 限制」下方:
    1. 選取「Restrict key」(限制金鑰)。
    2. 在「選取 API」下拉式選單中,搜尋並選取「Google SecOps API」 (或「Chronicle API」)。
  3. 按一下 [儲存]。
  4. 複製頁面頂端「API 金鑰」欄位中的 API 金鑰值。
  5. 妥善保存 API 金鑰。

在 Keycloak 中啟用事件儲存功能

設定 Webhook 擴充功能前,請先在 Keycloak 中啟用事件儲存功能,以便產生及轉送事件。

啟用使用者事件

  1. 登入 Keycloak 管理控制台。
  2. 從左上角的領域下拉式選單中,選取要監控的領域。
  3. 依序前往「領域設定」>「活動」。
  4. 選取「User events settings」(使用者事件設定) 子標籤。
  5. 啟用「儲存活動」切換鈕。
  6. 設定「到期」期限 (建議至少 7 天)。
  7. 按一下 [儲存]。

啟用管理員事件

  1. 在同一個「事件」分頁中,選取「管理事件設定」子分頁。
  2. 啟用「儲存活動」切換鈕。
  3. 啟用「Include representation」(包含表示法) 切換鈕,擷取變更物件的完整詳細資料。
  4. 設定「到期」期限 (建議至少 7 天)。
  5. 按一下 [儲存]。

安裝 Webhook 事件監聽器擴充功能

Keycloak 不含原生 Webhook 事件監聽器。安裝 Phase Two (p2-inc) 的 keycloak-events 擴充功能,啟用 Webhook 傳送功能。

下載及部署擴充功能

  1. 從 Maven Central 的 keycloak-events 發布頁面下載最新發布的 JAR,或從來源建構:

    git clone https://github.com/p2-inc/keycloak-events.git
    cd keycloak-events
    mvn clean install
    
  2. 將產生的 Fat JAR 檔案複製到 Keycloak providers 目錄:

    cp target/keycloak-events-*.jar /opt/keycloak/providers/
    
  3. 重建並重新啟動 Keycloak:

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

啟用 Webhook 事件監聽器

  1. 登入 Keycloak 管理控制台。
  2. 從領域下拉式選單選取目標領域。
  3. 依序前往「領域設定」>「活動」。
  4. 在「事件監聽器」下拉式選單中,選取「ext-event-webhook」。
  5. 按一下 [儲存]。

設定 Keycloak Webhook

建構 Webhook 網址

  • 合併 Chronicle 端點網址和 API 金鑰:

    <ENDPOINT_URL>?key=<API_KEY>
    
  • 範例:

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

透過 Keycloak REST API 建立 Webhook 訂閱項目

keycloak-events 擴充功能提供 REST 端點,可用於管理 Webhook 訂閱項目。使用 Keycloak Admin REST API 建立 Webhook。

步驟 1:取得存取權杖

  • 使用管理員帳戶向 Keycloak 要求存取權杖:

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

更改下列內容:

  • <KEYCLOAK_HOST>:Keycloak 伺服器主機名稱和通訊埠 (例如 keycloak.example.com:8443)
  • <ADMIN_USERNAME>:Keycloak 管理員使用者名稱
  • <ADMIN_PASSWORD>:Keycloak 管理員密碼

步驟 2:建立 Webhook

  • 傳送 POST 要求,為目標領域建立 Webhook 訂閱項目:

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

更改下列內容:

  • <KEYCLOAK_HOST>:Keycloak 伺服器主機名稱
  • <REALM_NAME>:要監控的領域名稱 (例如 master 或 my-realm)
  • <ENDPOINT_URL>:先前複製的 Chronicle 動態饋給端點網址
  • <API_KEY>:先前建立的 Google Cloud API 金鑰
  • <SECRET_KEY>:先前產生的 Chronicle Webhook 密鑰
  • <WEBHOOK_HMAC_SECRET>:用於 HMAC 簽署 Webhook 酬載的任意 Secret 字串 (例如 mySecretKey123)

步驟 3:驗證 Webhook

  • 列出領域的所有 Webhook,確認是否已建立:

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

回應會傳回 Webhook 物件清單。確認 Webhook 顯示 "enabled": "true" 和正確的網址。

Webhook 事件類型

eventTypes 欄位接受運算式陣列,可篩選要傳送的事件:

  • *:傳送所有事件 (建議用於 SIEM 整合)
  • access.* - 傳送所有存取事件
  • admin.* - 傳送所有管理員事件
  • admin.USER-* - 傳送與使用者相關的所有管理員事件
  • admin-USER-CREATE - 只傳送使用者建立管理員事件

Webhook 酬載格式

  • Webhook 會以 HTTP POST 要求形式傳送事件,並附帶 JSON 酬載。使用者事件酬載範例:

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

Webhook 重試行為

收到非 2xx 回應時,擴充功能會自動使用指數輪詢重試:

參數 預設值 說明
backoffInitialInterval 500 毫秒 初始重試間隔
backoffMaxElapsedTime 900000 毫秒 (15 分鐘) 重試時間總計上限
backoffMaxInterval 180000 毫秒 (3 分鐘) 重試間隔時間上限
backoffMultiplier 5 每次重試間隔的乘數
backoffRandomizationFactor 0.5 隨機抖動係數

驗證方式參考資料

Chronicle 網頁掛鉤動態饋給支援多種驗證方法。請選擇供應商支援的方法。

如果供應商支援自訂 HTTP 標頭,請使用這個方法,提高安全性。

  • 要求格式:

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

優點:

  • 網址中不會顯示 API 金鑰和密鑰
  • 更安全 (標頭不會記錄在網路伺服器存取記錄中)
  • 供應商支援時的首選方法

方法 2:查詢參數

如果廠商不支援自訂標頭,請將憑證附加至網址。

  • 網址格式:

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

    https://{region}-chronicle.googleapis.com/v1/{parent}/logs:import?key=AIzaSyD...&secret=abcd1234...
    
  • 要求格式:

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

缺點:

  • 網址中顯示憑證
  • 可能記錄在網路伺服器存取記錄中
  • 安全性低於標頭

方法 3:混合 (網址 + 標頭)

部分設定會在網址中使用 API 金鑰,並在標頭中使用密鑰。

  • 要求格式:

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

驗證標頭名稱

Chronicle 接受下列驗證標頭名稱:

API 金鑰:

  • x-goog-chronicle-auth (建議)
  • X-Goog-Chronicle-Auth (不區分大小寫)

密鑰:

  • x-chronicle-auth (建議)
  • X-Chronicle-Auth (不區分大小寫)

Webhook 限制和最佳做法

要求限制

限制 值
要求大小上限 4 MB
QPS (每秒查詢次數) 上限 15,000
要求逾時 30 秒
重試行為 自動,採用指數輪詢

UDM 對應表

記錄欄位 UDM 對應 邏輯
payload.client_id additional.fields 與從 payload.client_id、payload.realm_id 建立的欄位合併
payload.realm_id additional.fields
source_timestamp metadata.event_timestamp 使用日期篩選器剖析,模式為 ISO8601 和 yyyy-MM-dd'T'HH:mm:ss.SSSZ
payload.ip_address metadata.event_type 如果 payload.ip_address 不為空白,則設為「STATUS_UPDATE」;如果 uuid 不為空白,則設為「USER_UNCATEGORIZED」;否則設為「GENERIC_EVENT」
uuid metadata.event_type
payload.type metadata.product_event_type 直接複製值
payload.session_id network.session_id 直接複製值
payload.ip_address principal.ip 直接複製值
source_metadata.schema principal.resource.attribute.labels 與從 source_metadata.schema、source_metadata.table、source_metadata.is_deleted (轉換為字串)、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 直接複製值
物件 security_result.detection_fields 與從物件、read_method、payload.id 建立的標籤合併
read_method security_result.detection_fields
payload.id security_result.detection_fields
redirect_uri target.url 直接複製值
使用者名稱 target.user.userid 直接複製值
metadata.product_name metadata.product_name 設為「KEYCLOAK」
metadata.vendor_name metadata.vendor_name 設為「KEYCLOAK」
username" from "details_json target.user.userid 從變更記錄對應
redirect_uri" from "details_json target.url 從變更記錄對應
realm_id" and "client_id additional.fields 從變更記錄對應

變更記錄

查看這個剖析器的變更記錄

還有其他問題嗎?向社群成員和 Google SecOps 專家尋求解答。