PingIDM(以前の ForgeRock OpenIDM)のログを収集する

パーサーのバージョン: 4.0

以下でサポートされています。

このドキュメントでは、Google Cloud Storage V2 を使用して PingIDM(以前の ForgeRock OpenIDM)ログを Google Security Operations に取り込む方法について説明します。

PingIDM は、ユーザーのプロビジョニング、同期、パスワード管理、アクセス ガバナンスを提供する ID 管理プラットフォームです。ID ライフサイクル イベント、認証試行、調整オペレーション、構成変更を REST 経由でアクセス可能な監査ログに記録します。

始める前に

次の前提条件を満たしていることを確認します。

  • Google SecOps インスタンス。
  • Cloud Storage API が有効になっている GCP プロジェクト。
  • GCS バケットと IAM ポリシーを作成および管理する権限。
  • Cloud Run サービス、Pub/Sub トピック、Cloud Scheduler ジョブを作成する権限。
  • 管理者認証情報を使用して ForgeRock OpenIDM または PingIDM インスタンスへの特権アクセス。

Google Cloud Storage バケットを作成する

  1. Google Cloud コンソールに移動します。
  2. プロジェクトを選択するか、新しいプロジェクトを作成します。
  3. ナビゲーション メニューで、[Cloud Storage] > [バケット] に移動します。
  4. [バケットを作成] をクリックします。
  5. 次の構成情報を提供してください。

    設定 値
    バケットに名前を付ける グローバルに一意の名前(forgerock-openidm-audit-logs など)を入力します。
    ロケーション タイプ ニーズに応じて選択します(リージョン、デュアルリージョン、マルチリージョン)。
    ロケーション 場所を選択します(例: us-central1)。
    ストレージ クラス Standard(アクセス頻度の高いログに推奨)
    アクセス制御 均一(推奨)
    保護ツール 省略可: オブジェクトのバージョニングまたは保持ポリシーを有効にする
  6. [作成] をクリックします。

ForgeRock OpenIDM の認証情報を収集する

ForgeRock OpenIDM のベース URL を取得する

  1. ForgeRock OpenIDM または PingIDM インスタンスにログインします。
  2. ブラウザのアドレスバーからベース URL をメモします。
    • 形式: https://openidm.example.com
    • 末尾のスラッシュや /admin などのパスは含めないでください。

管理者の認証情報を取得する

  1. ForgeRock OpenIDM インスタンスの管理者認証情報を取得します。
  2. 以下の情報が必要になります。
    • ユーザー名: 管理ユーザー名(例: openidm-admin)
    • パスワード: 管理者パスワード

権限を確認する

  1. ForgeRock OpenIDM にログインします。
  2. [構成] > [システム設定] > [監査] に移動します。
  3. 監査構成とトピックが表示される場合は、必要な権限が付与されています。
  4. このオプションが表示されない場合は、監査の読み取り権限を付与するよう管理者にお問い合わせください。

テスト API へのアクセス

  • 統合に進む前に、認証情報をテストします。

    # Replace with your actual credentials
    OPENIDM_BASE_URL="[https://openidm.example.com](https://openidm.example.com)"
    OPENIDM_USERNAME="openidm-admin"
    OPENIDM_PASSWORD="your-admin-password"
    
    # Test API access to authentication audit topic
    curl -v \
        -H "X-OpenIDM-Username: ${OPENIDM_USERNAME}" \
        -H "X-OpenIDM-Password: ${OPENIDM_PASSWORD}" \
        -H "Accept-API-Version: resource=1.0" \
        -H "Accept: application/json" \
        "${OPENIDM_BASE_URL}/openidm/audit/authentication?_queryFilter=true&_pageSize=1"
    

想定されるレスポンス: 監査イベントを含む JSON を含む HTTP 200。

Cloud Run functions のサービス アカウントを作成する

Cloud Run functions には、GCS バケットへの書き込み権限があり、Pub/Sub によって呼び出されるサービス アカウントが必要です。

サービス アカウントの作成

  1. GCP コンソールで、[IAM と管理] > [サービス アカウント] に移動します。
  2. [サービス アカウントを作成] をクリックします。
  3. 次の構成情報を指定します。
    • サービス アカウント名: forgerock-openidm-collector-sa
    • サービス アカウントの説明: Service account for Cloud Run function to collect ForgeRock OpenIDM logs
  4. [作成して続行] をクリックします。
  5. [このサービス アカウントにプロジェクトへのアクセスを許可する] セクションで、次のロールを追加します。
    1. Storage オブジェクト管理者: ログを GCS バケットに書き込み、状態ファイルを管理します。
    2. Cloud Run 起動元: Pub/Sub が関数を呼び出すことを許可します。
    3. Cloud Functions 起動元: 関数の呼び出しを許可します。
  6. [続行]、[完了] の順にクリックします。

GCS バケットに対する IAM 権限を付与する

  1. [Cloud Storage] > [バケット] に移動します。
  2. バケット名(例: forgerock-openidm-audit-logs)をクリックします。
  3. [権限] タブに移動します。
  4. [アクセス権を付与] をクリックします。
  5. 次の構成情報を指定します。
    • プリンシパルを追加: サービス アカウントのメールアドレス(forgerock-openidm-collector-sa@PROJECT_ID.iam.gserviceaccount.com など)を入力します。
    • ロールを割り当てる: [ストレージ オブジェクト管理者] を選択します。
  6. [保存] をクリックします。

Pub/Sub トピックの作成

  1. GCP コンソールで、[Pub/Sub] > [トピック] に移動します。
  2. [トピックを作成] をクリックします。
  3. 次の構成情報を指定します。
    • トピック ID: forgerock-openidm-trigger
    • その他の設定はデフォルトのままにします。
  4. [作成] をクリックします。

ログを収集する Cloud Run 関数を作成する

  1. GCP Console で、[Cloud Run] に移動します。
  2. [サービスを作成] をクリックします。
  3. [関数] を選択します(インライン エディタを使用して関数を作成します)。
  4. [構成] セクションで、次の構成の詳細を指定します。

    設定 値
    サービス名 forgerock-openidm-collector
    リージョン GCS バケットと一致するリージョンを選択します(例: us-central1)。
    ランタイム [Python 3.12] 以降を選択します。
  5. [トリガー] セクションで次の操作を行います。

    1. [+ トリガーを追加] をクリックします。
    2. [Cloud Pub/Sub] を選択します。
    3. [Cloud Pub/Sub トピックを選択してください] で、forgerock-openidm-trigger を選択します。
    4. [保存] をクリックします。
  6. [認証] セクションで、次の操作を行います。

    1. [認証が必要] を選択します。
    2. Identity and Access Management(IAM)を確認します。
  7. 下にスクロールして、[コンテナ、ネットワーキング、セキュリティ] を開きます。

  8. [セキュリティ] タブに移動します。

    • サービス アカウント: forgerock-openidm-collector-sa を選択します。
  9. [コンテナ] タブに移動します。

    1. [変数とシークレット] をクリックします。
    2. 環境変数ごとに [+ 変数を追加] をクリックします。
    変数名 値の例 説明
    GCS_BUCKET forgerock-openidm-audit-logs GCS バケット名
    GCS_PREFIX openidm ログファイルの接頭辞
    STATE_KEY openidm/state.json 状態ファイルのパス
    OPENIDM_BASE_URL https://openidm.example.com OpenIDM のベース URL
    OPENIDM_USERNAME openidm-admin OpenIDM 管理ユーザー名
    OPENIDM_PASSWORD your-admin-password OpenIDM 管理者パスワード
    AUDIT_TOPICS access,activity,authentication,config,sync カンマ区切りのトピック
    PAGE_SIZE 100 1 ページあたりのレコード数
    MAX_PAGES 50 トピックあたりの最大ページ数
  10. [リクエスト] セクションで、次の操作を行います。

    • リクエスト タイムアウト: 600 秒。
  11. [設定] タブに移動します。

    • リソース: 512 MiB のメモリ、1 個の CPU。
  12. [作成] をクリックします。サービスが作成されると、インライン コード エディタが開きます。

関数コードを追加する

  1. [エントリ ポイント] フィールドに「main」と入力します。
  2. エディタで 2 つのファイルを作成します。

    • main.py:
    import functions_framework
    from google.cloud import storage
    import json
    import os
    import urllib3
    from datetime import datetime, timezone
    
    # Initialize HTTP client with timeouts
    http = urllib3.PoolManager(
        timeout=urllib3.Timeout(connect=5.0, read=30.0),
        retries=False,
    )
    
    # Initialize Storage client
    storage_client = storage.Client()
    
    # Environment variables
    GCS_BUCKET = os.environ.get('GCS_BUCKET')
    GCS_PREFIX = os.environ.get('GCS_PREFIX', 'openidm')
    STATE_KEY = os.environ.get('STATE_KEY', 'openidm/state.json')
    OPENIDM_BASE_URL = os.environ.get('OPENIDM_BASE_URL')
    OPENIDM_USERNAME = os.environ.get('OPENIDM_USERNAME')
    OPENIDM_PASSWORD = os.environ.get('OPENIDM_PASSWORD')
    AUDIT_TOPICS = os.environ.get('AUDIT_TOPICS', 'access,activity,authentication,config,sync').split(',')
    PAGE_SIZE = int(os.environ.get('PAGE_SIZE', '100'))
    MAX_PAGES = int(os.environ.get('MAX_PAGES', '50'))
    
    @functions_framework.cloud_event
    def main(cloud_event):
        """
        Cloud Run function triggered by Pub/Sub to fetch ForgeRock OpenIDM logs and write to GCS.
        """
        if not all([GCS_BUCKET, OPENIDM_BASE_URL, OPENIDM_USERNAME, OPENIDM_PASSWORD]):
            print('Error: Missing required environment variables')
            return
    
        try:
            bucket = storage_client.bucket(GCS_BUCKET)
            state = load_state(bucket, STATE_KEY)
    
            all_events = []
            for topic in AUDIT_TOPICS:
                topic = topic.strip()
                print(f"Fetching audit logs for topic: {topic}")
                events = fetch_audit_logs(topic, state.get(topic, {}))
                all_events.extend(events)
    
                if events:
                    latest_timestamp = max(e.get('timestamp', '') for e in events)
                    state[topic] = {
                        'last_timestamp': latest_timestamp,
                        'last_run': datetime.now(timezone.utc).isoformat(),
                        'events_count': len(events)
                    }
    
            if all_events:
                write_to_gcs(bucket, all_events)
                save_state(bucket, STATE_KEY, state)
                print(f"Successfully processed {len(all_events)} audit events")
            else:
                print("No new audit events to process")
    
        except Exception as e:
            print(f'Error processing logs: {str(e)}')
            raise
    
    def load_state(bucket, key):
        try:
            blob = bucket.blob(key)
            if blob.exists():
                return json.loads(blob.download_as_text())
        except Exception as e:
            print(f"Warning: Could not load state: {e}")
        return {}
    
    def save_state(bucket, key, state):
        try:
            blob = bucket.blob(key)
            blob.upload_from_string(json.dumps(state, indent=2), content_type='application/json')
        except Exception as e:
            print(f"Warning: Could not save state: {e}")
    
    def fetch_audit_logs(topic, topic_state):
        base_url = OPENIDM_BASE_URL.rstrip('/')
        all_events = []
        last_timestamp = topic_state.get('last_timestamp')
        query_filter = 'true' if not last_timestamp else f'timestamp gt "{last_timestamp}"'
        page_offset = 0
        page_count = 0
    
        while page_count < MAX_PAGES:
            try:
                url = f"{base_url}/openidm/audit/{topic}"
                params = {
                    '_queryFilter': query_filter,
                    '_pageSize': str(PAGE_SIZE),
                    '_pagedResultsOffset': str(page_offset),
                    '_sortKeys': 'timestamp'
                }
    
                headers = {
                    'X-OpenIDM-Username': OPENIDM_USERNAME,
                    'X-OpenIDM-Password': OPENIDM_PASSWORD,
                    'Accept-API-Version': 'resource=1.0',
                    'Accept': 'application/json'
                }
    
                response = http.request('GET', url, fields=params, headers=headers)
                if response.status != 200:
                    print(f"API error for topic {topic}: {response.status}")
                    break
    
                data = json.loads(response.data.decode('utf-8'))
                events = data.get('result', [])
                if not events:
                    break
    
                all_events.extend(events)
                page_offset += PAGE_SIZE
                page_count += 1
                if len(events) < PAGE_SIZE:
                    break
            except Exception as e:
                print(f"Error for topic {topic}: {str(e)}")
                break
        return all_events
    
    def write_to_gcs(bucket, events):
        timestamp = datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')
        filename = f"{GCS_PREFIX}/openidm_audit_{timestamp}.json"
        ndjson_content = '\n'.join([json.dumps(event) for event in events])
        bucket.blob(filename).upload_from_string(ndjson_content, content_type='application/x-ndjson')
    
    • requirements.txt:
    functions-framework==3.*
    google-cloud-storage==2.*
    urllib3>=2.0.0
    
  3. [デプロイ] をクリックします。デプロイには 2 ~ 3 分かかります。

Cloud Scheduler ジョブの作成

  1. GCP Console で、[Cloud Scheduler] に移動します。
  2. [ジョブを作成] をクリックします。
  3. 次の構成情報を提供してください。

    設定 値
    名前 forgerock-openidm-collector-hourly
    リージョン Cloud Run functions と同じリージョンを選択する
    周波数 0 * * * *(1 時間ごと)
    タイムゾーン タイムゾーンを選択(UTC を推奨)
    ターゲット タイプ Pub/Sub
    トピック forgerock-openidm-trigger
    メッセージ本文 {}
  4. [作成] をクリックします。

スケジュールの頻度オプション

頻度 CRON 式 ユースケース
5 分おき */5 * * * * 大容量、低レイテンシ
1 時間ごと 0 * * * * 標準(推奨)
毎日 0 0 * * * バッチ収集

統合をテストする

  1. Cloud Scheduler で、ジョブの [強制実行] をクリックします。
  2. Cloud Run のログで実行を確認します。Successfully processed X audit events を探します。
  3. Cloud Storage バケットの openidm/ フォルダに新しい json ファイルが存在することを確認します。

Google SecOps サービス アカウントを取得する

Google SecOps でフィードを構成する

  1. [SIEM Settings] > [Feeds] に移動します。
  2. [Add New Feed] > [Configure a single feed] をクリックします。
  3. フィード名: ForgeRock OpenIDM Audit Logs。
  4. ソースタイプ: Google Cloud Storage V2。
  5. ログタイプ: FORGEROCK_OPENIDM。
  6. [サービス アカウントを取得する] をクリックし、表示されたメールアドレス(例: chronicle-12345...)をコピーします。
  7. [次へ] をクリックします。
  8. ストレージ バケットの URL: gs://forgerock-openidm-audit-logs/openidm/。
  9. Source deletion option: 必要に応じて選択します(例: [Never])。
  10. [次へ] をクリックして内容を確認し、[送信] をクリックします。

IAM 権限を付与

  1. [Cloud Storage] > [バケット] に移動します。
  2. バケットを選択し、[権限] タブをクリックします。
  3. [アクセス権を付与] をクリックします。
  4. プリンシパルを追加: Google SecOps サービス アカウントのメールアドレスを貼り付けます。
  5. ロールを割り当てる: [Storage オブジェクト閲覧者] を選択します。
  6. [保存] をクリックします。

UDM マッピング テーブル

ログフィールド UDM マッピング ロジック
fluenttag_label、topic_label、context_roles_label additional.fields コンテキストの Key-Value ペア。
Via intermediary.hostname プロキシ/仲介業者のホスト名。
x_forwarded_ip、caller.callerIps intermediary.ip 仲介者の IP。
timestamp metadata.event_timestamp イベントのタイムスタンプ。
transactionId metadata.product_deployment_id 一意の取引 ID。
eventName metadata.product_event_type ForgeRock のイベント名。
_id metadata.product_log_id 一意のログ識別子。
request_method network.http.method 使用される HTTP メソッド。
response.statusCode network.http.response_code HTTP ステータス コード。
user_agent network.http.user_agent 完全なユーザー エージェント文字列。
client.ip、context.ipAddress principal.ip アクターの送信元 IP。
userId、principalData.0 principal.user.userid 操作を行うユーザーの ID。
security_action security_result.action セキュリティ上の判断が下されました。
level security_result.severity マッピングされた重大度レベル。
server.ip target.ip ターゲット システムの IP。
http.request.path target.url ターゲット URL/パス。
なし metadata.product_name ForgeRock OpenIDM に設定します。
なし metadata.vendor_name ForgeRock に設定します。
elapsed_time" and "X-Content-Type-Options additional.fields 変更履歴からマッピング
trackingIds.0 metadata.product_log_id 変更履歴からマッピング
context.userRolesProperty", "context.authenticationId", and "context.authenticationIdProperty principal.user.attribute.roles 変更履歴からマッピング
context.component", "context.moduleId", and "context.queryId principal.resource.attribute.labels 変更履歴からマッピング
context.roles", "_normalized.fieldNames", and "_eventId additional.fields 変更履歴からマッピング

変更ログ

このパーサーの変更ログを表示する

さらにサポートが必要な場合 コミュニティ メンバーや Google SecOps のプロフェッショナルから回答を得ることができます。