Log Analytics/Sentinel ワークスペースからのログのエクスポートを PowerShell + Container Apps ジョブでバッチ処理化

# 本記事について

本記事では、**PowerShell を用いて、Log Analytics ワークスペース (Sentinel ワークスペース含む) から CSV 形式でログをエクスポート**する方法について見ていきます。

特に、[**Azure Container Apps ジョブ**](https://learn.microsoft.com/ja-jp/azure/container-apps/jobs?tabs=azure-cli) を用いて、**日時実行するバッチジョブとしてログのエクスポートを行う方法**をご紹介します。Azure Container Apps では Azure Files のファイル共有をマウントできるため、**Container Apps ジョブ上で CSV ファイルを作成し、それを Azure Files に格納する**という流れで考えます。

# 全体のアーキテクチャについて

アーキテクチャの全体像は下記になります。Container Apps ジョブで PowerShell スクリプトを実行して、Log Analytics ワークスペースに対してクエリを実行し、その結果を CSV ファイルにまとめます。そして、その CSV ファイルをマウントしているファイル共有内のフォルダーに格納します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/9cfdeef6-8c2f-a398-96f7-1530390fc00d.png)

# 構成要素のポイント

上記のアーキテクチャでポイントになるところを確認します。

## PowerShell を使った Log Analytics からのエクスポート

下記のマイクロソフトのサポートチームからのブログ記事にもあるように、Log Analytics に対して、PowerShell の `Invoke-AzOperationalInsightsQuery` のコマンドレットでクエリを外部からかけることができます。そして、その結果を `ConvertTo-Csv ` のコマンドレットを使った一行のコードで CSV に変換して、保存することができます。

https://jpazmon-integ.github.io/blog/LogAnalytics/QueryByPowerShell/

## Azure Container Apps ジョブ

この PowerShell のスクリプトを定時実行できるプラットフォームとしては、Azure 上に多くのサービスがあります。例えば、Azure Functions, Azure Automation, Azure Container Instances などが挙げられます。

今回この記事では、2023年に新たに登場した [**Azure Container Apps ジョブ**](https://learn.microsoft.com/ja-jp/azure/container-apps/jobs?tabs=azure-cli) を活用したいと思います。このサービスでは、コンテナー化されたバッチジョブを、サーバーレスのコンテナー実行基盤にて容易に展開できます。

特に、**cron を用いた実行スケジュールの設定**、**複数のコンテナーの並列実行の管理**、**Azure Files のマウント**、**Azure Monitor との監視の連携**などが利用でき、コンテナー化されたジョブであれば、上述の Azure サービス以上に使いやすくなっています。

# サンプルの実装

簡単にポイントを抜粋しながらご紹介します。

## Azure リソース

Log Analytics ワークスペース、Container Apps ジョブと Container Apps 環境、ストレージアカウントをそれぞれ準備します。

Container Apps 環境でファイル共有の設定を行い、各 Container Apps ジョブのコンテナーでボリュームマウントを構成します。

**Container Apps 環境におけるファイル共有の設定例**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/306a545c-279f-8746-445b-b1a920197cdd.png)

**Container Apps ジョブ上のコンテナーにおけるボリュームマウントの設定例**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/89b4799a-54d5-aade-9801-c8251cd2cc17.png)

これで、各ジョブからボリュームが見えるようになり、今回は PowerShell からファイルを格納できるようになります。

なお、Cron の設定は、Container Apps ジョブの Configuration から行えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/d5a01fdf-7bd8-6fbb-cdee-a49eef01209a.png)

## PowerShell スクリプトと Dockerfile

下記が簡単な PowerShell スクリプト例になります。クエリやファイル名などは適宜ご変更ください。(**特にクエリについては、[上記記事](https://jpazmon-integ.github.io/blog/LogAnalytics/QueryByPowerShell/)でも解説されている通り、コマンドレットで取れる最大データ量に制限があるため、それを超えそうな検索を実行する場合はクエリを分割するなどの対策が必要になります。**)

```Powershell:Container Apps ジョブ上で実行するコードのサンプル

# Azure へ接続
Clear-AzContext -Force
Connect-AzAccount -Identity #マネージドID以外を利用する場合は適宜ご変更ください

# ワークスペースの設定
$WorkspaceId = "<Log AnalyticsのワークスペースID>"

# ログの取得範囲の設定
$endData = (get-date).ToUniversalTime().AddDays(-1).ToString("yyyy-MM-dd") + " 00:00:00"
$startData = (get-date).ToUniversalTime().AddDays(-2).ToString("yyyy-MM-dd") + " 00:00:00"

# クエリの設定
$query = "StorageFileLogs 
| where TimeGenerated between (datetime($startData) .. datetime($endData))
| where Protocol == 'SMB'
| where ObjectKey !contains 'file.core.windows.net\\IPC$\\'
| sort by TimeGenerated desc 
| project TimeGenerated, AccountName, Location, Protocol, OperationName, AuthenticationType, Uri, ObjectKey, SmbPrimarySID, Category, SmbCommandMinor, MetricResponseType, Type, _ResourceId"

# クエリの実行
$result = Invoke-AzOperationalInsightsQuery -WorkspaceId  $workspaceId -Query $query

# ファイル名の設定
$fileName = (get-date).ToUniversalTime().ToString("yyyy-MM-dd") + ".csv"
$filePath = "/mnt/CSV/" + $fileName

# 結果の出力
$result.Results | ConvertTo-Csv > $filePath

```

この例の最後では、マウントしているファイル共有内の CSV というフォルダーにログが吐かれるようにしています。

この PowerShell スクリプトを Docker コンテナーのイメージに格納し、Docker 起動時に実行されるようにします。下記は、ローカルの ./scripts 配下にある log-export.ps1 をコンテナー上で実行する際の Dockerfile の例です。

```Dockerfile
FROM mcr.microsoft.com/azure-powershell

COPY ./scripts /scripts

WORKDIR /scripts

ENTRYPOINT [ "pwsh", "./log-export.ps1" ]
```

これで作成された Docker イメージを Azure Container Registry にプッシュし、そのイメージを Container Apps ジョブで実行すれば、今回やりたかったことが実現できます。

# 実行例

Container Apps ジョブ上にコンテナーを配置し、実行してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/f7f16372-edfd-091f-6d69-080ba3e0a59b.png)

指定したファイル名で、クエリの結果が CSV としてストレージアカウント内のファイル共有に格納されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/458d49cd-fdcd-3c91-b2f2-a467219fc1d5.png)


# 最後に

＊本稿は、個人の見解に基づいた内容であり、所属する会社の公式見解ではありません。また、いかなる保証を与えるものでもありません。正式な情報は、各製品の販売元にご確認ください。