Claude Media
Claude Codeセキュリティ監査とOTELイベントの対応表

Claude Codeセキュリティ監査とOTELイベントの対応表

セキュリティ監査でよく出る質問と、それに答えるClaude CodeのOTELイベント・属性を1対1で引ける対応表にまとめます。

このTipsでできること

セキュリティ監査で「この質問にはどのイベントを見ればいいか」を都度ドキュメントから探す代わりに、質問からイベント名・属性へ一発で引ける対応表をまとめます。Claude Codeが出すのはイベントの生ストリームだけです。異常検知やベースライン化、セッションをまたいだ相関分析、アラートの発報はSIEMや可観測性バックエンド側で組みます。

監査の質問からイベントを引く

対応表は「知りたいこと」から「イベント名」「見るべき属性」「追加で必要な設定」を1行で引ける形です。「必要な設定」列にOTEL_LOG_TOOL_DETAILS=1とある行は、そのフラグを立てないと該当の属性が伏せられたまま記録されます。「標準で取得可」の行は追加設定なしで取得できます。

知りたいことイベント主な属性必要な設定
コマンドが許可・拒否されたか、誰の判断かイベントtool_decision主な属性decision・source・tool_name必要な設定標準で取得可(引数はOTEL_LOG_TOOL_DETAILS=1)
実行されたコマンド・触れたファイルイベントtool_result(実行時)/ tool_decision(拒否時)主な属性tool_parameters・tool_input必要な設定OTEL_LOG_TOOL_DETAILS=1
権限モードが昇格したか(auto→bypassPermissions等)イベントpermission_mode_changed主な属性from_mode・to_mode・trigger必要な設定標準で取得可
ポリシーhookがアクションをブロックしたかイベントhook_execution_complete主な属性hook_event・num_blocking必要な設定標準で取得可
ログイン・ログアウト・認証失敗イベントauth主な属性action・success・error_category必要な設定標準で取得可
MCPサーバーの接続・切断・失敗イベントmcp_server_connection主な属性status・server_name・is_plugin・error_code必要な設定server_nameはOTEL_LOG_TOOL_DETAILS=1
プラグインがインストールされたか、出所はイベントplugin_installed主な属性plugin.name・marketplace.name・marketplace.is_official必要な設定サードパーティ名はOTEL_LOG_TOOL_DETAILS=1
フリート全体で有効なプラグインの棚卸しイベントplugin_loaded主な属性plugin.scope・enabled_via・has_hooks・has_mcp必要な設定標準で取得可(名前の一部は要フラグ)
フリート全体で設定されているhookの棚卸しイベントhook_registered主な属性hook_event・hook_type・hook_source・safe_mode必要な設定標準で取得可
端末が適用している管理設定の出所と、起動拒否の理由イベントmanaged_settings_resolved主な属性managed_settings.sources・managed_settings.helper.state・error.type必要な設定設定の名前と構造(値は伏せ字)とダイジェストはOTEL_LOG_MANAGED_SETTINGS=1(v2.1.274以降)
APIリトライが枯渇したか(異常・障害の兆候)イベントapi_retries_exhausted主な属性total_attempts・status_code必要な設定標準で取得可
どのスキルがいつ起動されたかイベントskill_activated主な属性skill.name・invocation_trigger・skill.source必要な設定カスタムスキル名はOTEL_LOG_TOOL_DETAILS=1
サブエージェント実行の集計イベントsubagent_completed主な属性agent_type・total_tool_uses・duration_ms必要な設定カスタムエージェント名はOTEL_LOG_TOOL_DETAILS=1
予期しない内部エラーの発生イベントinternal_error主な属性error_name・error_code必要な設定標準で取得可(メッセージ・スタックトレースは含まれない)
セッションデータが保持期間どおり削除されたかイベントretention_sweep主な属性result・transcripts_deleted・period_days必要な設定標準で取得可

公式のセキュリティ向け対応表に載っているのは、tool_decisionからmanaged_settings_resolvedまでの8行(tool_resultを含む)です。プラグイン・hookの棚卸し、リトライ枯渇、保持期間の消込みなどは、イベント一覧には別項目として定義されているものの、その対応表には行がありません。hookそのものの設定方法や種類はClaude Code Hooks完全ガイドに、ユーザーを誰の操作かに紐づける属性はClaude Code OTELユーザー特定に、イベントをSIEMへ届ける設定はClaude Code SIEM連携にあります。

OTEL_LOG_TOOL_DETAILSの有無でMCP監査の見え方が変わる

decisionやstatusのような判断結果そのものは、標準の識別属性だけで取得できます。tool_parametersやtool_inputのような何を実行したかの中身は、フラグを立てて初めて乗ります。差が最も大きいのがMCPです。

くらべる

MCPの監査で見える範囲

判断結果だけ

フラグなし(既定)

mcp_server_connectionでは接続の成否(status)が追えます。server_nameとエラーメッセージは伏せられますが、is_pluginとplugin_id_hashは残るので、プラグイン経由のサーバーかどうかは判別できます。Anthropic公式の出所のプラグイン名は実名で、サードパーティは"third-party"に丸められます。

tool_resultとtool_decisionでは、ユーザー設定のMCPサーバーのtool_nameが文字列"mcp_tool"に置き換わります。どのサーバーのどのツールかは分かりません。例外はClaude Desktopの組み込みサーバー(tool_sourceがsdk_host_builtin_mcp)です。v2.1.214以降は、フラグなしでもmcp_server_name・mcp_tool_nameが出ます。この値になるのはClaude Desktopが持つセッションに限られ、入れ子のセッションでは"mcp"と報告されます。

中身まで追える

`OTEL_LOG_TOOL_DETAILS=1`

server_nameとエラーメッセージが記録されます。tool_resultとtool_decisionのtool_parametersにmcp_server_name・mcp_tool_nameが入り、tool_resultのtool_inputには呼び出し引数が乗ります。引数の値は512文字を超えると切り詰められ、全体も約4K文字が上限です。

「どのMCPサーバーの、どのツールが、どんな引数で呼ばれたか」まで踏み込む監査には、このフラグが前提になります。

注意したいのはtool_inputの置き場所です。公式のセキュリティ向け対応表では、tool_inputはtool_resultにだけ付き、拒否された呼び出しの内容はtool_decisionのtool_parametersで読みます。拒否側に引数全体を期待すると、フィールドが無く空振りします。

plugin_installedとplugin_loadedは別の質問に答える

plugin_installedはインストールという操作そのものを記録し、install.triggerでCLIコマンド経由かインタラクティブな/pluginUI経由かまで分かります。plugin_loadedはセッション開始のたびに、その時点で有効なプラグイン全部を1件ずつ記録します。

「いつ・誰が・どこからインストールしたか」を追うならplugin_installed、「今フリート全体でどのプラグインが動いているか」の棚卸しならplugin_loadedです。後者のenabled_viaは、有効になった経路をdefault-enable・org-policy・admin-install・seed-mount・user-installの5値で区別します。admin-installは、組織設定の「Plugins & skills」で必須または自動インストールに指定したプラグインです。v2.1.246より前は、これらがuser-installやseed-mountとして報告されていました。

管理者が把握していないプラグインを洗い出すときは、enabled_viaがuser-installで、plugin.scope(official・community・org・user-local・default-bundle)がcommunityかuser-localのものを重点的に見る、という絞り込みが効きます。v2.1.246より前のログでは、管理者が配ったプラグインがuser-installとして記録されているため、期間をまたぐ集計では版の境目に注意します。

対応表だけでは読み取れない限界

生イベントだけでは答えられない質問があります。hook_execution_completeのnum_blockingは、その回に何個のhookがブロック判定を返したかを数えます。複数のhookが登録されているときに、どれがブロックしたかはイベント単体では特定できません。hook_name(マッチャー込みのフック名)で絞れるのはそこまでで、それ以上はhook自体のログと突き合わせます。

hook_eventによって発生頻度の意味も変わります。PreToolUseは公式のhooksページで、エージェントループ内の全ツール呼び出しごとに走るとされています。PermissionRequestは、ツール呼び出しが権限判断を必要とするときに走ります。同じnum_blockingでも、PreToolUse側の集計は母数が桁違いに大きくなります。

tool_decisionのsourceが"config"のときは、プロジェクト設定・個人設定の許可/拒否ルール・組織のポリシー・--allowedToolsと--disallowedTools・現在の権限モード・同一セッションでの許可の持ち越し・本質的に安全なツール、のどれが決め手かが区別されません。許可プロンプト自体が失敗した場合も"config"で報告されます。Agent SDKのcanUseToolコールバックや--permission-prompt-toolのツールが無効な結果を返したときなどです。v2.1.216より前は、これらの失敗が"user_reject"で報告されていました。どのルールが効いたかは、対象マシンのsettings.json階層で別途確認します。

user_temporaryとuser_permanentにも読み違えやすい点があります。対話型CLIでは、この2つは許可プロンプトで選んだ瞬間のイベントにしか付きません。「今後は確認しない」で保存された許可ルールに後から一致した呼び出しは"config"になります。Agent SDKや非対話の-pセッションでは、後続の一致にもuser_temporary・user_permanentが付くので、同じ値でも実行形態によって意味が違います。

拒否側の読み方も実行形態で分かれます。user_abortは、許可プロンプトに答えず閉じた場合です。user_rejectは、プロンプトで「No」を選んだ場合です。対話型CLIでuser_rejectが付くのはその選択そのものだけで、個人設定の拒否ルールに一致した呼び出しは"config"になります。Agent SDKや非対話の-pセッションでは、個人設定の拒否ルールに一致した呼び出しにもuser_rejectが付きます。

イベントを横断して1つの操作を追う

1件のインシデントを調べるとき、複数のイベントを同じ操作にまとめる相関キーは3つあります。

相関

相関キー3種

  • prompt.id

    1つのユーザープロンプトの処理中に出た全イベントに共通するUUIDです。あるコマンド実行の前後で何が起きたかの軸になります。

  • session.id

    セッション単位のキーです。ログインやログアウトはauthイベントとして同じセッション内に現れるので、session.idでは認証から操作までを同じ軸に載せられます。

  • tool_use_id

    1回のツール呼び出しについて、tool_decisionとtool_resultに共通で付きます。hookに渡されるtool_use_idと同じ値なので、hookが捕捉したデータとOTelイベントを突き合わせられます。

並べる順序にはevent.sequenceも使えます。ただし公式の定義では、これはセッション単位ではなくClaude Codeのプロセス単位のカウンターです。同じsession.idで再開された別プロセスのイベントは、event.sequenceだけでは並びません。

たとえば「あるBashコマンドが拒否されたあと、権限モードが変わって再実行されたか」は、tool_decision(reject)→permission_mode_changed→tool_decision(accept)の順でprompt.idかsession.idをキーに並べれば追えます。

シナリオ:危険なコマンドが実行された疑いを調べる

対応表の行をつなげて、典型的な調査を追います。

手順

疑いのあるBashコマンドの追跡

  1. 1

    対象セッションを絞る

    session.idで対象セッションを選び、tool_decisionを時系列に並べてtool_nameがBashのものに絞ります。

  2. 2

    誰が許可したかを見る

    decisionがacceptでsourceがhookなら、PreToolUseかPermissionRequestのhookが決めた記録です。どのhookかは、hook_registeredのhook_sourceと突き合わせます。そのhookの設定意図が正しかったかを確認します。sourceがuser_temporaryかuser_permanentなら、開発者本人が許可プロンプトで選んだ記録です。

  3. 3

    止まるはずだったのに通った理由を探す

    hook_execution_completeのnum_blockingが0だったか、該当するhook_eventのhookがhook_registeredに存在するかを確認します。hook未設定やマッチャーの範囲外は、よくある原因です。

  4. 4

    権限モードの変化を遡る

    実行が権限モード変更の直後なら、permission_mode_changedのtriggerを見ます。shift_tabはキー操作による切り替え、exit_plan_modeはプランモードからの退出、auto_gate_deniedとauto_opt_inはautoモードの判定や選択に伴う変更です。SDKやブリッジ経由の遷移ではtriggerが付きません。

  5. 5

    実行内容を確定する

    tool_resultで実際の中身を確認します。OTEL_LOG_TOOL_DETAILS=1があればtool_parametersのfull_commandに、実行されたコマンドが入っています。

権限モード名の表記にも注意が要ります。公式のイベント定義はfrom_modeの例に"default"・"plan"・"acceptEdits"・"auto"・"bypassPermissions"を挙げています。一方、v2.1.287のclaude --helpでは--permission-modeの選択肢が次のとおりです。

claude --version
claude --help | grep -A3 -e "--permission-mode"
2.1.287 (Claude Code)
  --permission-mode <mode>              Permission mode to use for the session
                                        (choices: "acceptEdits", "auto",
                                        "bypassPermissions", "manual",
                                        "dontAsk", "plan")

--helpの選択肢表示にはdefaultが無く、代わりにmanualが載ります。CLIリファレンスではmanualはdefaultの別名で、どちらの値も使えます(v2.1.200以降)。from_modeの例は設定値側のdefaultで書かれています。SIEMの検知ルールで昇格を判定するときは、from_modeとto_modeに実際に届いた値を一度集計してから、条件に入れる表記を決める方法があります。

サブエージェントが実行した操作も同じ経路で追える

サブエージェントの監査では、見る軸が2つに分かれます。ツール呼び出しの中身を追う軸と、コスト・トークンを集計する軸は別のイベントです。

「あるサブエージェントが何をしたか」の概要は、subagent_completedのagent_type・total_tool_uses・duration_msで分かります。個々のツール呼び出しまで遡るには、起動元と同じsession.idのtool_decisionとtool_resultを時系列で並べます。OTEL_LOG_TOOL_DETAILS=1があれば、tool_parameters内のsubagent_typeでAgent tool(または旧Task tool)経由の呼び出しを絞れます。

query_source("main"・"subagent"・"auxiliary")はコスト・トークンのメトリクス側の軸です。サブエージェント分を集計するときは、トークンカウンターとコストカウンターをquery_sourceが"subagent"のものに絞ります。バックグラウンドで動くサブエージェント(is_asyncがtrue)もsubagent_completedに同じ形で記録されます。

まとめ

監査要件に「誰が何を実行したか」まで含まれるなら、OTEL_LOG_TOOL_DETAILS=1を有効にする設計と、ログに載る機微情報の扱いを先に決めておく流れになります。

よくある質問

プラグイン経由のhookとユーザー定義のhookを対応表で区別できますか

hook_registeredのhook_sourceがpluginHookかどうかで判別できます。pluginHookの場合はplugin.nameでどのプラグインのhookかまで分かります。サードパーティのプラグイン名はOTEL_LOG_TOOL_DETAILS=1がないと"third-party"に丸められます。hook_execution_complete側のhook_sourceはpolicySettingsかmergedの2値なので、登録元の内訳はhook_registeredで見ます。

--safe-modeで起動したセッションかどうかも追えますか

追えます。hook_registered・hook_execution_start・hook_execution_complete・plugin_loadedにsafe_mode属性があり、v2.1.169以降で記録されます。--safe-modeはCLAUDE.md・スキル・インストール済みプラグイン・hook・MCPサーバーなどを無効にして起動するオプションです。管理設定のポリシー(ポリシーで設定したhookなど)は引き続き適用されます。管理プラグイン・管理スキル・管理CLAUDE.md・ポリシーで設定したMCPサーバーは読み込まれません。期待したhookが動いていないときは、まずsafe_modeが"true"でないかを確認できます。

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