EVTX ファイルから Microsoft Sentinel の SecurityEvent テーブルにイベントログを取り込んでみる
はじめに
本記事ではサーバーやクライアント PC のイベントログを保存した evtx ファイルから、Microsoft Sentinel の標準ビルドインの SecurityEvent テーブルにログを入れることを Azure Functions を使って実装してみます。
ただし、このようなやり方は推奨されず、あくまで機能上の動作についての実験・確認結果を示す意図での記事になります。本番環境や各組織で参照・利用する場合は自己責任にてお願いいたします。
よいこの皆様は正規のやり方の Azure Monitor Agent を使って、イベントログの収集をしましょう。
Github レポジトリ
以下に今回実装したソースコードを公開しています。コードも Readme もほとんど(98%くらい) Github Copilot に書いてもらっています。上記にも書いておりますが、参照・利用する際は利用者の方の責任の下利用していただくようお願いいたします。
実装について
1.アーキテクチャ
今回は Azure Function の Blob トリガーを使って、保存された evtx ファイルを Log Ingestion API 経由で、SecurityEvent テーブルに入れることにしました。(以下のイメージ)
[Blob Storage] → [Azure Functions] → [Log Analytics Workspace]
↓ ↓ ↓
.evtx files Processing SecurityEvent Table
- Parse EVTX
- Convert to JSON
- Batch send
2.SecurityEvent テーブルへのログ インジェスト
今回 Log Ingestion API 経由で、SecurityEvent テーブルにログを取り込めるかを確認しました。Log Ingestion API でのログ取り込みは基本的にカスタム テーブルへの取り込みと考える方が多いと思いますが、実は Built-in のテーブルについてもいくつかサポートされているテーブルが存在しています。サポートされるテーブルについて公開情報を参照ください。
公開情報のページに SecurityEvent テーブルは含まれており、Log Ingestion API でログを取り込むことが可能であるはずです。
Data Collection Rule (DCR) について
Log Ingestion API でデータ取り込みをするために重要な要素が Data Collection Rule(DCR) です。DCR は JSON 形式で Log Analytics Workspace へのデータ取り込み時の、取り込み元から送付されるデータスキーマや、どのテーブルに送るか、その過程でどのような変換をするかといったことを定義する Azure Monitor に関連したリソースの一つになります。
具体的などのような構造になっているかは公式のリファレンスを参照ください。
DCR の要素がどのようにデータフローに関連するかは公式のリファレンスにある以下のイメージがわかりやすいかと思います。

Azure Monitor Agent を利用した正規の取り込みでは、"Input Stream" 上段の "Known data" -> "dataSources" という流れで、Log Analytics Workspaces の決まったテーブルにログが取り込まれます。ただ、この絵で分かる通り、それ以外の "Custom data" も "streamDeclarations" を経由して、DCR がサポートしているテーブルについて等しく出力できると読み取れます。これはイメージ通りで、SecurityEvent テーブルのスキーマと同等のデータ取り込み用のスキーマを "streamDeclarations" で正しく定義できれば、標準のSecurityEvent テーブルにログを入れることが可能であることを確認できました。
具体的な DCR の定義については Github で公開している DCR 構造になっている json ファイルをご参照ください。
DCR の制約(未解決)
上記の通り、SecurityEvent テーブルのスキーマ通りに、DCR の streamDeclarations のプロパティを設定し、outputStream も公開情報からに「これが Windows イベントなどの標準のデータ型の場合、ストリームは Microsoft-<TableName> という形式になります。」との記載があることから "Microsoft-SecurityEvent" とすればよさそうです。(通常の AMA でのログ取り込みの際の DCR の内容も見て、Stream 名が"Microsoft-SecurityEvent" であること念のため確認してます。)
SecurityEvent テーブルのスキーマについてはリファレンスで確認できます。数は多いですが、この通り DCR の streamDeclarations を定義すれば SecurityEvent テーブルに Log Ingestion API 経由でデータを入れることができるはずですが、ここで落とし穴が出てきます。
"SourceComputerId"、"LogonGuid"、"TargetLogonGuid"がテーブルのスキーマ情報を見ると string 型なのに対して、String で streamDeclarations を定義しても、output steream として、guid 型となっているため、型が不一致となり、DCR のデプロイに失敗します。

DCR の仕様のページを見ても、データ型に guid 型は指定できません。ここはどうしても解決できずに、"SourceComputerId"と"LogonGuid"、"TargetLogonGuid"の3つのフィールドについてはデータ取り込みができませんでした。
3.evtx ファイルから JSON にする
extx ファイルはバイナリ形式になります。一方、Microsoft Sentinel にログを入れるためには、Log Ingest API を使っていれる必要があり、ログデータは JSON 形式にして API に POST する必要があります。今回はネット上で情報が多そうな python のパッケージ ライブラリを使って、extx ファイルから JSON に変換することにしました。ここは Github Copilot にお任せしてサクッと変換できました。
結果
Azure Functions にデプロイし、Blob Trigger を構成したコンテナーに extx ファイルを保存すると以下の通り Azure Functions が動き、Sentinel にローカル ファイルから作成した evtx ファイルのイベント ログが SecurityEvent テーブルに保存されることを確認できました。


余談
私は Azure Functions は専門領域外なためこの関数アプリを作成するにあたりに多くの、躓きにあいました。その中でも、現在新規の Azure Functions リソースを作成しようとするときにデフォルトで設定される Flex 従量課金プランは従来のポーリング ベースでの Blob Storage トリガーでは動かなくなっており、Event Grid ベースで構成が必要となるというのに気づくのにかなり時間がかかってしまいました。同じ躓きをしてしまう方がいるかもなので、ここに念のため記しておきます。
Discussion