收集 Oracle Cloud Infrastructure 稽核記錄
本文說明如何使用 Amazon S3,將 Oracle Cloud Infrastructure 稽核記錄檔擷取至 Google Security Operations。
事前準備
請確認您已完成下列事前準備事項:
- Google SecOps 執行個體。
- 具備建立及管理下列項目的權限的 Oracle Cloud Infrastructure 帳戶:
- 服務連接器中樞
- Oracle Functions
- 保管箱和密鑰
- 動態群組和 IAM 政策
- 記錄
- 具有建立及管理權限的 AWS 帳戶:
- S3 儲存貯體
- IAM 使用者和政策
建立 Amazon S3 儲存貯體
- 登入 AWS 管理主控台。
- 依序前往「S3」>「建立 bucket」。
- 請提供下列設定詳細資料:
- Bucket name:輸入不重複的名稱 (例如
oci-audit-logs-bucket)。 - AWS 區域:選取區域 (例如
us-east-1)。 - 其他選項保留預設設定。
- Bucket name:輸入不重複的名稱 (例如
- 按一下「建立值區」。
- 儲存 bucket 的「名稱」和「區域」,稍後會用到。
在 AWS 中為 OCI Functions 建立 IAM 使用者
- 登入 AWS 管理主控台。
- 依序前往「IAM」>「Users」>「Add users」。
- 請提供下列設定詳細資料:
- 使用者名稱:輸入使用者名稱 (例如
oci-functions-s3-user)。 - 存取權類型:選取「存取金鑰 - 程式輔助存取」。
- 使用者名稱:輸入使用者名稱 (例如
- 點選 [Next: Permissions] (下一步:權限)。
- 按一下「Attach existing policies directly」(直接附加現有政策)。
- 搜尋並選取 AmazonS3FullAccess 政策。
- 按一下「下一步:代碼」。
- 按一下 [下一步:檢閱]。
- 按一下「建立使用者」。
- 重要事項:在成功頁面中,複製並儲存下列憑證:
- 存取金鑰 ID
- 存取密鑰
在 OCI Vault 中儲存 AWS 憑證
如要安全地儲存 AWS 憑證,請務必使用 Oracle Cloud Infrastructure Vault,而不是在函式程式碼中硬式編碼。
建立 Vault 和主加密金鑰
- 登入 Oracle Cloud Console。
- 依序前往「身分與安全性」>「Vault」。
- 如果沒有 Vault,請按一下「建立 Vault」。
- 請提供下列設定詳細資料:
- 在區間中建立:選取區間。
- 「Name」(名稱):輸入名稱 (例如
oci-functions-vault)。
- 按一下「建立 Vault」。
- 建立保管箱後,按一下保管箱名稱即可開啟。
- 在「主加密金鑰」下方,按一下「建立金鑰」。
- 請提供下列設定詳細資料:
- 保護模式:軟體
- 「Name」(名稱):輸入名稱 (例如
oci-functions-key)。 - 金鑰形狀:演算法:AES
- 金鑰形狀:長度:256 位元
- 按一下 [Create Key] (建立金鑰)。
建立 AWS 憑證的密鑰
- 在 Vault 中,按一下「Secrets」下方的「Create Secret」。
- 請提供 AWS 存取金鑰的下列設定詳細資料:
- 在區間中建立:選取區間。
- Name (名稱):
aws-access-key - 說明:S3 的 AWS 存取金鑰
- 加密金鑰:選取您建立的主加密金鑰。
- 密鑰類型內容:純文字
- 私密內容:貼上 AWS 存取金鑰 ID。
- 按一下「建立密鑰」。
- 複製並儲存這項密鑰的 OCID (看起來像
ocid1.vaultsecret.oc1...)。 - 再次按一下「建立密鑰」,建立第二個密鑰。
- 請提供 AWS 密鑰的下列設定詳細資料:
- 在區間中建立:選取區間。
- Name (名稱):
aws-secret-key - 說明:S3 的 AWS 密鑰
- 加密金鑰:選取相同的主加密金鑰。
- 密鑰類型內容:純文字
- 私密內容:貼上 AWS 私密存取金鑰。
- 按一下「建立密鑰」。
- 複製並儲存這個密鑰的 OCID。
為 OCI 函式建立動態群組
- 登入 Oracle Cloud Console。
- 依序前往「身分與安全性」>「身分」>「動態群組」。
- 按一下「建立動態群組」。
請提供下列設定詳細資料:
- Name (名稱):
oci-functions-dynamic-group - 說明:OCI Functions 存取 Vault 密鑰的動態群組
比對規則:輸入下列規則 (將
<your_compartment_ocid>替換成分區 OCID):ALL {resource.type = 'fnfunc', resource.compartment.id = '<your_compartment_ocid>'}
- Name (名稱):
點選「建立」。
建立保管箱存取權的身分與存取權管理政策
- 登入 Oracle Cloud Console。
- 依序前往「身分與安全性」>「身分」>「政策」。
- 選取要建立政策的區間。
- 點選「建立政策」。
請提供下列設定詳細資料:
- Name (名稱):
oci-functions-vault-access-policy - 說明:允許 OCI Functions 從 Vault 讀取密碼
- 政策建立工具:切換「顯示手動編輯器」。
政策陳述式:輸入下列內容 (將
<compartment_name>替換為區間名稱):allow dynamic-group oci-functions-dynamic-group to manage secret-family in compartment <compartment_name>
- Name (名稱):
點選「建立」。
建立 OCI 函式應用程式
- 登入 Oracle Cloud Console。
- 依序前往「開發人員服務」>「應用程式」(位於「功能」下方)。
- 點選「Create Application」(建立應用程式)。
- 請提供下列設定詳細資料:
- 「Name」(名稱):輸入名稱 (例如
oci-logs-to-s3-app)。 - VCN:選取區間中的 VCN。
- 子網路:選取一或多個子網路。
- 「Name」(名稱):輸入名稱 (例如
- 點選「建立」。
建立及部署 OCI 函式
設定 Cloud Shell (建議做法)
- 在 Oracle Cloud 控制台中,按一下右上角的「Cloud Shell」圖示。
- 等待 Cloud Shell 初始化。
建立函式
在 Cloud Shell 中,為函式建立新目錄:
mkdir pushlogs cd pushlogs初始化新的 Python 函式:
fn init --runtime python這會建立三個檔案:
func.py、func.yaml和requirements.txt。
更新 func.py
將
func.py的內容替換為下列程式碼:import io import json import logging import boto3 import oci import base64 import os from fdk import response def handler(ctx, data: io.BytesIO = None): """ OCI Function to push audit logs from OCI Logging to AWS S3 """ try: # Parse incoming log data from Service Connector funDataStr = data.read().decode('utf-8') funData = json.loads(funDataStr) logging.getLogger().info(f"Received {len(funData)} log entries") # Replace these with your actual OCI Vault secret OCIDs secret_key_id = "ocid1.vaultsecret.oc1..<your_secret_key_ocid>" access_key_id = "ocid1.vaultsecret.oc1..<your_access_key_ocid>" # Replace with your S3 bucket name s3_bucket_name = "oci-audit-logs-bucket" # Use Resource Principals for OCI authentication signer = oci.auth.signers.get_resource_principals_signer() secret_client = oci.secrets.SecretsClient({}, signer=signer) def read_secret_value(secret_client, secret_id): """Retrieve and decode secret value from OCI Vault""" response = secret_client.get_secret_bundle(secret_id) base64_secret_content = response.data.secret_bundle_content.content base64_secret_bytes = base64_secret_content.encode('ascii') base64_message_bytes = base64.b64decode(base64_secret_bytes) secret_content = base64_message_bytes.decode('ascii') return secret_content # Retrieve AWS credentials from OCI Vault awsaccesskey = read_secret_value(secret_client, access_key_id) awssecretkey = read_secret_value(secret_client, secret_key_id) # Initialize boto3 session with AWS credentials session = boto3.Session( aws_access_key_id=awsaccesskey, aws_secret_access_key=awssecretkey ) s3 = session.resource('s3') # Process each log entry for i in range(0, len(funData)): # Use timestamp as filename filename = funData[i].get('time', f'log_{i}') # Remove special characters from filename filename = filename.replace(':', '-').replace('.', '-') logging.getLogger().info(f"Processing log entry: {filename}") # Write log entry to temporary file temp_file = f'/tmp/{filename}.json' with open(temp_file, 'w', encoding='utf-8') as f: json.dump(funData[i], f, ensure_ascii=False, indent=4) # Upload to S3 s3_key = f'{filename}.json' s3.meta.client.upload_file( Filename=temp_file, Bucket=s3_bucket_name, Key=s3_key ) logging.getLogger().info(f"Uploaded {s3_key} to S3 bucket {s3_bucket_name}") # Clean up temporary file os.remove(temp_file) return response.Response( ctx, response_data=json.dumps({ "status": "success", "processed_logs": len(funData) }), headers={"Content-Type": "application/json"} ) except Exception as e: logging.getLogger().error(f"Error processing logs: {str(e)}") return response.Response( ctx, response_data=json.dumps({ "status": "error", "message": str(e) }), headers={"Content-Type": "application/json"}, status_code=500 )- 將
secret_key_id替換為 AWS 密鑰的實際保存庫密鑰 OCID - 將
access_key_id換成 AWS 存取金鑰的實際保存庫密鑰 OCID - 請將
s3_bucket_name替換成實際的 S3 值區名稱
- 將
更新 func.yaml
將 func.yaml 改成以下內容:
schema_version: 20180708
name: pushlogs
version: 0.0.1
runtime: python
build_image: fnproject/python:3.9-dev
run_image: fnproject/python:3.9
entrypoint: /python/bin/fdk /function/func.py handler
memory: 256
更新 requirements.txt
將
requirements.txt改成以下內容:fdk>=0.1.56 boto3 oci
部署函式
設定 Fn 內容,以使用您的應用程式:
fn use context <region-context> fn update context oracle.compartment-id <compartment-ocid>部署函式:
fn -v deploy --app oci-logs-to-s3-app等待部署作業完成。輸出內容應該會指出函式已部署成功。
確認函式是否已建立:
fn list functions oci-logs-to-s3-app
建立服務連接器,將 OCI 稽核記錄傳送至函式
- 登入 Oracle Cloud Console。
- 依序前往「Analytics & AI」>「Messaging」>「Service Connector Hub」。
- 選取要建立服務連接器的區間。
- 按一下「建立服務連接器」。
設定服務連接器詳細資料
- 請提供下列設定詳細資料:
服務連接器資訊:
* 連接器名稱:輸入描述性名稱 (例如 audit-logs-to-s3-connector)。
* 說明:選用說明 (例如「將 OCI 稽核記錄轉送至 AWS S3」)。
* 資源區間:選取區間。
設定來源
- 在「設定來源」下方:
- 來源:選取「記錄」。
- 區間:選取包含稽核記錄的區間。
- 記錄群組:選取
_Audit(這是稽核記錄的預設記錄群組)。 - 記錄:按一下「+ 另一個記錄」。
- 選取區間的稽核記錄 (例如
_Audit_Include_Subcompartment)。
設定目標
- 在「設定目標」下方:
- 目標:選取「函式」。
- 區間:選取包含函式應用程式的區間。
- 「Function Application」(函式應用程式):選取
oci-logs-to-s3-app(您先前建立的應用程式)。 - 函式:選取
pushlogs(您部署的函式)。
設定政策
在「設定政策」下方:
- 查看顯示的必要 IAM 政策陳述式。
- 按一下「建立」,自動建立必要政策。
按一下「建立」,建立服務連接器。
等待服務連結器建立並啟用。狀態應變更為「有效」。
確認記錄是否已推送至 AWS S3
- 登入 Oracle Cloud Console。
- 執行一些會產生稽核記錄的動作 (例如建立或修改資源)。
- 等待 2 到 5 分鐘,讓系統處理記錄。
- 登入 AWS 管理主控台。
- 依序前往「S3」>「Buckets」。
- 按一下 bucket (例如
oci-audit-logs-bucket)。 - 確認 JSON 記錄檔是否顯示在 bucket 中。
為 Google SecOps 設定 AWS S3 值區和 IAM
為 Chronicle 建立 IAM 使用者
- 登入 AWS 管理主控台。
- 依序前往「IAM」>「Users」>「Add users」。
- 請提供下列設定詳細資料:
- 使用者名稱:輸入
chronicle-s3-reader。 - 存取權類型:選取「存取金鑰 - 程式輔助存取」。
- 使用者名稱:輸入
- 點選 [Next: Permissions] (下一步:權限)。
- 按一下「Attach existing policies directly」(直接附加現有政策)。
- 搜尋並選取 AmazonS3ReadOnlyAccess 政策。
- 按一下「下一步:代碼」。
- 按一下 [下一步:檢閱]。
- 按一下「建立使用者」。
- 按一下「下載 CSV 檔案」,即可儲存「存取金鑰 ID」和「私密存取金鑰」。
- 按一下 [關閉]。
選用:建立自訂 IAM 政策,提供最低權限存取權
如要限制只能存取特定 bucket,請按照下列步驟操作:
- 依序前往「IAM」>「Policies」>「Create policy」。
- 按一下「JSON」分頁標籤。
輸入下列政策:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::oci-audit-logs-bucket", "arn:aws:s3:::oci-audit-logs-bucket/*" ] } ] }- 請將
oci-audit-logs-bucket替換成您的值區名稱。
- 請將
按一下「下一步:代碼」。
按一下 [下一步:檢閱]。
請提供下列設定詳細資料:
- Name (名稱):
chronicle-s3-read-policy - 說明:OCI 稽核記錄 bucket 的唯讀存取權
- Name (名稱):
點選「建立政策」。
返回「IAM」>「Users」,然後選取
chronicle-s3-reader使用者。依序點選「新增權限」>「直接附加政策」。
搜尋並選取
chronicle-s3-read-policy。如果先前新增了 AmazonS3ReadOnlyAccess 政策,請移除該政策。
按一下「Add permissions」。
在 Google SecOps 中設定資訊提供,以便擷取 Oracle Cloud 稽核記錄
- 依序前往「SIEM 設定」>「動態饋給」。
- 按一下「新增動態消息」。
- 在下一個頁面中,按一下「設定單一動態饋給」。
- 在「動態饋給名稱」欄位中輸入動態饋給名稱 (例如
Oracle Cloud Audit Logs)。 - 選取「Amazon S3 V2」做為「來源類型」。
- 選取「Oracle Cloud Infrastructure」做為「記錄類型」。
- 點選「下一步」。
- 指定下列輸入參數的值:
- S3 URI:輸入 S3 bucket URI (例如
s3://oci-audit-logs-bucket/)。 - 來源刪除選項:根據偏好選取刪除選項:
- 永不:建議用於測試和初始設定。
- 刪除已轉移的檔案:成功擷取檔案後刪除檔案 (適用於正式版,可管理儲存空間費用)。
- 檔案存在時間上限:包含在過去天數內修改的檔案。預設值為 180 天。
- 存取金鑰 ID:輸入您建立的 Chronicle IAM 使用者存取金鑰 ID。
- 存取密鑰:輸入您建立的 Chronicle IAM 使用者存取密鑰。
- 資產命名空間:資產命名空間。
- 擷取標籤:要套用至這個動態饋給事件的標籤。
- S3 URI:輸入 S3 bucket URI (例如
- 點選「下一步」。
- 在「Finalize」(完成) 畫面中檢查新的動態饋給設定,然後按一下「Submit」(提交)。
UDM 對應表
| 記錄欄位 | UDM 對應 | 邏輯 |
|---|---|---|
data.request.headers.authorization.0 |
event.idm.read_only_udm.additional.fields |
從 data.request.headers.authorization.0 取得值,並以鍵/值組合的形式加入,其中鍵為「Request Headers Authorization」。 |
data.compartmentId |
event.idm.read_only_udm.additional.fields |
從 data.compartmentId 取得的值,並以鍵/值組合的形式新增,其中鍵為「compartmentId」。 |
data.compartmentName |
event.idm.read_only_udm.additional.fields |
從 data.compartmentName 取得值,並新增為鍵/值組合,其中鍵為「compartmentName」。 |
data.response.headers.Content-Length.0 |
event.idm.read_only_udm.additional.fields |
從 data.response.headers.Content-Length.0 取得值,並以鍵/值組合形式新增,其中鍵為「Response Headers Content-Length」。 |
data.response.headers.Content-Type.0 |
event.idm.read_only_udm.additional.fields |
從 data.response.headers.Content-Type.0 取得值,並以鍵/值組合形式新增,其中鍵為「Response Headers Content-Type」。 |
data.eventGroupingId |
event.idm.read_only_udm.additional.fields |
從 data.eventGroupingId 取得的值,並以鍵/值組合的形式加入,其中鍵為「eventGroupingId」。 |
oracle.tenantid、data.identity.tenantId |
event.idm.read_only_udm.additional.fields |
如有 oracle.tenantid,則會從該處取值,否則會從 data.identity.tenantId 取值。系統會將其新增為鍵/值組合,其中鍵為「tenantId」。 |
data.message |
event.idm.read_only_udm.metadata.description |
取自 data.message 的值。 |
time |
event.idm.read_only_udm.metadata.event_timestamp |
從 time 取得的值,並剖析為 ISO8601 時間戳記。 |
event.idm.read_only_udm.metadata.event_type |
預設為 GENERIC_EVENT。如果主體 (IP 或主機名稱) 和目標 IP 都存在,請設為 NETWORK_CONNECTION。如果只有主體,請設為 STATUS_UPDATE。 |
|
time |
event.idm.read_only_udm.metadata.ingested_timestamp |
如果 oracle.ingestedtime 不為空白,系統會從 time 欄位取得值,並剖析為 ISO8601 時間戳記。 |
oracle.tenantid |
event.idm.read_only_udm.metadata.product_deployment_id |
取自 oracle.tenantid 的值。 |
type |
event.idm.read_only_udm.metadata.product_event_type |
取自 type 的值。 |
oracle.logid |
event.idm.read_only_udm.metadata.product_log_id |
取自 oracle.logid 的值。 |
specversion |
event.idm.read_only_udm.metadata.product_version |
取自 specversion 的值。 |
data.request.action |
event.idm.read_only_udm.network.http.method |
取自 data.request.action 的值。 |
data.identity.userAgent |
event.idm.read_only_udm.network.http.parsed_user_agent |
從 data.identity.userAgent 擷取並剖析的值。 |
data.response.status |
event.idm.read_only_udm.network.http.response_code |
從 data.response.status 取得值並轉換為整數。 |
data.protocol |
event.idm.read_only_udm.network.ip_protocol |
data.protocol 中的數值會轉換為字串表示法 (例如 6 會變成「TCP」,17 會變成「UDP」)。 |
data.bytesOut |
event.idm.read_only_udm.network.sent_bytes |
從 data.bytesOut 取得的值,並轉換為無正負號整數。 |
data.packets |
event.idm.read_only_udm.network.sent_packets |
從 data.packets 取得值並轉換為整數。 |
data.identity.consoleSessionId |
event.idm.read_only_udm.network.session_id |
取自 data.identity.consoleSessionId 的值。 |
id |
event.idm.read_only_udm.principal.asset.product_object_id |
取自 id 的值。 |
source |
event.idm.read_only_udm.principal.hostname |
取自 source 的值。 |
data.sourceAddress、data.identity.ipAddress |
event.idm.read_only_udm.principal.ip |
data.sourceAddress 和 data.identity.ipAddress 的值會合併到這個欄位。 |
data.sourcePort |
event.idm.read_only_udm.principal.port |
從 data.sourcePort 取得值並轉換為整數。 |
data.request.headers.X-Forwarded-For.0 |
event.idm.read_only_udm.principal.resource.attribute.labels |
從 data.request.headers.X-Forwarded-For.0 取得值,並新增為鍵/值組合,其中鍵為「x forward」。 |
oracle.compartmentid |
event.idm.read_only_udm.principal.resource.attribute.labels |
從 oracle.compartmentid 取得的值,並以鍵/值組合形式新增,其中鍵為「compartmentid」。 |
oracle.loggroupid |
event.idm.read_only_udm.principal.resource.attribute.labels |
從 oracle.loggroupid 取得值,並以鍵/值組合形式加入,其中鍵為「loggroupid」。 |
oracle.vniccompartmentocid |
event.idm.read_only_udm.principal.resource.attribute.labels |
從 oracle.vniccompartmentocid 取得值,並新增為鍵/值組合,其中鍵為「vniccompartmentocid」。 |
oracle.vnicocid |
event.idm.read_only_udm.principal.resource.attribute.labels |
從 oracle.vnicocid 取得值,並新增為鍵/值組合,其中鍵為「vnicocid」。 |
oracle.vnicsubnetocid |
event.idm.read_only_udm.principal.resource.attribute.labels |
從 oracle.vnicsubnetocid 取得值,並新增為鍵/值組合,其中鍵為「vnicsubnetocid」。 |
data.flowid |
event.idm.read_only_udm.principal.resource.product_object_id |
取自 data.flowid 的值。 |
data.identity.credentials |
event.idm.read_only_udm.principal.user.attribute.labels |
從 data.identity.credentials 取得值,並新增為鍵/值組合,其中鍵為「credentials」。 |
data.identity.principalName |
event.idm.read_only_udm.principal.user.user_display_name |
取自 data.identity.principalName 的值。 |
data.identity.principalId |
event.idm.read_only_udm.principal.user.userid |
取自 data.identity.principalId 的值。 |
data.action |
event.idm.read_only_udm.security_result.action |
預設為 UNKNOWN_ACTION。如果 data.action 為「REJECT」,則會設為 BLOCK。如果 data.action 為「ACCEPT」,則此值會設為 ALLOW。 |
data.endTime |
event.idm.read_only_udm.security_result.detection_fields |
從 data.endTime 取得的值,並以鍵/值組合形式新增,其中鍵為「endTime」。 |
data.startTime |
event.idm.read_only_udm.security_result.detection_fields |
從 data.startTime 取得值,並新增為鍵/值組合,其中鍵為「startTime」。 |
data.status |
event.idm.read_only_udm.security_result.detection_fields |
從 data.status 取得值,並新增為鍵/值組合,其中鍵為「status」。 |
data.version |
event.idm.read_only_udm.security_result.detection_fields |
從 data.version 取得值,並新增為鍵/值組合,其中鍵為「version」。 |
data.destinationAddress |
event.idm.read_only_udm.target.ip |
取自 data.destinationAddress 的值。 |
data.destinationPort |
event.idm.read_only_udm.target.port |
從 data.destinationPort 取得值並轉換為整數。 |
data.request.path |
event.idm.read_only_udm.target.url |
取自 data.request.path 的值。 |
event.idm.read_only_udm.metadata.product_name |
設為「ORACLE CLOUD AUDIT」。 | |
event.idm.read_only_udm.metadata.vendor_name |
設為「ORACLE」。 |
還有其他問題嗎?向社群成員和 Google SecOps 專業人員尋求答案。