Compliance APIのSIEM連携 — ポーリングとカーソル増分読み取りの設計
Compliance APIを継続的なパイプラインに組み込む際の3つの設計判断(消費パターン・SIEM相関・保持期間)を、公式ガイドの推奨に沿って示します。
Compliance API統合で決めるべき3つの設計
Compliance APIを一度きりの照会ではなく、継続的なパイプラインへ組み込むなら、決めるべき設計判断は3つあります。1つ目はActivity Feedをどう消費するかです。2つ目は出力を自社のSIEM(Splunk・Datadog・Microsoft Sentinel・Cribl等)とどう相関させるかです。3つ目はアクティビティやコンテンツの長期コピーをどこに置くかです。この3つはエンドポイント自体の仕様とは独立していて、組み合わせ次第でパイプラインの安定性が大きく変わります。
Activity Feedそのものの呼び出し方(フィルタ・ページネーション)はCompliance API Activity Feedの使い方で扱いました。ここでは、それを継続的な運用に載せる設計に絞ります。単発のスクリプトから、24時間稼働のパイプラインへ切り替える段階で見落としやすい判断ばかりです。
消費パターンを選ぶ — ウィンドウポーリングvsカーソル駆動
Activity Feedは2つの消費パターンに対応します。created_at.gteとcreated_at.ltで区切った時間窓を定期的に照会するウィンドウポーリングと、前回のレスポンスから引き継いだカーソルを次のリクエストに渡すカーソル駆動の増分読み取りです。どちらも同じActivityオブジェクトを返します。違いはクライアント側が呼び出しの間で何を保持するかです。
ウィンドウポーリングを使う場合
パイプラインが固定スケジュールで動き、ステートレスなワーカーを好み、ウィンドウの再取得や重複を許容できるなら、ウィンドウポーリングが向きます。
curl --fail-with-body -sS -G \
"https://api.anthropic.com/v1/compliance/activities" \
--header "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
--header "anthropic-version: 2023-06-01" \
--data-urlencode "created_at.gte=2026-04-20T07:00:00Z" \
--data-urlencode "created_at.lt=2026-04-20T08:00:00Z" \
--data-urlencode "limit=5000"created_at.ltは現在時刻より最低1分前に設定します。ウィンドウ内の全アクティビティが照会可能になっているようにするためです。連続する窓が隙間なく重なるよう、前の窓のltを次の窓のgteにそのまま流用します。窓を閉じたあとに索引されるアクティビティは、その窓を過ぎた時点で二度と戻ってきません。idで重複排除しつつ、窓を数分だけ重ねる、または古い窓を定期的に再照会する調整パスを設けます。
カーソル駆動の増分読み取りを使う場合
アクティビティ発生からパイプライン取り込みまでの遅延を最小にしたい、既に読んだページを読み直したくない、カーソルを永続化する場所があるなら、カーソル駆動が向きます。
first_id="activity_01XyDMpzjS89pFZXqSFUBDr6"
curl --fail-with-body -sS -G \
"https://api.anthropic.com/v1/compliance/activities" \
--header "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
--header "anthropic-version: 2023-06-01" \
--data-urlencode "limit=5000" \
--data-urlencode "before_id=$first_id"has_moreがfalseになるまでページを読み進め、最終レスポンスのfirst_idを永続化します。次回はそれをbefore_idとして渡すと、保存したカーソルより新しいアクティビティだけを取得できます。逆方向のバックフィルにはlast_idをafter_idとして使います。カーソルはキーのローテーションをまたいでも有効です。1回のレスポンスだけを見て「追いついた」と判断しないことが重要です。has_moreがtrueの間は、まだ読んでいない新しいページが残っています。
どちらのパターンを選ぶか
| 観点 | ウィンドウポーリング | カーソル駆動 |
|---|---|---|
| 状態管理 | ウィンドウポーリング不要(ステートレス) | カーソル駆動カーソルの永続化が必要 |
| 遅延 | ウィンドウポーリングポーリング間隔ぶん発生 | カーソル駆動最小 |
| 重複耐性 | ウィンドウポーリング窓の重なりで吸収 | カーソル駆動idでの重複排除が前提 |
| 向く運用 | ウィンドウポーリング固定スケジュールのバッチ | カーソル駆動常時稼働のパイプライン |
両パターンとも共通の制約を持ちます。アクティビティは発生から1分以内に照会可能になり6年保持され、記録はCompliance API有効化時点からしか遡りません。ページの上限はlimit=5000です。カーソル値は不透明な文字列としてパースせずに扱います。レート制限は親組織単位で毎分600リクエストを共有し、リモートセッションのエンドポイントだけは別枠の予算を追加で持ちます。どちらのパターンで始めても、後から他方へ切り替えることは可能です。ただし切り替え時にカーソルの初期化や重複期間の扱いを決め直す必要があるので、最初の選択は運用要件から逆算しておきます。
SIEMと相関させるフィールド設計
各Activityは、SIEM側に既にあるイベントと突合するためのフィールドを持ちます。actor.user_idはIDプロバイダーの安定したユーザー識別子と、actor.email_addressはディレクトリのメールアドレスと、actor.ip_addressはネットワーク・VPN・エンドポイントのログと、actor.user_agentはエンドポイント資産管理台帳と、それぞれ突合できます。
主キーにすべきはemail_addressではなくuser_idです。ユーザーのメールアドレスや表示名が変わっても値が変わらないためです。actor.ip_addressとactor.user_agentはanthropic_actorやscim_directory_sync_actorのような一部のactor種別では存在しないので、フィールドを読む前にactor.typeの判別を必ず確認します。
Compliance API自体への呼び出しもcompliance_api_accessedというアクティビティとして記録されます。activity_types[]=compliance_api_accessedで絞り込み、actor.typeがapi_actorのイベントからactor.api_key_idを読めば、どのキーが誰の代理でいつコンプライアンスデータへアクセスしたかをSIEM側に記録できます。コンプライアンスチーム自身の操作も監査対象に含める設計です。
created_atは、他のログソースとの時間窓相関に使います。たとえばVPNログで異常な地域からのアクセスを検知したら、同じcreated_atの範囲でActivity Feedを照会し、actor.ip_addressが一致するアクティビティを拾い上げる、という突き合わせが組めます。SIEM側のスキーマにActivityの主要フィールドをそのままマッピングしておけば、インシデント調査のたびにフィールド名を読み替える手間が省けます。
保持期間をどう設計するか
Compliance APIが後から取得できる範囲は、5つの保持期間の組み合わせで決まります。Activity Feedの記録は6年保持されます。チャット・ファイル・プロジェクトのコンテンツは、ユーザーが先に削除しない限り、組織のclaude.ai保持ポリシーに従います。ローカルセッションのトランスクリプトは、既定では6年、組織が有限の期間を設定していればその期間です。リモートセッションのトランスクリプトは、ユーザーが削除しない限り6年です。そしてCompliance API経由でハード削除したコンテンツは、即座かつ永続的に失われます。5つのうちどれが自社の要件に対して短すぎるかを、先に洗い出しておきます。
自社の証跡保持要件がこれらの期間より長い場合は、取得したページやトランスクリプトを自前のアーカイブへその都度エクスポートします。逆に、6年に収まる範囲でオンデマンド取得が足りるなら、並行してコピーを保持する必要はありません。Compliance API経由のハード削除を伴うワークフロー(DLPの強制削除等)がある場合は、削除より先に対象コンテンツを取得・保存しておきます。削除後の回復手段はありません。何が記録に含まれないか(暗号化キーが使えない組織のローカルセッション等の例外)はCompliance APIは内部統制の記録保存義務にどこまで応えるかにまとめてあります。
データの完全性をどう保証するか
Activity Feedはat-least-once配信です。正しくページングされた走査は全アクティビティを最低1回返しますが、部分的な失敗のあとのリトライは、既に保存済みのアクティビティを再送することがあります。idフィールドで重複排除するのが前提です。
一覧系のエンドポイントはtotal_countもチェックサムも返しません。エクスポートが完全に終わったことを示すには、開始カーソルと終端のlast_id、エクスポートしたレコード数、実行時刻と最終ページのrequest-idをログに残します。アクティビティの件数だけを完全性の判定に使うのは避けます。claude_chat_viewedのような閲覧系のアクティビティはアプリの読み込み挙動に左右されるため、チャットメッセージがあるのに閲覧イベントが無い期間があっても、それだけではデータ欠損を意味しません。
よくあるつまずき
- ウィンドウの下限を現在時刻に近づけすぎる: 索引の遅延(最大1分)より内側に
created_at.ltを設定すると、遅れて索引されたアクティビティを永久に取りこぼします。1分は目安ではなく仕様上の下限として扱います - カーソルをキャッシュや別システムへコピーして再構築する: 内部フォーマットは安定しておらず、パースや再構成をすると通知なく壊れます
has_moreがtrueのまま処理を「完了」扱いにする: カーソル駆動では、まだ読んでいない新しいページが手前に残っています- 重複排除をしないまま件数をアラートの閾値に使う: at-least-once配信のもとでは、リトライによる再送で件数が実際の発生数より多く出ることがあります
- 保持期間の設定変更後に過去のトランスクリプトが復活すると期待する: ローカルセッションの保持期間を後から延ばしても、既に期限切れになった過去のトランスクリプトは戻りません
- 単一のキーで全パイプラインを回す: どのキーがいつ何を取得したかを
compliance_api_accessedで追跡する前提なら、用途ごとにキーを分けておいたほうが、インシデント時にアクセス元を絞り込みやすくなります。1本化は運用を単純にする一方、証跡の粒度を犠牲にします
まとめ
Compliance APIを継続的なパイプラインに組み込む設計は、3段階で決まります。まず、状態を持たないウィンドウポーリングか、低遅延なカーソル駆動かを選びます。次に、actor.user_idを軸にSIEMと相関させます。最後に、6年という基準の保持期間を自社の要件と突き合わせます。at-least-once配信を前提にした重複排除と、完全性を示すログの取り方まで押さえておけば、単発の照会から継続運用への切り替えに迷いません。どれも後から変更できますが、最初に決めておくほど作り直しは減ります。Compliance API自体の位置づけはCompliance APIとはを参照してください。