收集 Fortra Digital Guardian (舊稱 Digital Guardian EDR) 記錄
剖析器版本:3.0
支援的國家/地區:
Google SecOps
SIEM
本文說明如何使用 Google Cloud Storage V2 和 Cloud Run 函式,將 Fortra Digital Guardian (舊稱 Digital Guardian EDR) 記錄檔擷取至 Google Security Operations。
Fortra Digital Guardian 是一套全面的資料遺失防護和端點偵測與應變平台,可掌握端點、網路和雲端應用程式的系統、使用者和資料事件。Analytics & Reporting Cloud (ARC) 服務提供進階分析、工作流程和報表功能,可全面保護資料。
Cloud Run 函式會使用 OAuth 2.0 向 ARC Export API 進行驗證、擷取匯出資料、確認書籤以繼續處理下一個區塊、將結果以 NDJSON 格式寫入 GCS bucket,而 Google SecOps 會透過 GCS V2 資訊提供擷取這些資料。
事前準備
請確認您已完成下列事前準備事項:
- Google SecOps 執行個體。
- 已啟用下列 API 的 Google Cloud 專案:
- Cloud Storage
- Cloud Run 函式
- Cloud Scheduler
- Pub/Sub
- Cloud Build
- 建立及管理 GCS 值區、Cloud Run 函式、Pub/Sub 主題和 Cloud Scheduler 工作的權限。
- 具備 Digital Guardian Management Console (DGMC) 的特殊權限。
- 存取 Digital Guardian Analytics & Reporting Cloud (ARC) 租戶設定。
- 在 DGMC 中設定 Cloud 服務的管理員權限。
- 在 DGMC 中建立的匯出設定檔,且包含有效的 GUID。
建立 Google Cloud Storage bucket
- 前往 Google Cloud 控制台。
- 選取專案或建立新專案。
- 在導覽選單中,依序前往「Cloud Storage」>「bucket」。
- 按一下「建立值區」。
請提供下列設定詳細資料:
設定 值 為 bucket 命名 輸入全域不重複的名稱 (例如 digitalguardian-edr-logs)位置類型 根據需求選擇 (區域、雙區域、多區域) 位置 選取最接近執行個體的位置 (例如 us-central1)儲存空間級別 標準 (建議用於經常存取的記錄) 存取控管 統一 (建議) 保護工具 選用:啟用物件版本管理或保留政策 點選「建立」。
收集 Digital Guardian API 憑證
取得 API 憑證
從 ARC 租戶設定取得用戶端 ID 和用戶端密鑰
- 登入 Digital Guardian ARC 入口網站。
- 前往「ARC 租戶設定」。
- 複製並儲存下列值:
- 租戶 ID:這是您的用戶端 ID。
- 驗證權杖:這是您的用戶端密鑰。
從 DGMC 取得閘道網址
- 登入 Digital Guardian Management Console (DGMC)。
- 依序前往「系統」>「設定」>「雲端服務」。
- 在「API 存取權」部分,記錄:
- Access Gateway 基準網址:例如
https://accessgw-usw.msp.digitalguardian.com - 授權伺服器網址:例如
https://authsrv.msp.digitalguardian.com/as/token.oauth2
- Access Gateway 基準網址:例如
建立及設定匯出設定檔
- 在 DGMC 中,依序前往「管理」>「報告」>「匯出設定檔」。
- 按一下「建立匯出設定檔」。
- 將「匯出格式」設為「JSON 平面資料表」。
- 按一下「儲存」,然後從設定檔詳細資料複製 GUID (格式:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)。
建立 Cloud Run 函式
準備函式來源檔案
requirements.txt
functions-framework==3.* google-cloud-storage==2.* urllib3==2.*main.py
"""Cloud Run function to ingest Digital Guardian EDR logs into GCS.""" import json import os import time import urllib.parse from datetime import datetime, timezone import functions_framework import urllib3 from google.cloud import storage GCS_BUCKET = os.environ["GCS_BUCKET"] GCS_PREFIX = os.environ.get("GCS_PREFIX", "digitalguardian_edr") STATE_KEY = os.environ.get("STATE_KEY", "digitalguardian_edr_state.json") AUTH_SERVER_URL = os.environ["AUTH_SERVER_URL"] ARC_SERVER_URL = os.environ["ARC_SERVER_URL"] CLIENT_ID = os.environ["CLIENT_ID"] CLIENT_SECRET = os.environ["CLIENT_SECRET"] EXPORT_PROFILE_GUID = os.environ["EXPORT_PROFILE_GUID"] MAX_RECORDS = int(os.environ.get("MAX_RECORDS", "10000")) http = urllib3.PoolManager() gcs = storage.Client() def _get_access_token() -> str: body = urllib.parse.urlencode({ "grant_type": "client_credentials", "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET, "scope": "client", }) resp = http.request( "POST", AUTH_SERVER_URL, body=body, headers={"Content-Type": "application/x-www-form-urlencoded"}, ) if resp.status != 200: raise RuntimeError(f"OAuth token request failed: {resp.status}") return json.loads(resp.data.decode("utf-8"))["access_token"] def _arc_get(token: str, path: str, retries: int = 5) -> dict: url = f"{ARC_SERVER_URL}{path}" headers = {"Authorization": f"Bearer {token}", "Accept": "application/json"} backoff = 2 for attempt in range(retries): resp = http.request("GET", url, headers=headers) if resp.status == 200: return json.loads(resp.data.decode("utf-8")) if resp.status == 429: time.sleep(backoff * (2 ** attempt)) continue raise RuntimeError(f"ARC API error: {resp.status}") raise RuntimeError("ARC API rate limit exceeded.") def _arc_acknowledge(token: str) -> None: url = f"{ARC_SERVER_URL}/rest/1.0/export/{EXPORT_PROFILE_GUID}/acknowledge" headers = {"Authorization": f"Bearer {token}", "Accept": "application/json"} resp = http.request("POST", url, headers=headers) if resp.status not in (200, 204): raise RuntimeError(f"ARC acknowledge failed: {resp.status}") def _load_state() -> dict: bucket = gcs.bucket(GCS_BUCKET) blob = bucket.blob(f"{GCS_PREFIX}/{STATE_KEY}") return json.loads(blob.download_as_text()) if blob.exists() else {} def _save_state(state: dict) -> None: bucket = gcs.bucket(GCS_BUCKET) blob = bucket.blob(f"{GCS_PREFIX}/{STATE_KEY}") blob.upload_from_string(json.dumps(state), content_type="application/json") def _fetch_export(token: str) -> list: path = f"/rest/1.0/export/{EXPORT_PROFILE_GUID}" data = _arc_get(token, path) records = data if isinstance(data, list) else data.get("data", []) return records[:MAX_RECORDS] def _write_ndjson(records: list, run_ts: str) -> str: bucket = gcs.bucket(GCS_BUCKET) blob_path = f"{GCS_PREFIX}/year={run_ts[:4]}/month={run_ts[5:7]}/day={run_ts[8:10]}/{run_ts}_export.ndjson" blob = bucket.blob(blob_path) ndjson = "\n".join(json.dumps(r, separators=(",", ":")) for r in records) blob.upload_from_string(ndjson, content_type="application/x-ndjson") return blob_path @functions_framework.cloud_event def main(cloud_event): state = _load_state() now = datetime.now(timezone.utc) token = _get_access_token() records = _fetch_export(token) if not records: return "OK" run_ts = now.strftime("%Y-%m-%dT%H%M%SZ") blob_path = _write_ndjson(records, run_ts) _arc_acknowledge(token) state["last_run"] = now.isoformat() _save_state(state) return "OK"
擷取 Google SecOps 服務帳戶並設定動態饋給
- 依序前往「SIEM 設定」>「動態消息」。
- 按一下「新增動態消息」。
- 選取「Google Cloud Storage V2」做為「來源類型」。
- 選取「Digital Guardian EDR」做為「記錄類型」。
- 按一下「取得服務帳戶」,然後複製電子郵件地址。
- 指定儲存空間 bucket 網址:
gs://digitalguardian-edr-logs/digitalguardian_edr/(請務必加上結尾斜線)。
UDM 對應表
| 記錄欄位 | UDM 對應 | 邏輯 |
|---|---|---|
Application |
target.application |
直接複製值。 |
Bytes_Written |
network.sent_bytes |
已轉換為 uinteger。 |
Command_Line |
principal.process.command_line |
已清除結尾引號。 |
Computer_Name |
principal.hostname |
來源主機名稱對應。 |
Destination_File |
target.file.names |
直接對應。 |
IP_Address |
principal.ip |
主要 IP 位址。 |
Process_PID |
principal.process.pid |
處理 ID 對應。 |
Rule |
security_result.rule_name |
直接對應。 |
Severity |
security_result.severity |
縮放至「低」、「中」、「高」、「重大」。 |
URL_Path |
target.url |
網頁目的地對應。 |
User_Name |
principal.user.userid |
透過 grok 擷取。 |
security_action |
security_result.action |
直接對應。 |
| 不適用 | metadata.product_name |
設為「Enterprise DLP Platform」。 |
| 不適用 | metadata.vendor_name |
設為「DigitalGuardian」。 |
Destination_File_Encryption |
event.idm.read_only_udm.target.resource.attribute.labels |
從變更記錄對應 |
Alert_ID |
event.idm.read_only_udm.security_result.detection_fields |
從變更記錄對應 |
Computer_Type |
event.idm.read_only_udm.security_result.detection_fields |
從變更記錄對應 |
Operation |
event.idm.read_only_udm.security_result.detection_fields |
從變更記錄對應 |
Printer_Jobname |
event.idm.read_only_udm.target.resource.attribute.labels |
從變更記錄對應 |
Was_Destination_Classified |
event.idm.read_only_udm.target.resource.attribute.labels |
從變更記錄對應 |
Was_Source_Classified |
event.idm.read_only_udm.src.resource.attribute.labels |
從變更記錄對應 |
Source_File_Encryption |
event.idm.read_only_udm.src.resource.attribute.labels |
從變更記錄對應 |
Source_Device_ID |
event.idm.read_only_udm.src.resource.attribute.labels |
從變更記錄對應 |
Destination_Device_ID |
event.idm.read_only_udm.target.resource.attribute.labels |
從變更記錄對應 |
Detail_Event_ID |
event.idm.read_only_udm.metadata.product_log_id |
從變更記錄對應 |
Source_Device_Friendly_Name |
event.idm.read_only_udm.src.resource.name |
從變更記錄對應 |
Source_Device_Product_Name |
event.idm.read_only_udm.src.resource.resource_subtype |
從變更記錄對應 |
Source_Device_Serial_Number |
event.idm.read_only_udm.src.resource.attribute.labels |
從變更記錄對應 |
File_Size_MB |
event.idm.read_only_udm.target.resource.attribute.labels |
從變更記錄對應 |
Detail_File_Size_MB |
event.idm.read_only_udm.target.resource.attribute.labels |
從變更記錄對應 |
Event_ID |
event.idm.read_only_udm.security_result.rule_id |
從變更記錄對應 |
Block_Code |
event.idm.read_only_udm.security_result.detection_fields |
從變更記錄對應 |
Policy |
event.idm.read_only_udm.security_result.detection_fields |
從變更記錄對應 |
Agent_Local_Date |
event.idm.read_only_udm.additional.fields |
從變更記錄對應 |
Agent_Local_Time |
event.idm.read_only_udm.additional.fields |
從變更記錄對應 |
Agent_UTC_Time |
event.idm.read_only_udm.additional.fields |
從變更記錄對應 |
Source_File |
src.file.names |
從變更記錄對應 |
Source_File_Extension |
src.file.mime_type |
從變更記錄對應 |
Destination_File_Extension |
target.file.mime_type |
從變更記錄對應 |
Source_Drive_Type |
security_result.detection_fields |
從變更記錄對應 |
Destination_Drive_Type |
security_result.detection_fields |
從變更記錄對應 |
Was_Removable |
security_result.detection_fields |
從變更記錄對應 |
Was_Source_Removable |
security_result.detection_fields |
從變更記錄對應 |
Product_Version |
metadata.product_version |
從變更記錄對應 |
Process_SHA256_Hash |
target.process.file.sha256 |
從變更記錄對應 |
MD5_Checksum |
target.process.file.md5 |
從變更記錄對應 |
File_Extension |
additional.fields |
從變更記錄對應 |
Protocol |
network.ip_protocol |
從變更記錄對應 |
Command_Line1 |
principal.process.command_line |
從變更記錄對應 |
Network_Direction |
network.direction |
從變更記錄對應 |
Local_Port |
principal.port |
從變更記錄對應 |
Remote_Port |
target.port |
從變更記錄對應 |
Dll_SHA1_Hash |
target.process.file.sha1 |
從變更記錄對應 |
變更記錄
還有其他問題嗎?向社群成員和 Google SecOps 專業人員尋求答案。