1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Microsoft Azure】特定操作を除いたリソース変更検知アラートの作成方法

1
Last updated at Posted at 2025-12-25

はじめに

クラウド環境においてリソース設定の変更検知はセキュリティや運用管理の観点から重要です。Microsoft Azure(以下、Azure)でも提供されている機能だけで比較的簡単にアラート通知が可能です。

しかし、ただ変更を検知するアラートを設定してしまうとプログラムによる運用操作など、意図した操作まで検知されてしまい、アラートの確認に無駄な労力がかかってしまいます。

そこで、本記事ではAzure環境おいて、特定操作を除外した変更検知アラートを作成する方法について解説します。

前提

本記事では、特定のリソース変更操作が定期的に行われるような環境を想定し、この操作を除外する変更検知機能について解説します。具体的には、 Azure Resource Graph(ARG)アクティビティログ を使用してこれを実現します。

実際のアラート作成には以下の作業も必要ですが、これらについては本記事で説明しません。必要に応じて他の情報を参照ください。

  • アクティビティログをLog Analytics ワークスペースに取り込む方法
  • カスタムログ検索を使用したアラートルールの作成方法

また、実運用ではサードパーティーの監視ツール等を利用して要件にあった監視を構築することも想定されます。とはいえ、まずはAzure提供の機能だけでできる事を把握する事も意味があると思いますので、以下調べた内容を共有します。

クエリの概要

まず、本記事で作成するクエリの概要は以下の通りです。

  • リソース変更履歴は Azure Resource Graph(ARG) の情報を使用
    • ARGの resourcechanges テーブルに含まれるリソース変更ログを検知対象とする
  • 特定操作の判断には、操作元のプリンシパル名やIPアドレス、オペレーション名等の情報を使用
    • ARGの resourcechanges テーブルには操作元の情報が含まれていない
    • アクティビティログAzureActivityテーブル)には操作元の情報が含まれているため、resourcechangesAzureActivityを結合して除外対象の操作か判断する
  • ARG とアクティビティログでログの取り込みに時間差があるため、これを考慮してクエリ範囲を調整
    • ARGのログが取り込まれ、アクティビティログが取り込まれていない時間範囲は除外処理がうまく動作しない
    • ログ取り込みに遅延があることを考慮してログ検索期間を調整する

以下、具体的なクエリを併せて上記内容を説明します。

リソース変更履歴のクエリ例

まず、ARGのリソース変更履歴は以下クエリで確認できます。

arg("").resourcechanges

Azure Resource Graph エクスプローラー を使う場合はresourcechangesのみでクエリ可能ですが、Log Analytics ワークスペース内のログに対するクエリでは arg("") が必要です。

ARGに対してクエリを実行する場合、アラートルール側で対象リソースの閲覧者ロールが必要です。
アラートの作成時は必ずマネージドIDを選択し、クエリ対象のスコープ(多くの場合はサブスクリプション)に対する「閲覧者」権限の付与を忘れずに実施してください。

リソース変更履歴にアクティビティログを突合するクエリ例

前述の通り、ARGのresourcechangesテーブルだけだと操作元の情報が含まれていません。そこで、操作元の情報を含んでいるAzureActivityテーブルも併せて確認し、除外する操作かを判定します。

以下、これらのテーブルを結合して特定の操作を除外するクエリの例です。

arg("").resourcechanges
| extend CorrelationId = tostring(properties["changeAttributes"]["correlationId"]) // AzureActivity との結合用
| join kind=leftouter (
    AzureActivity
    | where CategoryValue =~ "Administrative" // 必要ないレコードを除外
    | where ActivityStatusValue =~ "Start" // 一度の操作 でStart,Success 等複数のログが出るため、対象を絞る
    )
    on CorrelationId // CorrelationIdをキーに、resourcechangesテーブルとAzureActivityテーブルを結合
| where not(Caller == "<CallerID>" and CallerIpAddress == "<CallerIpAddress>" and OperationNameValue == "<OperationName>" ) // IDやIPアドレス、操作名等で除外する
// 以下、除外操作の分だけ追記
| order by TimeGenerated

クエリの解説

  • 前半部分でresourcechangesテーブルから必要な情報を抽出
  • 目的が変更検知のため、resourcechangesテーブルが全て含まれるようにleftouter joinで結合
  • 結合の際、AzureActivity側は不要なレコードを除外
  • 結合後、CallerCallerIpAddressOperationNameValue 等のカラムを使用して許可された対象、操作であれば除外
    • IPアドレスを指定するかなどは環境によって変化するため、使用する情報は各々で取捨選択する

基本的には上記のクエリで特定操作の除外は動作しますが、前述の通りこれだけでは除外がうまく動かない場合があります。

というのも、Azureの仕様上ログの取り込みには必ず遅延が発生するためです。上記のクエリでは、resourcechangesテーブルよりAzureActivityテーブルのログ取り込みが遅れた場合、必要な情報が結合されないためアラート発報されてしまいます。

そこで、ログの取り込み遅延も考慮してクエリを修正する必要があります。

ログ取り込みの遅延を考慮したクエリ例

ドキュメントによるとログの取り込みにかかる時間は "20秒から3分"のようです。

実際にどの程度取り込み遅延が発生しているかは以下のクエリで確認できます。自分の環境で確認すると9分を超えるレコードもありました。

AzureActivity
| where CategoryValue =~ "Administrative"
| where ActivityStatusValue =~ "Start"
| extend E2EIngestionLatency = ingestion_time() - TimeGenerated
| project CorrelationId, TimeGenerated, ingestion_time(), E2EIngestionLatency

そこで、ログ検索の範囲を一定期間遅延させ、取り込みが完了したであろう範囲だけを対象とするクエリに修正します。

以下の例は、アラートルールの評価頻度が1時間の場合に、検索範囲を10分遅延させる場合のクエリ例です。
1時間の検索範囲を10分間だけ前にスライドし、10分前から70分前の範囲を指定しています。

arg("").resourcechanges
| extend Timestamp = todatetime(properties["changeAttributes"]["timestamp"])
| where ago(70m) <= Timestamp and Timestamp < ago(10m)  // 検索範囲は1時間で10分の遅延
| extend CorrelationId = tostring(properties["changeAttributes"]["correlationId"]) // AzureActivity との結合用
| join kind=leftouter (
    AzureActivity
    | where ago(70m) <= TimeGenerated and TimeGenerated < ago(10m)  // ARGと同じ範囲
    | where CategoryValue =~ "Administrative" // 必要ないレコードを除外
    | where ActivityStatusValue =~ "Start" // 一度の操作 でStart,Success 等複数のログが出るため、対象を絞る
    )
    on CorrelationId // resourcechanges テーブルと AzureActivityで CorrelationId が一致するものを結合する
| where not(Caller == "<CallerID>" and CallerIpAddress == "<CallerIpAddress>" and OperationNameValue == "<OperationName>" ) // IDやIPアドレス、操作名等で除外する
// 以下、除外対象の数だけ記載
| order by TimeGenerated

当然ながら、遅延させる時間が大きければ除外漏れは少なくなる代わりに、事象の発生からアラート発報までの時間が遅延する可能性も上がります。誤検知と検知遅延の天秤を許容できる範囲で調整しましょう。

以上で目的としていたアラート用クエリは完成です。

とはいえ、実運用では除外対象の操作がすべて事前に判明している事は稀だと思います。
現実的には、事前に把握できる操作は除外しつつ、運用中に検出されたアラートに対して除外対象とするか継続的に検討していく事になると思います。

おわりに

本記事では、resourcechangesテーブルとAzureActivityテーブルを使用することで、特定操作を除いた変更検知機能を実現する方法について解説しました。変更検知の機能は実際の運用まで見据えた場合、かなり検討すべきことが多い要件かと思いますが、本記事がそういった困りごとを持っている皆様の一助になれば幸いです。

また、各項目で説明した通り実際に適用するにあたってはいくつかの注意点がありますので、各環境・要件に合わせてカスタマイズするようにお願いします。運用環境に合わせて除外対象や時間のバランスを取りながら、効果的に機能を実現しましょう。


  • Microsoft Azure は,Microsoft Corporation の商標または登録商標です
  • その他、記載されている会社名および商品・製品・サービス名は、各社の商標または登録商標です
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?