Claude Media
Claude CodeでAzure activity logを追い、変更履歴を時系列にする

Claude CodeでAzure activity logを追い、変更履歴を時系列にする

az monitor activity-log listを--offsetと--resource-groupで絞り、誰が何を変えたかをClaude Codeで時系列の表にします。90日の保持期限とLog Analyticsも扱います。

Azureで「昨日の夜、誰がこのリソースグループをいじったのか」を知りたいときは、Azure Monitorのactivity logが最初の手がかりになります。CLIでは az monitor activity-log list で取り出せます。Claude Codeにはこの出力を読ませ、caller(誰が)とoperationName(何を)を軸にした時系列の表へ整えさせるのが現実的な使い方です。

Azure Monitorのactivity logとは、サブスクリプション内で行われた管理操作(コントロールプレーンの操作)の記録です。仮想マシンの作成、Key Vaultのアクセスポリシー変更、デプロイのエラーなどが入ります。ここでは取得コマンドの絞り方、Claude Codeに渡す権限の決め方、90日で消える点への備えを順に見ます。

activity logに残るものと残らないもの

先に守備範囲を押さえておきます。ここを取り違えると、「ログに出ない」ことを「誰も触っていない」と読み違えます。

  • 記録されるのは、作成・更新・削除といった変更や、操作の開始が中心です。読み取り操作は通常は記録されません
  • キーの取得やデータベースへのリクエストのようなデータプレーンの操作は、リソースログの領域です。診断設定を作らないと集まりません
  • エントリは通常、イベント発生から3〜20分ほどで分析やアラートに使える状態になります
  • システムが生成するエントリで、後から変更も削除もできません

変更履歴を追う目的には、Administrativeカテゴリが主役になります。Resource Manager経由のcreate、update、delete、actionがここに入ります。Write、Delete、Actionの各操作では、開始と、成功または失敗の両方が記録されます。サブスクリプション内のAzure RBACの変更もAdministrativeに含まれるため、「誰かに権限を付けた」という変更も同じ手順で追えます。

取得コマンドの絞り方

az monitor activity-log list は、何も指定しない場合でも動きますが、既定値が控えめです。使う頻度の高い引数を表にします。

引数役割既定値・注意
--offset役割時間範囲を ##d##h 形式で指定既定値・注意既定は6h
--resource-group (-g)役割リソースグループで絞る既定値・注意省略時は絞らない
--caller役割メールアドレスまたはサービスプリンシパルIDで絞る既定値・注意人物の追跡に使う
--status役割Failed などの状態で絞る既定値・注意失敗だけを見たいとき
--max-events役割返す件数の上限既定値・注意既定は50
--select役割返すプロパティを限定既定値・注意callerやoperationNameなどを指定可
--start-time / --end-time役割範囲の開始・終了既定値・注意両方指定すると --offset は無視される

--offset の挙動は少し癖があります。--end-time だけ(または何も指定しない)の場合は、終了時刻からoffsetを引いた範囲になります。--start-time と組み合わせたときは、開始時刻にoffsetを足した範囲です。開始と終了の両方を渡すとoffsetは無視されます。

Microsoft Learnのコマンドリファレンスには、次のような例があります。

# 7月1日から1週間分
az monitor activity-log list --start-time 2018-07-01 --offset 7d
 
# 過去1時間、リソースグループで絞る
az monitor activity-log list -g {ResourceGroup} --offset 1h

変更履歴の調査では、リソースグループと期間を固定し、必要な列だけに絞る形が扱いやすくなります。

az monitor activity-log list \
  --resource-group my-rg \
  --offset 7d \
  --max-events 500 \
  --select eventTimestamp caller operationName status resourceId \
  --output json

--max-events の既定は50件です。期間を長く取っても50件で打ち切られるので、変更が多いリソースグループでは上限を引き上げます。件数が足りているかは、返ってきた最古の eventTimestamp が指定期間の頭に届いているかで判断できます。

Claude Codeにコマンドを任せる権限を決める

az コマンドは、Claude Codeが確認なしで実行する読み取り専用コマンドの組み込みセットには挙がっていません。そのまま頼むと、実行のたびに許可を求められます。調査用に読み取りだけを通すなら、permissions.allow に対象を絞って書きます。

{
  "permissions": {
    "allow": [
      "Bash(az monitor activity-log list *)",
      "Bash(az account show *)"
    ],
    "deny": [
      "Bash(az group delete *)",
      "Bash(az role assignment create *)"
    ]
  }
}

ルールの書き方には注意点が2つあります。まず、末尾の * の前の空白がルールの一部で、Bash(az monitor activity-log list *) はそのサブコマンドから始まるコマンドだけに一致します。次に、&& や | でつないだ複合コマンドは、すべての部分が許可されていないと確認が出ます。az ... | jq ... のようなパイプを使うなら、jq 側も許可するか、パイプを使わず --query で整形します。

denyは、より狭いallowがあっても優先されます。上の例の deny は、調査中にClaudeが誤って破壊的な操作へ進まないための保険です。Azureのログインは、あらかじめ読み取り権限だけを持つアカウントで行っておくと、権限ルールとの二重の備えになります。

取得結果を時系列の表にする

権限が決まったら、Claude Codeに次のように頼みます。

リソースグループ my-rg の直近7日間の変更を、az monitor activity-log list で
取得して。status が Succeeded のものだけを対象に、時刻の昇順で
「時刻 / caller / operationName / 対象リソース名」の表にして。
同じ correlationId のイベントは1行にまとめ、読み取りコマンドしか使わないこと。

頼み方の要点は3つです。

  1. 読み取りコマンドに限定する。誤操作を避ける最初の防波堤になります
  2. statusを絞る。Write系の操作は開始と成功・失敗の両方が記録されるため、絞らないと同じ操作が2行以上に膨らみます
  3. correlationIdでまとめる。同じcorrelationIdのイベントは同じ一連の操作に属します(operationId も、単一の操作に対応するイベントで共有されるGUIDです)

イベントのスキーマで、表の列に使えるフィールドは次のとおりです。

フィールド中身
caller中身操作したユーザーのメールアドレス、UPNクレーム、SPNクレームのいずれか(取得できるもの)
operationName中身操作名。value と localizedValue を持つオブジェクト
status中身Started、In Progress、Succeeded、Failedなど
resourceId中身影響を受けたリソースのID
eventTimestamp中身Azureのサービスがイベントを生成した時刻
correlationId中身同じ一連の操作に属するイベントが共有するID

operationName は文字列ではなくオブジェクトとして定義されています。JMESPathで直接整形するなら、operationName.value の形で指します。たとえば、時刻順に並べ替えつつ必要な列だけを取り出す場合は、CLI側の --query で組み立てられます。

az monitor activity-log list -g my-rg --offset 7d --max-events 500 \
  --status Succeeded \
  --query "sort_by(@, &eventTimestamp)[].{time:eventTimestamp, caller:caller, op:operationName.value, resource:resourceId}" \
  --output table

Claude Codeに整形を任せる場合も、この型を手元で一度試しておくと、Claudeが組み立てたコマンドの妥当性を見抜けます。出力が崩れたときは、--select に指定した列と --query の参照先が食い違っていないかを最初に疑います。

人物ではなくサービスプリンシパルが操作しているケースでは、callerにアプリケーションのIDが入ります。activity logのcallerだけでは、そのIDを管理している人には結びつきません。

90日の壁をLog Analyticsで越える

Azureはactivity logのイベントを90日間保持し、その後に削除します。90日以内なら無料で、イベント量による課金もありません。このため、--offset 120d のように長い期間を指定しても、90日より前のイベントは返ってきません。開始と終了の両方が90日の範囲に収まっている必要があります。

見落としやすいのは、リソースの作成者という情報です。作成者はactivity logにしか保存されません。90日を過ぎると、「このリソースを誰が作ったのか」が調べられなくなります。長く残したいときは、診断設定でactivity logをLog Analyticsワークスペースなどへ送ります。

  • 送信先は、Log Analyticsワークスペース、Azure Event Hubs、Azure Storageのアカウントから選びます
  • アクティビティログ自体にはデータ取り込み料金がかかりません。課金は、既定の90日を超えて保持する期間に対してだけです
  • 保持期間は最大12年まで延ばせます
  • 旧方式のログプロファイルを使っている場合は、診断設定を作る際に旧設定を無効にします

Log Analyticsに入ったデータは AzureActivity テーブルに格納されます。次のようなKQLで、Administrativeカテゴリのレコードを取り出せます。

AzureActivity
| where CategoryValue == "Administrative"

フィールドの大文字小文字が、同じ値なのに揃っていない場合があります。文字列比較には =~ のような大文字小文字を区別しない演算子か、tolower() を使ってください。

ワークスペースに送る構成にしておけば、Claude Codeに渡す入り口が2つになります。直近の調査は az monitor activity-log list、90日より前の調査はワークスペース側のKQLクエリです。後者をClaudeに任せるなら、実行手段に応じた許可ルールを別に用意します。Azureの操作そのものをClaudeから扱う構成は、Azure MCPサーバーの記事にまとめています。

つまずきやすい点

件数が50で止まっている。 --max-events の既定は50です。期間を広げたのに表が短いときは、まずこの値を疑います。

操作したはずの人が出てこない。読み取りは通常記録されません。また、データプレーンの操作(Key Vaultからシークレットを取る、DBへ問い合わせる)はactivity logの対象外です。これらを追うにはリソースログを診断設定で集めておく必要があります。

同じ操作が複数行に出る。Write、Delete、Actionは開始と結果が別々のイベントになります。--status Succeeded で絞るか、correlationIdで束ねます。

時刻が思っていた範囲とずれる。開始と終了の両方を指定すると --offset は無視されます。範囲の指定方法は、どちらか一方に揃えてください。

Claudeが長大な出力を抱え込む。取得件数が多いときは、--select で列を減らします。出力全体をClaudeの会話に流し込むより、手元でファイルに保存し、そのファイルを読ませる方が確実です。

az monitor activity-log list -g my-rg --offset 30d --max-events 2000 \
  --select eventTimestamp caller operationName status resourceId \
  > activity-30d.json

ファイルに落としたあと、Claudeには「activity-30d.json を読み、callerごとの操作回数を上位から並べて」と頼みます。生のログを繰り返し取得せずに済み、同じデータから別の切り口を試せます。

変更前後のコードと照らす

activity logは「何が変わったか」までは教えてくれますが、「なぜ変えたか」はわかりません。Bicepなどのコードで管理している環境なら、リポジトリ側の履歴と突き合わせると経緯が追えます。デプロイ前の差分確認はBicepとwhat-ifの記事で、コード側の経緯の調べ方はgit履歴から経緯を調べる記事で扱っています。

突き合わせる軸は、時刻、リソースID、そして操作した人です。コードのコミット時刻の少し後に同じリソースIDの書き込みがあれば、デプロイ経由の変更と見なせます。コミットの痕跡が無いのに書き込みがあれば、ポータルや手作業の変更を疑う手がかりになります。

まとめ

変更履歴の追跡は、--resource-group と --offset で範囲を決め、--select で列を絞り、--max-events で打ち切りを避ける、という順で組み立てると崩れません。Claude Codeには読み取りコマンドだけを許可し、表の整形と相関IDでの束ね直しを任せます。

残るのは90日の期限です。作成者を後から知りたい環境では、Claudeを使う前に診断設定でLog Analyticsへ送る構成を整えておくことが、いちばん効く下準備になります。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. learn.microsoft.com/en-us/cli/azure/monitor/activity-log
  2. learn.microsoft.com/en-us/azure/azure-monitor/platform/activity-log
  3. learn.microsoft.com/en-us/azure/azure-monitor/platform/activity-log-schema
  4. code.claude.com/docs/en/permissions
  5. code.claude.com/docs/en/common-workflows
この記事を共有:XはてブLinkedIn