Claude Media
Compliance APIのSIEM連携 — ポーリングとカーソル増分読み取りの設計

Compliance APIのSIEM連携 — ポーリングとカーソル増分読み取りの設計

Compliance APIを継続的なパイプラインに組み込む際の3つの設計判断(消費パターン・SIEM相関・保持期間)を、公式ガイドの推奨に沿って示します。

Compliance API統合で決める3つの設計

Compliance APIを一度きりの照会ではなく、継続的なパイプラインへ組み込むときに決める設計判断は3つあります。Activity Feedをどう消費するか。出力を自社のSIEM(Splunk・Datadog・Microsoft Sentinel・Cribl等)とどう相関させるか。アクティビティやコンテンツの長期コピーをどこに置くか。この3つはエンドポイントの仕様とは独立していて、組み合わせ次第でパイプラインの安定性が変わります。Cribl Streamを使う場合の設定はCribl StreamでClaude Complianceログを取り込みマスクして振り分けるにあります。

Activity Feedそのものの呼び出し方(フィルタ・ページネーション)はCompliance API Activity Feedの使い方で扱いました。ここでは、単発のスクリプトを24時間稼働のパイプラインへ切り替える段階で見落としやすい判断に絞ります。Datadogの取り込み口を使う手順はDatadogでClaudeの監査ログを見るにあります。

ウィンドウポーリングとカーソル駆動のどちらで取るか

Activity Feedの消費パターンは2つあります。created_at.gteとcreated_at.ltで区切った時間窓を定期的に照会するウィンドウポーリングと、前回のレスポンスから引き継いだカーソルを次のリクエストに渡すカーソル駆動の増分読み取りです。返ってくるActivityオブジェクトは同じで、違いは呼び出しの間にクライアントが何を保持するかだけです。

くらべる

運用の形でパターンを選ぶ

ステートレス

ウィンドウポーリング

固定スケジュールで動くバッチ向けです。ワーカーが状態を持たず、窓の再取得や重複を許容できるなら、こちらが単純です。取りこぼしを防ぐには、窓を重ねるか古い窓を再照会する調整パスが要ります。

低遅延

カーソル駆動

常時稼働のパイプライン向けです。発生から取り込みまでの遅延が最小で、読んだページを読み直しません。代わりに、カーソルを永続化する置き場所が要ります。

どちらを選んでも、次の制約は共通です。アクティビティは発生から1分以内に照会可能になり、6年間保持されます。記録はCompliance APIを有効化した時点から始まり、それ以前の分は遡れません。1ページの上限はlimit=5000(既定は100)で、返却順は新しい順です。

ウィンドウポーリングの書き方

窓の上端created_at.ltは、現在時刻より最低1分前に置きます。窓内の全アクティビティが照会可能になっている状態を保つためです。連続する窓が隙間なく並ぶよう、前の窓のltを次の窓のgteにそのまま使います。

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"

レスポンスのhas_moreがtrueなら、窓の中に1ページを超える件数があります。last_idをafter_idに渡して窓の中をページングするか、時間窓を細かくして対処します。

窓をきれいに並べても、窓が閉じたあとに索引されたアクティビティは、後続のどの窓にも現れません。idで重複排除したうえで、窓を数分だけ重ねるか、古い窓を定期的に再照会する調整パスを設けます。

カーソル駆動の書き方

最新ページのfirst_idを保存しておき、次回それをbefore_idとして渡すと、保存したカーソルより新しいアクティビティだけが返ります。逆方向のバックフィルには、last_idをafter_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"

カーソルは不透明な文字列です。値をパースしたり、組み立てたりしません。キーをローテーションしても、保存済みのカーソルは使い続けられます。

追いつき型の取り込みループを組む

カーソル駆動で事故が起きるのは、ループの順序を間違えたときです。1回のレスポンスだけを見て「追いついた」と判断すると、新しいページが未読のまま残ります。before_idで進む方向は現在時刻に向かうため、1レスポンスで終わりと決めつけられません。

手順

1ループの順序

  1. 1

    保存済みカーソルで1ページ取る

    before_idに前回のfirst_idを渡します。初回はbefore_idなしで最新ページを取り、そのfirst_idを初期カーソルとして保存します。それより古い分は、last_idとafter_idで別途バックフィルします。

  2. 2

    ページを書き込んでからカーソルを進める

    SIEMへの送出かストレージへの書き込みが終わった後で、first_idを次のカーソルにします。失敗(5xx・タイムアウト・429)したリクエストはカーソルを進めません。同じカーソルで再送します。成功したページのカーソルは、再送時も有効です。

  3. 3

    `has_more`が`false`になるまで繰り返す

    falseになった時点のfirst_idを永続化します。途中で落ちたら、前回の永続値から読み直せば、重複はあっても欠落はありません。

この順序をそのままシェルにしたのが次のスクリプトです。429ではretry-afterの秒数だけ待ち(ヘッダーが無ければ1秒。倍々に延ばす処理は省いています)、カーソルは進めません。カーソルファイルが空の初回は、最新の1ページだけを書き込んで終わります。

#!/usr/bin/env bash
set -euo pipefail
 
API="${API:-https://api.anthropic.com}/v1/compliance/activities"
CURSOR_FILE="${CURSOR_FILE:-cursor.txt}"
OUT="${OUT:-activities.ndjson}"
 
cursor=$(cat "$CURSOR_FILE" 2>/dev/null || true)
 
while :; do
  q=(--data-urlencode "limit=5000")
  [ -n "$cursor" ] && q+=(--data-urlencode "before_id=$cursor")
 
  code=$(curl -sS -G "$API" -D headers.txt -o page.json -w '%{http_code}' \
    --header "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
    --header "anthropic-version: 2023-06-01" "${q[@]}")
 
  if [ "$code" = "429" ]; then
    ra=$(awk 'tolower($1)=="retry-after:"{print $2+0}' headers.txt)
    sleep "${ra:-1}"
    continue
  fi
  [ "$code" = "200" ] || { echo "HTTP $code" >&2; exit 1; }
 
  jq -c '.data[]' page.json >> "$OUT"
 
  first_id=$(jq -r '.first_id // empty' page.json)
  [ -n "$first_id" ] && cursor="$first_id"
  [ "$(jq -r '.has_more' page.json)" = "false" ] && break
done
 
printf '%s' "$cursor" > "$CURSOR_FILE"

このスクリプトはファイルへ追記するだけです。SIEMへ直接送る構成にするなら、送出が成功してからfirst_idを進めます。

レート制限は全キー・全ワーカーで分け合う

リクエストは親組織あたり毎分600件までで、Compliance Access Keyも、リンクされた全組織のAdmin API keyも、/v1/compliance/*の全エンドポイントも同じ枠を共有します。リモートセッションのエンドポイントだけは、これに加えて別枠の予算を持ちます。

レスポンスにはanthropic-ratelimit-requests-remainingなどのヘッダーが付くので、枠が尽きる前に間隔を広げられます。429が返ったときはretry-afterの秒数だけ待ちます。このヘッダーが落ちている場合は、1秒から始めて60秒まで倍々に待つ指数バックオフが推奨されています。リモートセッションの別枠で429になったときのretry-afterは常に1で、実際のリセット時刻ではありません。繰り返し429になるなら、指数バックオフに切り替えます。

SIEMと相関させるフィールド設計

各Activityは、SIEM側に既にあるイベントと突合できるフィールドを持ちます。

Activityのフィールド突合先
actor.user_id突合先IDプロバイダーの安定したユーザー識別子
actor.email_address突合先安定したIDが無いときのディレクトリのメールアドレス
actor.ip_address突合先ネットワーク・VPN・エンドポイントのログ
actor.user_agent突合先端末の資産台帳、リクエストを出したクライアントアプリ
created_at突合先あらゆるログソースとの時間窓相関

主キーはemail_addressではなくuser_idにします。user_idはどのCompliance APIエンドポイントでも同じ値で、メールアドレスや表示名が変わっても変わらないためです。user_idとemail_addressが入るのはactor.typeがuser_actorのときだけです。ip_addressとuser_agentも、anthropic_actorやscim_directory_sync_actorでは存在しません。フィールドを読む前にactor.typeで分岐します。

取り込み側で外れやすい3つの前提

注意

フィールドを読む前に押さえる点

  • user_actorは本人の操作とは限らない

    Anthropicがユーザーに代わって動かす処理(たとえばメモリー移行のplatform_memory_createdなど)も、当面はuser_actorとして記録されます。この帰属は変わる可能性があります。メモリー関連のアクティビティは、誰が行ってもip_addressが0.0.0.0になりえます。この値だけでプラットフォーム処理と判定することはできません。

  • viewedは人が見た印ではない

    claude_chat_viewed・claude_file_viewed・claude_project_viewedは、Claudeアプリがサーバーから内容を読み込むたびに記録されます。同じ読み込みの重複は除かれません。Web・デスクトップ・モバイルで読み込みのタイミングが違い、キャッシュ表示なら記録されないこともあります。送信メッセージ数や画面の表示回数とは対応しません。

  • ファイル名とタイトルは入らない

    2026年9月24日以降、ファイル・プロジェクトのドキュメント・アーティファクトに関するアクティビティのfilenameとtitleは、常にnull・空文字・省略のいずれかです。この日より前に記録された分も同じです。名前が必要なときは、アクティビティ内のclaude_file_*・claude_proj_doc_*・claude_artifact_version_*のIDで、対応するメタデータのエンドポイントを引きます。

新しいtypeやactor.typeは今後も増えます。未知の値はそのまま通し、期待していないフィールドは無視するハンドラーにしておけば、SIEM側のパーサーが新種のイベントで止まりません。

Compliance API自身の呼び出しも記録される

Compliance APIへの呼び出しは、compliance_api_accessedというアクティビティになります。activity_types[]=compliance_api_accessedで絞り、actor.typeがapi_actorのものからactor.api_key_idを読めば、どのキーがいつコンプライアンスデータへアクセスしたかをSIEMに残せます。Compliance Access KeyでもAdmin API keyでも、actor.typeはapi_actorになります。

created_atは、他のログソースとの時間窓相関に使います。たとえばVPNログで異常な地域からのアクセスを見つけたら、同じ時間帯のActivity Feedを引き、actor.ip_addressが一致するアクティビティを拾えます。SIEM側のスキーマにActivityの主要フィールドをそのままマッピングしておくと、調査のたびにフィールド名を読み替えずに済みます。

保持期間をどう設計するか

後から取得できる範囲は、5つの保持期間で決まります。

データ保持期間管理主体
Activity Feedの記録保持期間6年管理主体Anthropic
チャット・ファイル・プロジェクトの内容保持期間組織のclaude.ai保持ポリシー(ユーザーが先に削除しなければ)管理主体組織
ローカルセッションのトランスクリプト保持期間既定は6年。組織が有限の保持期間を設定していればその期間。HIPAA対応を有効にした組織は30日管理主体既定はAnthropic、設定時は組織
リモートセッションのトランスクリプト保持期間6年(ユーザーが先に削除しなければ)管理主体Anthropic
Compliance API経由でハード削除した内容保持期間保持されない(即時かつ永続的)管理主体DELETEを呼んだ側

自社の証跡保持要件が6年より長いなら、取得したページやトランスクリプトを自前のアーカイブへ取り込みのたびにエクスポートします。チャットやファイルの保持ポリシーが、eDiscoveryの対象期間より短い場合も同じです。保持期限が過ぎた内容は、Compliance APIからも返りません。

ローカルセッションは、組織の保持期間を変えた時点で扱いが変わります。現在の期間より古いメッセージは、設定を変えた直後から返らなくなります。期間を後から延ばしても、既に期限切れになったトランスクリプトは戻りません。残す必要があるものは、期限前にエクスポートします。

ユーザーがclaude.aiで削除したチャットや、削除したリモートセッションの内容も取得できません。法的保全(リーガルホールド)のように削除後も残す必要があるなら、取り込みの時点でチャット・ファイル・アーティファクト・リモートセッションの内容をアーカイブします。DLPの強制削除など、Compliance API経由のハード削除を伴うワークフローでは、削除より先に対象を取得して保存します。削除後の回復期間はありません。

上のどれにも当たらないなら、並行コピーは持たず、APIから都度取得で足ります。何が記録に含まれないか(暗号化キーが使えない組織のローカルセッション等の例外)はCompliance APIは内部統制の記録保存義務にどこまで応えるかにまとめてあります。

完全性をどう示すか

Activity Feedはat-least-once配信です。正しくページングした走査は全アクティビティを最低1回返しますが、部分的な失敗のあとのリトライでは、保存済みのアクティビティが再送されることがあります。idで重複排除するのが前提です。

一覧系のエンドポイントはtotal_countもチェックサムも返しません。エクスポートの完了を示すには、開始カーソルと終端のlast_id、エクスポートした件数、実行時刻、最終ページのrequest-idをログに残します。チェーン・オブ・カストディ(証拠の保管経路)が要る場合は、取得元エンドポイント、クエリパラメーター、実行時刻、各レコードのコンテンツハッシュも一緒に保存します。

アクティビティの件数は、完全性の指標になりません。閲覧系のアクティビティは各アプリの読み込み挙動に従うので、チャットメッセージがあるのにclaude_chat_viewedが無い期間があっても、それだけでデータ欠損とは言えません。確かめるのは、走査そのものと、窓の重なりや再照会の結果です。

よくあるつまずき

  • カーソルをパースしたり組み立てたりする: 内部フォーマットは安定しておらず、通知なく壊れます。発行されたカーソルでも、正しい形式のアクティビティIDでもない値は、400のinvalid_request_errorで返ります。直前のレスポンスのfirst_id・last_idをそのまま使います
  • ローカルセッションのページトークンを長く持ち越す: セッションのメッセージを取るエンドポイントでは、走査の最初のページから24時間でトークンが失効します。失効後はpageなしで走査をやり直します。Activity Feedのカーソルとは性質が違います
  • 単一のキーで全パイプラインを回す: 用途ごとにキーを分けておくと、compliance_api_accessedでアクセス元を絞り込みやすくなります。1本化は運用を単純にする一方、証跡の粒度を犠牲にします

まとめ

エクスポートが要るのは、Anthropic側の保持(6年・組織の保持ポリシー・ユーザー削除・ハード削除)が自社の保存義務より先に切れる場合です。それ以外は都度取得で足ります。idでの重複排除とuser_idでの相関は、どちらの取り込み方でも共通の前提になります。自前で組まずに既製のDLP・SIEM・eDiscovery製品へ流す選択肢は、Claude Compliance API連携の製品一覧にまとめています。

この記事を共有:XはてブLinkedIn