Oracle Cloud Infrastructure 監査ログを収集する
このドキュメントでは、次のいずれかの方法を使用して Oracle Cloud Infrastructure(OCI)監査ログを Google Security Operations に取り込む方法について説明します。
- 方法 1: Cloud Storage: OCI 関数がログを Cloud Storage バケットに書き込み、Google SecOps フィードがバケットからログを読み取ります。
- 方法 2: Webhook: OCI 関数がログを Google SecOps Webhook フィードに直接送信します。この方法では、Cloud Storage バケットは使用しません。
OCI は Cloud Storage または HTTPS エンドポイントにログを直接送信できないため、どちらの方法でも OCI Connector Hub を使用して監査ログを関数に配信します。
Oracle Cloud Infrastructure Audit サービスは、サポートされているすべての OCI パブリック API エンドポイントへの呼び出しをログイベントとして自動的に記録します。すべてのサービスが OCI Audit によるロギングをサポートしています。OCI Audit によって記録されるログイベントには、OCI コンソール、CLI、SDK、独自のカスタム クライアント、またはその他の OCI サービスによって行われた API 呼び出しが含まれます。
始める前に
次の前提条件を満たしていることを確認してください。
- Google SecOps インスタンス
- Oracle Cloud コンソールへの特権アクセス。次の作成と管理を行う権限が必要です。
- Connector Hub コネクタ
- Functions アプリケーションと関数
- IAM ポリシー
- OCI Function 用のインターネット アクセスを備えた VCN サブネット
- OCI Cloud Shell または Fn CLI を使用するローカル環境
- 方法 1 の場合: Cloud Storage API が有効になっている Google Cloud プロジェクト。Cloud Storage バケット、サービス アカウント、バケットの Identity and Access Management(IAM)ポリシーを作成する権限。
- 方法 2 の場合: Google SecOps インスタンスにリンクされている Google Cloud プロジェクトで API キーを作成する権限
方法 1: Cloud Storage
Cloud Storage バケットを作成する
- Google Cloud コンソールに移動します。
- プロジェクトを選択するか、新しいプロジェクトを作成します。
- ナビゲーション メニューで、[Cloud Storage] > [バケット] に移動します。
- [バケットを作成] をクリックします。
次の構成情報を提供してください。
設定 値 バケットに名前を付ける グローバルに一意の名前( oci-audit-logs-gcsなど)を入力します。ロケーション タイプ ニーズに応じて選択します(リージョン、デュアルリージョン、マルチリージョン)。 ロケーション ロケーションを選択します(例: us-central1)。ストレージ クラス Standard(頻繁にアクセスするログにおすすめ) アクセス制御 均一(推奨) 保護ツール 省略可: オブジェクトのバージョニングまたは保持ポリシーを有効にする [作成] をクリックします。
監査ログを Cloud Storage にエクスポートするように OCI を構成する
Oracle Cloud Infrastructure は、Cloud Storage への組み込みエクスポートをサポートしていません。OCI Service Connector Hub と Function を使用して、監査ログを Cloud Storage に転送します。
ログを Cloud Storage に転送する OCI 関数を作成する
- Oracle Cloud コンソールにログインします。
- [Developer Services] > [Functions] > [Applications] に移動します。
- 関数アプリケーションを作成するコンパートメントを選択します。
- [アプリケーションを作成] をクリックします。
- 次の構成情報を指定します。
- 名前: 「
audit-logs-to-gcs-app」と入力します。 - VCN: Virtual Cloud Network を選択します。
- サブネット: インターネット アクセスが可能なサブネットを選択します。
- 名前: 「
- [作成] をクリックします。
- アプリケーションが作成されたら、[Getting Started] をクリックし、手順に沿って Fn CLI を使用してローカル開発環境を設定します。
ローカルマシンに新しい関数ディレクトリを作成します。
mkdir oci-audit-to-gcs cd oci-audit-to-gcsPython 関数を初期化します。
fn init --runtime python oci-audit-to-gcs cd oci-audit-to-gcsfunc.pyの内容を次のコードに置き換えます。import io import json import logging import os from fdk import response from google.cloud import storage from google.oauth2 import service_account from datetime import datetime # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger() # Environment variables GCS_BUCKET = os.environ.get('GCS_BUCKET') GCS_PREFIX = os.environ.get('GCS_PREFIX', 'oci-audit-logs') GCS_CREDENTIALS_JSON = os.environ.get('GCS_CREDENTIALS_JSON') def handler(ctx, data: io.BytesIO = None): """ Oracle Cloud Infrastructure Function to forward Audit logs to GCS. Args: ctx: Function context data: Input data containing Audit log events """ if not all([GCS_BUCKET, GCS_CREDENTIALS_JSON]): logger.error('Missing required environment variables: GCS_BUCKET or GCS_CREDENTIALS_JSON') return response.Response( ctx, response_data=json.dumps({"error": "Missing configuration"}), headers={"Content-Type": "application/json"} ) try: # Parse input data body = json.loads(data.getvalue()) logger.info(f"Received event: {json.dumps(body)}") # Extract log entries log_entries = [] if isinstance(body, list): log_entries = body elif isinstance(body, dict): # Service Connector Hub sends data in specific format if 'data' in body: log_entries = [body['data']] if isinstance(body['data'], dict) else body['data'] else: log_entries = [body] if not log_entries: logger.info("No log entries to process") return response.Response( ctx, response_data=json.dumps({"status": "no_logs"}), headers={"Content-Type": "application/json"} ) # Initialize GCS client with service account credentials credentials_dict = json.loads(GCS_CREDENTIALS_JSON) credentials = service_account.Credentials.from_service_account_info(credentials_dict) storage_client = storage.Client(credentials=credentials, project=credentials_dict.get('project_id')) bucket = storage_client.bucket(GCS_BUCKET) # Write logs to GCS as NDJSON timestamp = datetime.utcnow().strftime('%Y%m%d_%H%M%S_%f') object_key = f"{GCS_PREFIX}/logs_{timestamp}.ndjson" blob = bucket.blob(object_key) ndjson = '\n'.join([json.dumps(entry, ensure_ascii=False) for entry in log_entries]) + '\n' blob.upload_from_string(ndjson, content_type='application/x-ndjson') logger.info(f"Wrote {len(log_entries)} records to gs://{GCS_BUCKET}/{object_key}") return response.Response( ctx, response_data=json.dumps({"status": "success", "records": len(log_entries)}), headers={"Content-Type": "application/json"} ) except Exception as e: logger.error(f'Error processing logs: {str(e)}') return response.Response( ctx, response_data=json.dumps({"error": str(e)}), headers={"Content-Type": "application/json"}, status_code=500 )次の依存関係で
requirements.txtを更新します。fdk>=0.1.0 google-cloud-storage>=2.0.0 google-auth>=2.0.0関数を OCI にデプロイします。
fn -v deploy --app audit-logs-to-gcs-appデプロイが完了したら、関数 OCID をメモします。次のステップでこれを使用します。
関数の環境変数を構成する
- Oracle Cloud コンソールで、[Developer Services] > [Functions] > [Applications] に移動します。
- アプリケーション(
audit-logs-to-gcs-app)をクリックします。 - 関数名(
oci-audit-to-gcs)をクリックします。 - [構成] をクリックします。
次の構成変数を追加します。
キー 値 GCS_BUCKETCloud Storage バケット名(例: oci-audit-logs-gcs)GCS_PREFIXログファイルの接頭辞(例: oci-audit-logs)GCS_CREDENTIALS_JSONGoogle Cloud サービス アカウント キーの JSON 文字列(下記参照) [変更を保存] をクリックします。
OCI 関数用の Google Cloud サービス アカウントを作成する
OCI 関数には、Cloud Storage バケットに書き込むための Google Cloud サービス アカウントが必要です。
- Google Cloud コンソールで、[IAM と管理] > [サービス アカウント] に移動します。
- [サービス アカウントを作成] をクリックします。
- 次の構成情報を指定します。
- サービス アカウント名: 「
oci-function-gcs-writer」と入力します。 - サービス アカウントの説明: 「
Service account for OCI Function to write Audit logs to GCS」と入力します。
- サービス アカウント名: 「
- [作成して続行] をクリックします。
- [このサービス アカウントにプロジェクトへのアクセスを許可する] セクションで、次のロールを追加します。
- [ロールを選択] をクリックします。
- [Storage オブジェクト管理者] を検索して選択します。
- [続行] をクリックします。
- [完了] をクリックします。
- 新しく作成したサービス アカウントのメールアドレスをクリックします。
- [キー] タブに移動します。
- [鍵を追加] > [新しい鍵を作成] の順にクリックします。
- キーのタイプとして [JSON] を選択します。
- [作成] をクリックします。
- JSON 鍵ファイルがパソコンにダウンロードされます。
- JSON キーファイルを開き、その内容をすべてコピーします。
- Oracle Cloud コンソールの関数構成に戻ります。
JSON の内容を
GCS_CREDENTIALS_JSON構成変数に貼り付けます。
Cloud Storage バケットに対する IAM 権限を付与する
Cloud Storage バケットに対する書き込み権限をサービス アカウントに付与します。
- [Cloud Storage] > [バケット] に移動します。
- バケット名(
oci-audit-logs-gcs)をクリックします。 - [権限] タブに移動します。
- [アクセス権を付与] をクリックします。
- 次の構成情報を指定します。
- プリンシパルを追加: サービス アカウントのメールアドレス(
oci-function-gcs-writer@PROJECT_ID.iam.gserviceaccount.com)を入力します。 - ロールを割り当てる: [Storage オブジェクト管理者] を選択します。
- プリンシパルを追加: サービス アカウントのメールアドレス(
- [保存] をクリックします。
OCI Service Connector Hub を作成する
- Oracle Cloud コンソールにログインします。
- [Observability & Management] > [Logging] > [Service Connector Hub] に移動します。
- サービス コネクタを作成するコンパートメントを選択します。
- [サービス コネクタを作成] をクリックします。
次の構成情報を提供してください。
サービス コネクタの情報:
設定 値 コネクタ名 「 audit-logs-to-gcs-connector」と入力します。説明 「 Forward OCI Audit logs to Cloud Storage」と入力します。リソース コンパートメント コンパートメントを選択します。 ソースを構成する:
設定 値 ソース [Logging] を選択します。 コンパートメント 監査ログを含むコンパートメントを選択します。 ロググループ [_Audit](監査ログのデフォルトのロググループ)を選択します。
[+ 別のログ] をクリックします。
コンパートメントの監査ログ(
_Audit_Include_Subcompartmentなど)を選択します。ターゲットを構成する:
設定 値 ターゲット [関数] を選択します。 機能コンパートメント 関数を含むコンパートメントを選択します。 関数適用 audit-logs-to-gcs-appを選択ファンクション oci-audit-to-gcsを選択
[タスクの構成(省略可)] に移動し、デフォルト設定のままにします。
[作成] をクリックします。
Service Connector Hub の IAM ポリシーを作成する
サービス コネクタ ハブには、関数を呼び出す権限が必要です。この権限は次のように作成します。
- Oracle Cloud コンソールで、[Identity & Security] > [Policies] に移動します。
- Service Connector Hub を作成したコンパートメントを選択します。
- [Create Policy] をクリックします。
- 次の構成情報を指定します。
- 名前: 「
service-connector-functions-policy」と入力します。 - 説明: 「
Allow Service Connector Hub to invoke Functions」と入力します。 - コンパートメント: コンパートメントを選択します。
- 名前: 「
- [ポリシー ビルダー] セクションで、[手動エディタを表示] を切り替えます。
次のポリシー ステートメントを入力します。
Allow any-user to use fn-function in compartment <compartment-name> where all {request.principal.type='serviceconnector'} Allow any-user to use fn-invocation in compartment <compartment-name> where all {request.principal.type='serviceconnector'}<compartment-name>は、コンパートメント名に置き換えます。
[作成] をクリックします。
統合をテストする
- Oracle Cloud コンソールにログインします。
- 監査ログを生成するアクション(リソースの作成や変更など)を実行します。
- ログが処理されるまで 2 ~ 5 分待ちます。
- Google Cloud コンソールで、[Cloud Storage] > [バケット] に移動します。
- バケット名(
oci-audit-logs-gcs)をクリックします。 - 接頭辞フォルダ(
oci-audit-logs/)に移動します。 新しい
.ndjsonファイルがバケットに表示されていることを確認します。
Google SecOps サービス アカウントを取得する
Google SecOps は、一意のサービス アカウントを使用して Cloud Storage バケットからデータを読み取ります。このサービス アカウントにバケットへのアクセス権を付与する必要があります。
サービス アカウントのメールアドレスを取得する
- [SIEM 設定] > [フィード] に移動します。
- [Add New Feed] をクリックします。
- [単一フィードを設定] をクリックします。
- [フィード名] フィールドに、フィードの名前を入力します(例:
Oracle Cloud Audit Logs)。 - [ソースタイプ] として [Google Cloud Storage V2] を選択します。
- [Log type] として [Oracle Cloud Infrastructure Audit Logs] を選択します。
[サービス アカウントを取得する] をクリックします。一意のサービス アカウントのメールアドレスが表示されます。例:
chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.comこのメールアドレスをコピーして、次のステップで使用します。
Google SecOps サービス アカウントに IAM 権限を付与する
Google SecOps サービス アカウントには、Cloud Storage バケットに対する 2 つのロールが必要です。ログ オブジェクトを読み取るためのストレージ オブジェクト閲覧者ロールと、バケット メタデータを読み取るためのバケットレベルのロールです。
- [Cloud Storage] > [バケット] に移動します。
- バケット名(
oci-audit-logs-gcs)をクリックします。 - [権限] タブに移動します。
- [アクセス権を付与] をクリックします。
- 次の構成情報を指定します。
- プリンシパルを追加: Google SecOps サービス アカウントのメールアドレスを貼り付けます。
- ロールを割り当てる: 次の両方を選択します。
- Storage オブジェクト閲覧者: ログ オブジェクトを読み取ります。
- Storage レガシー バケット読み取り: バケット メタデータを読み取ります。[転送されたファイルと空のディレクトリを削除する] 削除オプションを選択した場合は、代わりに [ストレージ レガシー バケット書き込み] を選択します。これにより、削除権限も付与されます。
[保存] をクリックします。
OCI 監査ログを取り込むように Google SecOps でフィードを構成する
- [SIEM 設定] > [フィード] に移動します。
- [Add New Feed] をクリックします。
- [単一フィードを設定] をクリックします。
- [フィード名] フィールドに、フィードの名前を入力します(例:
Oracle Cloud Audit Logs)。 - [ソースタイプ] として [Google Cloud Storage V2] を選択します。
- [Log type] として [Oracle Cloud Infrastructure Audit Logs] を選択します。
- [次へ] をクリックします。
次の入力パラメータの値を指定します。
- ストレージ バケットの URL: 接頭辞パスを含む Cloud Storage バケット URI を入力します。
gs://oci-audit-logs-gcs/oci-audit-logs/次のように置き換えます。
oci-audit-logs-gcs: Cloud Storage バケット名。oci-audit-logs: ログが保存されるオプションの接頭辞またはパス(ルートの場合は空のままにします)。
例:
- ルートバケット:
gs://company-logs/ - 接頭辞あり:
gs://company-logs/oci-audit-logs/ サブフォルダあり:
gs://company-logs/oracle/audit/
Source deletion option: 必要に応じて削除オプションを選択します。
- ファイルを削除しない: ソースからファイルを削除しません(テストにおすすめ)。
- 転送されたファイルと空のディレクトリを削除する: 取得が正常に完了した後、ソースからファイルと空のディレクトリを削除します。
ファイルの最長存続期間: 過去数日間に変更されたファイルを含めます。デフォルトは 180 日です。
Asset namespace: アセットの名前空間。
Ingestion labels: このフィードのイベントに適用されるラベル。
[次へ] をクリックします。
[Finalize] 画面で新しいフィードの設定を確認し、[送信] をクリックします。
方法 2: Webhook
この方法では、Connector Hub が監査ログエントリのバッチを OCI 関数に配信し、関数が HTTPS 経由で Google SecOps Webhook フィードに送信します。Cloud Storage バケットは関与しません。
Google SecOps で Webhook フィードを作成する
フィードを作成する
- [SIEM 設定] > [フィード] に移動します。
- [Add New Feed] をクリックします。
- 次のページで、[単一のフィードを構成する] をクリックします。
- [フィード名] フィールドに、フィードの名前を入力します(例:
OCI Audit Logs Webhook)。 - [Source type] として [Webhook] を選択します。
- [Log type] として [Oracle Cloud Infrastructure Audit Logs] を選択します。
- [次へ] をクリックします。
- 次の入力パラメータの値を指定します。
- 分割区切り文字: 「
\n」と入力します。この関数は、各ログエントリを独自の行で送信します。 - Asset namespace: アセットの名前空間。
- Ingestion labels: このフィードのイベントに適用されるラベル。
- 分割区切り文字: 「
- [次へ] をクリックします。
- [Finalize] 画面で新しいフィードの設定を確認し、[送信] をクリックします。
秘密鍵を生成して保存する
- フィードの詳細ページで、[秘密鍵を生成] をクリックします。
秘密鍵をコピーして安全に保存します。
フィード エンドポイントの URL を取得する
- フィードの [詳細] タブに移動します。
[エンドポイント情報] セクションで、[フィードのエンドポイント URL] をコピーします。URL の形式は次のとおりです。
https://<REGION>-chronicle.googleapis.com/v1alpha/projects/<PROJECT_NUMBER>/locations/<REGION>/instances/<INSTANCE_ID>/feeds/<FEED_ID>:importPushLogs[完了] をクリックします。
Google Cloud API キーを作成する
- Google Cloud コンソールの [認証情報] ページに移動します。
- Google SecOps インスタンスにリンクされているプロジェクトを選択します。
- [認証情報を作成] > [API キー] をクリックします。
- [API キーを編集] をクリックしてキーを制限します。
- [名前] フィールドにわかりやすい名前(例:
oci-audit-webhook)を入力します。 - [API の制限] で [キーを制限] を選択し、[API を選択] リストで [Chronicle API] を選択します。
- [保存] をクリックします。
- API キーの値をコピーして安全に保存します。
ログを Webhook に転送する OCI 関数を作成する
アプリケーションの作成
- Oracle Cloud コンソールにログインします。
- ナビゲーション メニューを開き、[Developer Services] > [Functions] > [Applications] を選択します。
- 関数アプリケーションを作成するコンパートメントを選択します。
- [アプリケーションを作成] をクリックします。
- 次の構成情報を指定します。
- 名前: 「
audit-logs-to-secops-app」と入力します。 - VCN: Virtual Cloud Network を選択します。
- サブネット: インターネット アクセスが可能なサブネット(インターネット ゲートウェイを備えたパブリック サブネット、または NAT ゲートウェイを備えたプライベート サブネット)を選択します。関数は、HTTPS(ポート 443)経由で Google SecOps エンドポイントに到達する必要があります。
- 名前: 「
- [作成] をクリックします。
関数を作成してデプロイする
- アプリケーションが作成されたら、[Getting Started] をクリックし、手順に沿って OCI Cloud Shell または Fn CLI を使用してローカル開発環境を設定します。
Python 関数を初期化します。
fn init --runtime python oci-audit-to-secops cd oci-audit-to-secopsfunc.pyの内容を次のコードに置き換えます。import io import json import logging import os import random import time from email.utils import parsedate_to_datetime import requests from fdk import response logging.basicConfig(level=logging.INFO) logger = logging.getLogger() # The webhook accepts at most 4 MB per request and 1 MB per log line. # Connector Hub delivers batches of up to 6 MB, so a batch is sent as several # requests, each made of whole log entries. MAX_REQUEST_BYTES = 3 * 1024 * 1024 MAX_LINE_BYTES = 1024 * 1024 MAX_ATTEMPTS = 5 RETRYABLE_STATUS = {429, 500, 502, 503, 504} # OCI stops the function at its configured timeout (300 seconds). Stop retrying # early enough to fail cleanly so that Connector Hub retries the whole batch. DEADLINE_SECONDS = 240 def to_lines(body): """Serialize each log entry from the Connector Hub batch as one JSON line.""" entries = body if isinstance(body, list) else [body] lines = [] for entry in entries: line = json.dumps(entry, ensure_ascii=False, separators=(',', ':')).encode('utf-8') if len(line) > MAX_LINE_BYTES: entry_id = entry.get('id') if isinstance(entry, dict) else None logger.error(f'Skipping log entry {entry_id}: {len(line)} bytes exceeds the 1 MB line limit') continue lines.append(line) return lines def to_requests(lines): """Group whole lines into newline-delimited request bodies below MAX_REQUEST_BYTES.""" chunk, size = [], 0 for line in lines: if chunk and size + len(line) + 1 > MAX_REQUEST_BYTES: yield b'\n'.join(chunk), len(chunk) chunk, size = [], 0 chunk.append(line) size += len(line) + 1 if chunk: yield b'\n'.join(chunk), len(chunk) def retry_after_seconds(value): """Parse a Retry-After header given either in seconds or as an HTTP date.""" if not value: return None try: return max(0.0, float(value)) except ValueError: pass try: return max(0.0, parsedate_to_datetime(value).timestamp() - time.time()) except (TypeError, ValueError, IndexError, OverflowError): return None def post(session, url, headers, payload, deadline): """Send one request, retrying throttling and server errors until the deadline.""" status, detail = None, '' for attempt in range(1, MAX_ATTEMPTS + 1): remaining = deadline - time.monotonic() if remaining < 5: break wait = None try: resp = session.post(url, data=payload, headers=headers, timeout=(10, min(60, remaining))) except requests.RequestException as e: status, detail = None, str(e) else: if 200 <= resp.status_code < 300: return status, detail = resp.status_code, resp.text[:500] if status not in RETRYABLE_STATUS: raise RuntimeError(f'Webhook rejected the request with HTTP {status}: {detail}') wait = retry_after_seconds(resp.headers.get('Retry-After')) if wait is None: wait = min(30, 2 ** attempt) + random.uniform(0, 1) if attempt == MAX_ATTEMPTS or time.monotonic() + wait >= deadline: break logger.warning(f'Attempt {attempt} failed (HTTP {status}): {detail}. Retrying in {wait:.1f} seconds') time.sleep(wait) raise RuntimeError(f'Webhook request failed (HTTP {status}): {detail}') def handler(ctx, data: io.BytesIO = None): """Forward a Connector Hub batch of OCI Audit log entries to the webhook feed. Any exception fails the invocation, and Connector Hub then retries the batch. """ deadline = time.monotonic() + DEADLINE_SECONDS url = os.environ.get('SECOPS_WEBHOOK_URL') api_key = os.environ.get('SECOPS_API_KEY') secret_key = os.environ.get('SECOPS_SECRET_KEY') if not all([url, api_key, secret_key]): raise RuntimeError('Missing configuration: SECOPS_WEBHOOK_URL, SECOPS_API_KEY and SECOPS_SECRET_KEY are required') raw = data.getvalue() if data else b'' if not raw.strip(): logger.info('Received an empty batch') return response.Response( ctx, response_data=json.dumps({'records': 0}), headers={'Content-Type': 'application/json'} ) lines = to_lines(json.loads(raw)) headers = { 'Content-Type': 'application/json', 'X-goog-api-key': api_key, 'X-Webhook-Access-Key': secret_key, } sent = 0 with requests.Session() as session: for payload, count in to_requests(lines): post(session, url, headers, payload, deadline) sent += count logger.info(f'Forwarded {sent} log entries') return response.Response( ctx, response_data=json.dumps({'records': sent}), headers={'Content-Type': 'application/json'} )requirements.txtの内容を次の依存関係に置き換えます。fdk>=0.1.0 requests>=2.32.0func.yamlを開き、次の行を追加して、関数のタイムアウトをデフォルトの 30 秒から最大 300 秒に引き上げます。timeout: 300関数を OCI にデプロイします。
fn -v deploy --app audit-logs-to-secops-app
関数の環境変数を構成する
- Oracle Cloud コンソールで、[Developer Services] > [Functions] > [Applications] に移動します。
- アプリケーション(
audit-logs-to-secops-app)をクリックします。 - 関数名(
oci-audit-to-secops)をクリックします。 - [構成] をクリックします。
次の構成変数を追加します。
キー 値 SECOPS_WEBHOOK_URLフィード エンドポイントの URL SECOPS_API_KEYGoogle Cloud API キー SECOPS_SECRET_KEYフィードの秘密鍵 [変更を保存] をクリックします。
関数ログを有効にする
- [アプリケーション] リストページで、[
audit-logs-to-secops-app] を選択します。 - [Monitoring] タブを選択し、[ログ] セクションに移動します。
- [Function Invocation Logs] カテゴリの [アクション] メニュー(3 つのドット)から、[ログを有効にする] を選択します。
- デフォルトのコンパートメント、ロググループ、ログ名をそのまま使用するか、必要に応じて変更します。
- [ログを有効にする] を選択します。
OCI Connector Hub コネクタを作成する
- ナビゲーション メニューを開き、[分析と AI] を選択します。[Messaging] で [Connector Hub] を選択します。
- コネクタを作成するコンパートメントを選択します。
- [コネクタを作成] をクリックします。
次の構成情報を提供してください。
コネクタ情報:
設定 値 コネクタ名 「 audit-logs-to-secops-connector」と入力します。説明 「 Forward OCI Audit logs to a webhook feed」と入力します。リソース コンパートメント コンパートメントを選択します。 ソースを構成する:
設定 値 ソース [Logging] を選択します。 コンパートメント 監査ログを含むコンパートメントを選択します。 ロググループ [_Audit](監査ログのデフォルトのロググループ)を選択します。
[+ 別のログ] をクリックします。
コンパートメントの監査ログ(
_Audit_Include_Subcompartmentなど)を選択します。ターゲットを構成する:
設定 値 ターゲット [関数] を選択します。 機能コンパートメント 関数を含むコンパートメントを選択します。 関数適用 audit-logs-to-secops-appを選択ファンクション oci-audit-to-secopsを選択
[タスクの構成(省略可)] に移動し、デフォルト設定のままにします。
ポリシーの作成を求めるメッセージが表示されたら(サービス コネクタの作成または更新にアクセスするために必要)、[作成] を選択します。
[作成] をクリックします。
コネクタハブの IAM ポリシーを作成する
コネクタハブには、関数を呼び出す権限が必要です。
- Oracle Cloud コンソールで、[Identity & Security] > [Policies] に移動します。
- コネクタを作成したコンパートメントを選択します。
- [Create Policy] をクリックします。
- 次の構成情報を指定します。
- 名前: 「
connector-hub-secops-function-policy」と入力します。 - 説明: 「
Allow Connector Hub to invoke the webhook forwarding function」と入力します。 - コンパートメント: コンパートメントを選択します。
- 名前: 「
- [ポリシー ビルダー] セクションで、[手動エディタを表示] を切り替えます。
次のポリシー ステートメントを入力します。
Allow any-user to use fn-function in compartment <compartment-name> where all {request.principal.type='serviceconnector'} Allow any-user to use fn-invocation in compartment <compartment-name> where all {request.principal.type='serviceconnector'}[作成] をクリックします。
関数がログを配信する方法
- バッチサイズ: Connector Hub は最大 6 MB の関数バッチを送信し、Webhook はリクエストあたり最大 4 MB を受け入れます。この関数は、各バッチを最大 3 MB のリクエストに分割します。ログエントリ間でのみ分割され、ログエントリ内では分割されません。各エントリは 1 つのイベントとして Google SecOps に到着します。
- 再試行: 関数は、指数バックオフを使用して HTTP 429 レスポンスと 5xx レスポンスを再試行し、
Retry-Afterヘッダーを優先します。その他のエラーが発生した場合、または 5 回試行してもリクエストが失敗した場合は、呼び出しが失敗します。その後、コネクタハブはバッチ全体を再試行し、成功するまで後続のバッチを移動しません。 - 保持: Connector Hub の Logging ソースは、未配信のデータを 24 時間保持します。配信がさらに長く失敗し続けると、最も古い未配信のログが失われるため、関数ログで報告されたエラーを速やかに修正してください。
- 重複: コネクタハブは各バッチを少なくとも 1 回配信します。バッチの一部がすでに送信された後にバッチが再試行されると、Google SecOps はそれらのエントリを 2 回受信することがあります。
- サイズ超過のエントリ: 1 MB を超えるログエントリは、Webhook の行数の上限を超えています。関数はそれをスキップし、その ID を関数ログに書き込みます。
統合を確認する
統合を確認するには、次の操作を行います。
- Oracle Cloud コンソールで、監査ログを生成する操作(リソースの作成や変更など)を実行します。
- Connector Hub がログを配信するまで 2 ~ 5 分待ちます。
- 有効にした関数呼び出しログを開き、
Forwarded N log entriesメッセージが含まれていることを確認します。エラー メッセージには、Google SecOps から返された HTTP ステータスが含まれます。 Google SecOps で、
OCI_AUDITログタイプの未加工ログ検索を実行し、監査イベントが届いていることを確認します。
UDM マッピング テーブル
| ログフィールド | UDM マッピング | ロジック |
|---|---|---|
accept_encoding_field |
additional.fields |
統合済み |
accept_field |
additional.fields |
統合済み |
additional_app |
additional.fields |
統合済み |
additional_content_type |
additional.fields |
統合済み |
additional_sort_by |
additional.fields |
統合済み |
additionaldetails_data |
additional.fields |
統合済み |
allow_methods_field |
additional.fields |
統合済み |
auth_type_label |
additional.fields |
統合済み |
authorization_field |
additional.fields |
統合済み |
backend_connect_time_field |
additional.fields |
統合済み |
backend_processing_time_field |
additional.fields |
統合済み |
caller_id_label |
additional.fields |
統合済み |
caller_name_label |
additional.fields |
統合済み |
cloud_event_versiom_field |
additional.fields |
統合済み |
compartment_id_field |
additional.fields |
統合済み |
compartment_name_field |
additional.fields |
統合済み |
connection_field |
additional.fields |
統合済み |
content_length_field |
additional.fields |
統合済み |
content_type_field |
additional.fields |
統合済み |
event_grouping_id_field |
additional.fields |
統合済み |
event_name_label |
additional.fields |
統合済み |
event_resource_label |
additional.fields |
統合済み |
event_source_label |
additional.fields |
統合済み |
event_type_label |
additional.fields |
統合済み |
event_type_versiom_field |
additional.fields |
統合済み |
has_compariment_id |
additional.fields |
マッピング済み: true → additional_app |
has_sort_by |
additional.fields |
マッピング済み: true → additional_sort_by |
listener_name_field |
additional.fields |
統合済み |
log_group_id_field |
additional.fields |
統合済み |
log_id_field |
additional.fields |
統合済み |
message |
additional.fields |
マッピングされた値(合計 41 個、例: \/ → tenant_id_label、\/ → auth_type_label、\/ → `ca... |
opc_request_id_field |
additional.fields |
統合済み |
origin_field |
additional.fields |
統合済み |
param0_field |
additional.fields |
統合済み |
param1_field |
additional.fields |
統合済み |
referer_field |
additional.fields |
統合済み |
request_processing_time_field |
additional.fields |
統合済み |
resource_id_field |
additional.fields |
統合済み |
routing_rules_engine_errors_field |
additional.fields |
統合済み |
routing_rules_matched_rule_field |
additional.fields |
統合済み |
routing_rules_rule_hits_field |
additional.fields |
統合済み |
routing_rules_rule_misses_field |
additional.fields |
統合済み |
source_field |
additional.fields |
統合済み |
tenant_id_label |
additional.fields |
統合済み |
column3 |
extensions.auth.type |
マッピング済み: login successful → AUTHTYPE_UNSPECIFIED |
message |
extensions.auth.type |
マッピング済み: \/ → AUTHTYPE_UNSPECIFIED |
column3 |
metadata.description |
直接マッピングされます。 |
data.message |
metadata.description |
直接マッピングされます。 |
column1 |
metadata.event_timestamp |
yyyy-MM-dd HH:mm:ss として解析 |
data_event_time |
metadata.event_timestamp |
yyyy-MM-ddTHH:mm:ss.SSSSSSZ として解析 |
time |
metadata.event_timestamp |
ISO8601 として解析 |
metadata_event_type |
metadata.event_type |
直接マッピングされます。 |
type |
metadata.product_event_type |
直接マッピングされます。 |
data_event_id |
metadata.product_log_id |
直接マッピングされます。 |
id |
metadata.product_log_id |
直接マッピングされます。 |
message |
metadata.product_name |
マッピング済み: \/ → OCI_AUDIT |
specversion |
metadata.product_version |
直接マッピングされます。 |
message |
metadata.vendor_name |
マッピング済み: \/ → Oracle |
message |
network.application_protocol |
マッピング済み: \/ → HTTPS、\/ → HTTP |
protocol |
network.application_protocol |
マッピング済み: (?i)HTTPS → HTTPS、(?i)HTTP → HTTP |
version |
network.application_protocol_version |
直接マッピングされます。 |
data_request_action |
network.http.method |
直接マッピングされます。 |
method |
network.http.method |
直接マッピングされます。 |
data_identity_userAgent |
network.http.parsed_user_agent |
名前変更/マッピング |
data_request_agent |
network.http.parsed_user_agent |
名前変更/マッピング |
url |
network.http.referral_url |
直接マッピングされます。 |
data.backendStatusCode |
network.http.response_code |
直接マッピングされます。 |
data_response_status |
network.http.response_code |
名前変更/マッピング |
data.userAgent |
network.http.user_agent |
直接マッピングされます。 |
data_identity_userAgent |
network.http.user_agent |
直接マッピングされます。 |
data_request_agent |
network.http.user_agent |
直接マッピングされます。 |
data.receivedBytes |
network.received_bytes |
直接マッピングされます。 |
message |
network.received_bytes |
マッピング済み: \/ → uinteger |
data.sentBytes |
network.sent_bytes |
直接マッピングされます。 |
message |
network.sent_bytes |
マッピング済み: \/ → uinteger |
data_identity_consoleSessionId |
network.session_id |
名前変更/マッピング |
data.sslCipher |
network.tls.cipher |
直接マッピングされます。 |
data.sslProtocol |
network.tls.version |
直接マッピングされます。 |
data.host |
principal.asset.hostname |
直接マッピングされます。 |
hostname |
principal.asset.hostname |
直接マッピングされます。 |
column6 |
principal.asset.ip |
統合済み |
data.forwardedForAddr |
principal.asset.ip |
統合済み |
data_identity_ipAddress |
principal.asset.ip |
マッピング済み: ^(?:[0-9]{1,3}[.]){3}[0-9]{1,3}$ → data_identity_ipAddress |
data_request_origin |
principal.asset.ip |
統合済み |
ip1 |
principal.asset.ip |
統合済み |
ip2 |
principal.asset.ip |
統合済み |
message |
principal.asset.ip |
マッピングされた値(合計 7 個、例: \/ → column6、\/ → data_request_origin、\/ → ip2) |
src_ip |
principal.asset.ip |
統合済み |
data.host |
principal.hostname |
直接マッピングされます。 |
hostname |
principal.hostname |
直接マッピングされます。 |
column6 |
principal.ip |
統合済み |
data.forwardedForAddr |
principal.ip |
統合済み |
data_identity_ipAddress |
principal.ip |
マッピング済み: ^(?:[0-9]{1,3}[.]){3}[0-9]{1,3}$ → data_identity_ipAddress |
data_request_origin |
principal.ip |
統合済み |
ip1 |
principal.ip |
統合済み |
ip2 |
principal.ip |
統合済み |
message |
principal.ip |
マッピングされた値(合計 7 個、例: \/ → column6、\/ → data_request_origin、\/ → ip2) |
src_ip |
principal.ip |
統合済み |
data_request_headers_sec-ch-ua-platform_0 |
principal.platform |
マッピング済み: (?i)Linux → LINUX、(?i)windows → WINDOWS、(?i)mac/ios → MAC |
message |
principal.platform |
マッピング済み: \/ → LINUX、\/ → WINDOWS、\/ → MAC |
originalConnection.sourcePort |
principal.port |
直接マッピングされます。 |
src_port |
principal.port |
直接マッピングされます。 |
data_request_headers_oci-original-url_0 |
principal.url |
直接マッピングされます。 |
credentials_label |
principal.user.attribute.labels |
統合済み |
message |
principal.user.attribute.labels |
マッピング済み: \/ → credentials_label |
data.identity.principalName |
principal.user.user_display_name |
直接マッピングされます。 |
data.username |
principal.user.user_display_name |
直接マッピングされます。 |
data.identity.principalId |
principal.user.userid |
直接マッピングされます。 |
data.principalId |
principal.user.userid |
直接マッピングされます。 |
column3 |
security_result |
マッピング済み: login successful → security_result |
message |
security_result |
マッピング済み: \/ → security_result |
allow_action |
security_result.action |
統合済み |
column3 |
security_result.action |
マッピング済み: login successful → allow_action |
message |
security_result.action |
マッピング済み: \/ → allow_action |
credential_type_field |
security_result.detection_fields |
統合済み |
message |
security_result.detection_fields |
マッピング済み: \/ → credential_type_field |
data.response.message |
security_result.summary |
直接マッピングされます。 |
message |
target.asset.ip |
マッピング済み: \/ → originalConnection.destinationIp、\/ → tar_ip |
originalConnection.destinationIp |
target.asset.ip |
統合済み |
tar_ip |
target.asset.ip |
統合済み |
message |
target.ip |
マッピング済み: \/ → originalConnection.destinationIp、\/ → tar_ip |
originalConnection.destinationIp |
target.ip |
統合済み |
tar_ip |
target.ip |
統合済み |
originalConnection.destinationPort |
target.port |
直接マッピングされます。 |
tar_port |
target.port |
直接マッピングされます。 |
message |
target.resource.attribute.labels |
マッピング済み: \/ → namespace_label |
namespace_label |
target.resource.attribute.labels |
統合済み |
type |
target.resource.attribute.labels |
マッピング済み: listretentionrules → namespace_label |
data.resourceId |
target.resource.name |
直接マッピングされます。 |
data.resourceName |
target.resource.name |
直接マッピングされます。 |
bucketId |
target.resource.product_object_id |
直接マッピングされます。 |
data.resourceId |
target.resource.product_object_id |
直接マッピングされます。 |
data_request_id |
target.resource.product_object_id |
直接マッピングされます。 |
message |
target.resource.resource_type |
マッピング済み: \/ → STORAGE_BUCKET |
type |
target.resource.resource_type |
マッピング済み: listretentionrules → STORAGE_BUCKET |
data_request_path |
target.url |
直接マッピングされます。 |
column2 |
target.user.email_addresses |
統合済み |
message |
target.user.email_addresses |
マッピング済み: \/ → column2 |
| なし | extensions.auth.type |
定数: AUTHTYPE_UNSPECIFIED |
| なし | metadata.product_name |
定数: OCI_AUDIT |
| なし | metadata.vendor_name |
定数: Oracle |
| なし | network.application_protocol |
定数: HTTPS |
| なし | principal.platform |
定数: LINUX |
| なし | target.resource.resource_type |
定数: STORAGE_BUCKET |
変更ログ
さらにサポートが必要な場合 コミュニティ メンバーや Google SecOps のプロフェッショナルから回答を得ることができます。