Claude Code SIEM連携でOTELイベントを監査基盤に送る
Claude CodeのOTELログイベントをSIEMへ送る設定を、プロトコル選択・mTLS認証・管理設定でのロック方法まで具体的にまとめます。
はじめに
Claude Codeが出力するOTel(OpenTelemetry)のログイベントは、Security Information and Event Management(SIEM)に取り込める形式で設計されています。OTLPのlogsエクスポーターを、SIEM側のOTLP受信エンドポイントか、SIEMへ転送するOpenTelemetry Collectorに向けるだけです。ツールの実行結果・権限判断・MCP接続などがイベントとして流れ込みます。
前提は次のとおりです。
| 項目 | 必要な状態 |
|---|---|
| Claude Code | 必要な状態制約なし。ただしエンドポイント・プロトコル・認証情報の削除挙動はv2.1.217以降が対象 |
| SIEM側 | 必要な状態OTLPを受信できるレシーバー、またはOTel Collectorを経由した転送経路 |
| 設定権限 | 必要な状態シェル変数、または管理設定(managed settings)ファイルへの書き込み権限 |
メトリクスによるコスト・利用量の可視化はClaude CodeのOpenTelemetryで利用量とコストを可視化が入り口です。どのイベントがどんな監査質問に答えるかはClaude Codeセキュリティ監査とOTELイベントの対応表にまとめました。OTel以外の監査経路を含む組織のセキュリティ設計はClaude Codeセキュリティ・権限ガイド、モデルの拒否を数えるイベントはapi_refusalイベントの読み方が詳しいです。
ステップ1: OTLPプロトコルとエンドポイントを決める
OTLPにはgrpc・http/protobuf・http/jsonの3プロトコルがあり、Claude Codeには既定プロトコルがありません。有効化する信号(metrics / logs / traces)ごとにOTEL_EXPORTER_OTLP_PROTOCOLか信号別の変数を必ず指定します。
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_LOGS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_LOGS_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://siem.example.com:4318/v1/logs
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer your-siem-token"信号別の変数(OTEL_EXPORTER_OTLP_LOGS_ENDPOINTなど)は、汎用のOTEL_EXPORTER_OTLP_ENDPOINTより優先されます。ヘッダーだけは置き換えではなくマージです。信号別のOTEL_EXPORTER_OTLP_LOGS_HEADERSを足すと、汎用のヘッダーと合わさって送られます。メトリクスはコスト用のCollectorへ、イベントだけをSIEMへ、という振り分けもこのエンドポイント分離で成立します。
mTLSを要求するSIEMやCollectorに接続するときは、プロトコルによって証明書関連の変数名が異なります。取り違えると証明書を設定したのに認証エラーが取れないという事態になるため、先に対応を確認しておきます。
| プロトコル | クライアント証明書変数 | CollectorのCAを信頼させる変数 |
|---|---|---|
http/protobuf / http/json | クライアント証明書変数CLAUDE_CODE_CLIENT_CERT / CLAUDE_CODE_CLIENT_KEY(必要ならCLAUDE_CODE_CLIENT_KEY_PASSPHRASE) | CollectorのCAを信頼させる変数NODE_EXTRA_CA_CERTS |
grpc | クライアント証明書変数OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE / OTEL_EXPORTER_OTLP_CLIENT_KEY(信号別に上書きするならOTEL_EXPORTER_OTLP_METRICS_CLIENT_KEYのように信号名を挟んだ形) | CollectorのCAを信頼させる変数OTEL_EXPORTER_OTLP_CERTIFICATE |
ステップ2: 管理設定でエンドポイントをロックする
管理設定(managed settings)ファイルでOTEL_EXPORTER_OTLP_*系の変数を設定すると、Claude Codeは起動時に開発者側が設定した競合変数を削除し、デバッグログに警告を残します。送信先を設定の優先順位ではなく削除で塞ぐ仕組みです。何が消えるかは、管理設定に書いた変数の種類で決まります。
管理設定に書いた変数と、消える開発者側の変数
汎用エンドポイント
OTEL_EXPORTER_OTLP_ENDPOINTを書くと、開発者が設定した信号別エンドポイントがすべて消えます。汎用プロトコル
OTEL_EXPORTER_OTLP_PROTOCOLを書くと、開発者が設定した信号別プロトコルがすべて消えます。認証情報
OTEL_EXPORTER_OTLP_HEADERS・..._CLIENT_KEY・..._CLIENT_CERTIFICATEのどれかを書くと、その信号別版が消えます。加えて、開発者が設定したエンドポイント変数も汎用・信号別を問わず消えます。認証情報が別の受信先に渡らないようにするためです。消えないもの
OTEL_METRICS_EXPORTER・OTEL_LOGS_EXPORTER・ベータのOTEL_TRACES_EXPORTERは通常のキー優先順位のままです。
エクスポーターのセレクターが消えないので、開発者側の設定でイベント送信を止めたりconsoleエクスポーターに切り替えたりできてしまいます。SIEM連携を固定したい組織は、セレクターも管理設定側で明示します。
リポジトリの.claude/settings.jsonと.claude/settings.local.jsonに書かれたOTelエクスポーター変数は、そもそも無視されます。クローンしたリポジトリ経由で送信先を奪われる心配はありません。ただしリポジトリ側は、管理設定・--settings・起動環境が同じ変数を設定していない限り、セレクターをnoneにして信号を止められます。
削除挙動はClaude Code v2.1.217以降が対象です。それより前は、すべての変数が独立してキー優先順位に従っていたため、ユーザー設定やシェルで指定した信号別エンドポイントが、管理設定のCollectorから信号ごと逸れる余地がありました。管理ソースが複数あるときOTEL_LOGS_EXPORTERだけがテレメトリ単位でまとまり、他の2つがキー単位でマージされる挙動はv2.1.223以降です。Claude Desktopや自己ホスト環境のランナーが起動時にOTLPエンドポイントを指定した場合も、同じ削除が働きます(v2.1.251以降)。
ステップ3: イベントだけをSIEM向けに送る
メトリクスとログ(イベント)は別々のエクスポーターを持てるため、コスト可視化用のCollectorとSIEMを分離できます。SIEM連携だけが目的なら、OTEL_METRICS_EXPORTERは設定しないかnoneにして、OTEL_LOGS_EXPORTERだけを設定すれば送信量を抑えられます。
MCP呼び出しやBashコマンドの詳細までSIEM側で検知ルールに使いたい場合は、OTEL_LOG_TOOL_DETAILS=1を追加します。この設定なしでは、ユーザー設定のMCPサーバーに対するtool_result / tool_decisionイベントのツール名が"mcp_tool"という文字列に丸められ、引数も含まれません。
SIEM側のベアラートークンは失効・ローテーションするため、OTEL_EXPORTER_OTLP_HEADERSに静的な値を直書きし続けると更新のたびに設定変更が要ります。http/protobuf・http/jsonではotelHeadersHelperにヘッダー生成スクリプトを指定でき、Claude Codeが定期的に呼び出してヘッダーを再生成します。呼び出し間隔はCLAUDE_CODE_OTEL_HEADERS_HELPER_DEBOUNCE_MSで変えられ、既定値は29分です。grpcはこのヘルパーに対応せず、静的な変数だけを使います。
ヘルパーは文字列のキーと値からなるJSONを出力する必要があります。失敗したり形式が合わなかったりすると、動くようになるまでそのセッションのテレメトリはSIEMに一切届きません。対話セッションでは、otelHeadersHelper failed; telemetry is not being exportedという警告が1セッションに1回出ます。/statusにも失敗が表示されます。
管理設定の例は次の形です。
{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_LOGS_EXPORTER": "otlp",
"OTEL_LOG_TOOL_DETAILS": "1",
"OTEL_EXPORTER_OTLP_LOGS_PROTOCOL": "http/protobuf",
"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT": "https://siem.example.com:4318/v1/logs",
"OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer your-siem-token"
}
}届いているかの確認
- 1
プロンプトを1つ送る
この構成が反映されたセッションで、適当なプロンプトを送ります。
- 2
SIEMでuser_promptを探す
claude_code.user_promptイベントが検索に出れば、送信は成立しています。 - 3
届かなければデバッグログを取る
ログの出力先を指定して起動し、
[3P telemetry]の行を探します。3Pはthird-partyの意で、設定したエクスポーターの失敗はこの接頭辞で出ます。
--debug-file <path>は指定したパスにデバッグログを書き、デバッグモードも暗黙に有効にします。
claude --debug-file ./otel-debug.log
grep '\[3P telemetry\]' ./otel-debug.log[Anthropic telemetry]で始まる行はAnthropic側の別系統の運用テレメトリで、SIEM連携の不具合とは無関係です。
誰の操作かをSIEMで特定する
Claudeアカウントでログインしている場合、すべてのイベントにuser.email・user.account_uuid・organization.idなどが付きます。user.idとsession.idも付きます。開発者が起動したセッションでは、Bashコマンドもファイル編集もMCP呼び出しも、その開発者のアカウントの操作として記録されます。user.emailの送信先は設定したOTelエンドポイントだけで、Anthropicには送られません。
直接のAPIキーやAmazon Bedrock、Google CloudのAgent Platform、Microsoft Foundryで認証している場合は事情が違います。Claudeアカウントがセッションに存在しないため、埋まるのはuser.idとsession.idだけです。この構成でユーザーを特定するには、管理設定か起動ラッパーでユーザーごとにOTEL_RESOURCE_ATTRIBUTESを渡します。
export OTEL_RESOURCE_ATTRIBUTES="enduser.id=jdoe@example.com,enduser.directory_id=S-1-5-21-..."何が既定でSIEMに載らないか
SIEMに入るデータは、既定ではプライバシー寄りに絞られています。検知ルールが必要とする項目は、対応する変数を明示して初めて載ります。
| 載せたい内容 | 必要な変数 | 既定の扱い |
|---|---|---|
| ユーザーのプロンプト本文 | 必要な変数OTEL_LOG_USER_PROMPTS=1 | 既定の扱い長さだけを記録 |
| アシスタントの応答テキスト | 必要な変数OTEL_LOG_ASSISTANT_RESPONSES=1 | 既定の扱い長さだけを記録(未設定のときはOTEL_LOG_USER_PROMPTSが代わりに効く) |
| Bashコマンド・MCPのツール名と引数 | 必要な変数OTEL_LOG_TOOL_DETAILS=1 | 既定の扱い載らない |
| APIリクエスト・レスポンスの全文 | 必要な変数OTEL_LOG_RAW_API_BODIES | 既定の扱い載らない |
OTEL_LOG_RAW_API_BODIESは会話履歴全体を含み、設定すると上の3つの内容への同意も含むことになります。file:<dir>を指定すると全文は<dir>のファイルに書かれ、イベントにはbody_refのパスだけが載ります。このディレクトリはテレメトリのストリームではなく、ログ収集のサイドカーで送る設計です。
OTEL_LOG_TOOL_DETAILS=1のtool_parametersでは、full_commandのようなBashのコマンド文字列が切り詰められずに載ります。コマンドにシークレットが混ざりうる環境では、SIEM側の保持期間とアクセス権の設計が先に要ります。
管理設定が効いているかもイベントで見る
v2.1.274以降のClaude Codeは、セッションが解決した管理設定をclaude_code.managed_settings_resolvedイベントとして送ります。セッション開始時に1回、管理設定やポリシーヘルパーの状態が途中で変わったときにもう1回出ます。ロックしたはずの端末が想定外の管理ソースで動いていないかを、SIEM側から検出できます。
managed_settings.triggerはstartup・change・refusedのどれかです。refusedは管理設定のポリシーがセッションを止めたときで、error.typeに理由が入ります。たとえばversion_below_minimumはrequiredMinimumVersion未満、またはrequiredMaximumVersion超のバージョンの端末、helper_failedはポリシーヘルパーの実行失敗です。信頼していないフォルダーの対話セッションでは、この拒否イベントは送られません。
既定では設定の中身は載らず、管理ソースとヘルパーの状態だけが載ります。OTEL_LOG_MANAGED_SETTINGS=1を管理設定・ユーザー設定・--settings・起動環境のどこかに置くと、値を伏せた設定の形(managed_settings.settings)と、伏せる前の設定のSHA-256ダイジェスト(managed_settings.resolved_sha256)の2つの属性が加わります。プロジェクト設定やローカル設定に書いた値は無効です。クローンしたリポジトリが書き換えられるためです。サーバー管理設定なら、承認ダイアログを出さずにこの変数を設定できます。
ダイジェストが同じ端末は同じポリシーで動いています。全社の適用状況は、ダイジェストの種類数で数えられます。
信号ごとにどのバックエンド特性が要るか
SIEM連携ではイベント(ログ)だけを意識しがちですが、メトリクス・トレースを同じ組織内の別基盤に振り分ける設計も珍しくありません。信号ごとに向いているバックエンド特性が異なります。
| 信号 | 向くバックエンド特性 | できる分析 |
|---|---|---|
| メトリクス | 向くバックエンド特性時系列データベース / 列指向ストア | できる分析レート計算、ユニークユーザー分析 |
| イベント(ログ) | 向くバックエンド特性ログ集約基盤 / SIEM | できる分析全文検索、監査イベントの構造化分析 |
| トレース(ベータ) | 向くバックエンド特性分散トレーシング対応基盤 | できる分析スパン可視化、リクエストのウォーターフォール表示 |
DAU/WAU/MAUのようなアクティブユーザー数を継続的に見たい組織は、ユニーク値クエリを効率的に処理できるバックエンドを選ぶ必要があります。イベントをSIEMに、メトリクスを別基盤に振り分ける構成は、OTEL_EXPORTER_OTLP_METRICS_ENDPOINTとOTEL_EXPORTER_OTLP_LOGS_ENDPOINTを別々に指定するだけです。
SIEM側でホストとバージョンを絞り込む属性
すべてのメトリクス・イベントには、送信元を特定するためのリソース属性が共通で付きます。service.nameはターミナルセッションならclaude-code、Claude DesktopアプリのCodeタブから起動したセッションならclaude-code-desktopになります。既存のCollectorパイプラインやダッシュボードがservice.name = claude-codeだけでフィルタしている場合、Desktopアプリ経由のテレメトリを取りこぼすため、claude-code-desktopもフィルタに加える必要があります。
他にもservice.version(Claude CodeまたはDesktopアプリのバージョン)、os.type / os.version、host.arch、WSL環境でのみ付くwsl.versionが付きます。SIEM側で「未パッチのバージョンからの操作だけを抽出する」「特定OSからの異常な操作を洗い出す」といった絞り込みルールを組むときの軸になります。Meter Nameはcom.anthropic.claude_code固定です。
mTLS証明書をローテーションしてもSIEMに届かなくなる罠
API接続用のクライアント証明書(CLAUDE_CODE_CLIENT_CERT / CLAUDE_CODE_CLIENT_KEY)は、差し替えれば再起動なしで反映されます。
証明書を差し替えたとき、どこまで反映されるか
API接続
接続リセットやTLSハンドシェイク失敗のような接続レベルのエラーを検知すると、証明書と鍵を読み直して再試行します。ファイルを監視しているわけではなく、失敗が起点です。ゲートウェイがハンドシェイクを完了してHTTPエラーを返す場合は読み直されず、次の設定適用か再起動で新しい証明書に替わります。
OTLPエクスポーター
最初に使ったときに読み込んだ証明書を保持し続けます。差し替えてもSIEMへの接続には反映されず、Claude Codeを再起動して初めて新しい証明書が届きます。
API接続は生きているのにSIEMへの送信だけが古い証明書のまま失敗し続けるため、切り分けにくい状態になります。証明書をローテーションしたら、SIEM連携用のセッションは再起動する運用が安全です。API側で読み直しが走ったかは、デバッグログのStale connection — reloaded rotated mTLS client materialで確認できます。読み直し自体を止めたいときはCLAUDE_CODE_DISABLE_MTLS_RELOAD_ON_STALE_CONNECTION=1を設定します。
よくあるつまずき
- 証明書変数を設定したのに認証エラーが取れない:
grpc用のOTEL_EXPORTER_OTLP_CLIENT_KEYとhttp/protobuf用のCLAUDE_CODE_CLIENT_KEYは別の変数です。プロトコルに対応する変数名を取り違えていないか確認します。 411 Length Requiredまたは400エラーが返る: v2.1.212より前のバージョンは、v2.1.191以降でチャンク転送エンコーディングを使っており、宣言された長さを要求するAzure Monitorなどの受信先が拒否していました。Content-Lengthヘッダーを送るv2.1.212以降にアップグレードすると解消します。- Cowork側の設定画面に送信先を入れたのにCLIのイベントが届かない: 管理コンソールのデータとプライバシー設定にあるMonitoringのOpenTelemetryフォームはCowork専用です。ターミナルのCLIもDesktopのCodeタブも、そこで設定した送信先には出力しません。管理設定のenvで指定します。
- Bashツールから起動した別のOTel対応アプリにテレメトリ設定が引き継がれない: Claude Codeは
OTEL_*環境変数をBashツール・フック・MCPサーバー・言語サーバーといったサブプロセスに渡しません。サブプロセス自身のテレメトリが必要なら、コマンド内で改めて変数を指定します。子プロセスへの認証情報漏えいを防ぐにはCLAUDE_CODE_SUBPROCESS_ENV_SCRUBが使えます。
まとめ
SIEM連携の骨格は、OTEL_LOGS_EXPORTER=otlpとSIEM向けのOTLPエンドポイントの2つです。送信先を組織で固定するなら、エンドポイントと認証情報に加えてエクスポーターのセレクターも管理設定に書きます。証明書を更新したあとは、SIEM用のセッションを再起動します。セレクターまで固定することと、証明書更新後の再起動で、取りこぼしが減ります。