Azure Blob ストレージに対して Microsoft Defender for Storage アンチマルウェアスキャンを行って自動化を行う

# 1. はじめに
[2023.6.25] Private Endpoint 経由の Blob Storage 対する AntiMalware Scanning がサポートされました!!
[2023.9.1] GA になりました!!

https://learn.microsoft.com/en-us/azure/defender-for-cloud/release-notes#private-endpoint-support-for-malware-scanning-in-defender-for-storage

Azure Storage に対するマルウェアスキャン検知の機能が 2023.3.28 の [Microsoft Secure](https://secure.microsoft.com/en-US/home) にて発表されました！
Microsoft Defender for Storage でも[ハッシュ評価分析](https://learn.microsoft.com/ja-jp/azure/defender-for-cloud/defender-for-storage-classic#limitations-of-hash-reputation-analysis)で同様な機能を提供していましたが、実ファイルをスキャンしているものでは無い点や、スキャン結果に遅延があり大きな課題になっていました。以下公式 [Doc](https://learn.microsoft.com/ja-jp/azure/defender-for-cloud/defender-for-storage-classic#limitations-of-hash-reputation-analysis) からの抜粋です。

>アップロードした BLOB のマルウェアを準リアルタイムでスキャンする場合は、新しい Defender for Storage プランにアップグレードすることをお勧めします。 マルウェア スキャンの詳細について確認してください。

今回 Azure Storage Blob データに対して Microsoft Defender Antivirus (MDAV) ベースでのファイルスキャンが SaaS 型で提供され、ニアリアルタイムでの検知・通報まで動作するようになっています。
本記事では、プレビュー発表された内容について触れたいと思います。

# 2. イメージ & 価格
新たな Microsoft Defender for Storage によるマルウェアスキャンは以下のようなイメージになります。
![image.png](https://learn.microsoft.com/ja-jp/azure/defender-for-cloud/media/defender-for-storage-malware-scan/malware-scanning.png)
機能は分かりやすく、blob に格納されたデータに対して動的にマルウェアスキャンが稼働し、スキャン結果をタグ付けで返す、といったものです。イベント駆動 (Event Grid) を用いてニアリアルタイムによる自動化 (automation) も設定することが出来るようになっています。

現在、Microsoft Defender for Storage の価格は以下のようになっています。
- Defender for Storage 通常機能 ``$10/Month/ストレージアカウント``　※時間単位で計算される
- Defender for Storage マルウェアスキャン ``$0.15/GB`` 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/b98b22d3-6d5b-15f0-5491-cfd7ad9c7286.png)

ストレージアカウント単位で約 1,200 円、マルウェアスキャンを用いると 1TB で約 18,000 円といった計算になります。
マルウェアスキャンについては、コンテナ単位での有効化は出来ないため、ストレージアカウントを分けるなどの工夫が必要かもしれません。

# 3. 制限事項 - 2023.7.7 現在
今回初リリース、プレビュー段階といったこともあり、幾つかの制約事項があります。

- Azure blob ストレージのみ対応。**Azure Files 未対応。**
- スキャンサイズは 2GB まで。ZIP ファイル対応（パスワード ZIP は不可）
- お客様ファイルの暗号化 (Customer Side CMK) は不可
- 旧式の Azure Storage v1 はサポート外
- スキャンレートは 2GB/分 が目安
- Azure Data Lake Storage Gen2 で用いる階層型ネームスペースは未対応
- 追加 / ページ BLOB 未対応

https://learn.microsoft.com/ja-jp/azure/defender-for-cloud/defender-for-storage-malware-scan#limitations

# 4. やってみる - Antimalware Scanning!
公式 Docs にも Malware Scanning のテスト方法が記載されていますので、併せてご確認下さい。

https://learn.microsoft.com/ja-jp/azure/defender-for-cloud/defender-for-storage-test

## 4.1 Defender for Storage を有効化する
はじめに Microsoft Defender for Cloud 側で Defender for Storage を有効化します。
新プランへの移行が促されている場合は、新プランへの変更を本画面で実施する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/7573b4f3-eecd-2478-a540-d59b2c3e3fe3.png)

## 4.2 ストレージアカウントでアンチマルウェアスキャンを有効化する
アンチマルウェアスキャンの有効化は、各 Azure Storage アカウント単位で実施する必要があります。リソース側 Azure Storge の Microsoft Defender for Storage 設定から、以下を有効化します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/bbc72727-815d-d1b4-113d-b9015a94c492.png)

|  項目  |  設定  | 意味 |
| ---- | ---- | ---- |
|  Microsoft Defender for Storage | オン | 本設定で有効化。ここをオフにすると、リソース単位で Microsoft Defender for Storage を無効化出来ます。|
| Sensitive data threat detection(preview) | オン/オフ | 今回新たに機能追加された機能。PIIに相当する情報を検知して通知することが出来ます。|
| On-upload malware scanniing(preview)| オン | MDAV (Microsoft Defender Antivirus)によるマルウェアスキャン機能を有効化します。|
| Set limit of GB scanned per month | - | 月のスキャン上限値を設定することが出来ます。課金対策に用いることが出来ます。|
| Send scan results to Log Analytics | (ターゲットの LAW) | スキャン結果をログとして Log Analytics に記録するオプション。Microsoft Defender for Cloud のアラートでも脅威検知アラートが検知するため、監査用途に。|
| Send scan results to Event-Grid topic | (ターゲットの Event-grid)| ニアリアルタイムでマルウェア検知時にイベント駆動するためのオプション。|

## 4.3 マルウェア検体テスト - EICAR の例
マルウェアファイルのアップロードとしては [EICAR](https://www.eicar.org/) のサンプルを用いることが出来ます。私の場合は、Azure CLI で eicar 検体ファイルをシェルスクリプトで実施しています。

```bash
#!/bin/bash
az storage blob upload --file eicar.txt --name example2.txt --account-name [ストレージアカウント名] --container-name [blob コンテナ名] --account-key [アカウントキー] --overwrite
```
マルウェア検体ファイルをアップロードすると、Antimalware Scanning を有効にしたアカウントではBlob のファイルに ``Malware Scanning scan result`` タグが付与されることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/58477f3a-2399-d4f7-2460-1b3a8ddfb40f.png)

大量のファイルが blob に上がっており、対象のタグを調べたい場合は azure-cli で抽出して、jq などでフィルターすると良いのではと思います。
```
[root@vmLinux002 ~]# az storage blob list --container-name test --account-name storagedefender004lrs --include t
[
  {
    "container": "test",
～省略～
    "tagCount": 2,
    "tags": {
      "Malware Scanning scan result": "No threats found",
      "Malware Scanning scan time UTC": "2023-04-02 22:50:03Z"
    },
    "versionId": null
```
jq を用いたフィルター例も挙げておきます。

- Blob ファイルの名前とスキャン結果のリスト抽出例

```bash
[root@vmLinux002 ~]# az storage blob list --container-name test --account-name storagedefender004lrs --include t | jq -r '.[] | { name: .name, tag: .tags }'
{
  "name": "eicar.com",
  "tag": {
    "Malware Scanning scan result": "Malicious",
    "Malware Scanning scan time UTC": "2023-03-29 05:36:28Z"
  }
}
{
  "name": "eicar.com.txt",
  "tag": {
    "Malware Scanning scan result": "Malicious",
    "Malware Scanning scan time UTC": "2023-03-29 05:36:27Z"
  }
}
{
  "name": "example1.txt",
  "tag": {
    "Malware Scanning scan result": "No threats found",
    "Malware Scanning scan time UTC": "2023-03-29 07:58:08Z"
  }
}
```

- Blob ファイルの名前とスキャン結果が ``Malicious`` の場合の抽出例

```bash
[root@vmLinux002 ~]# az storage blob list --container-name test --account-name storagedefender004lrs --include t | jq -r '.[] | { name: .name, tag: .tags } | select(.tag."Malware Scanning scan result" == "Malicious")'
{
  "name": "eicar.com",
  "tag": {
    "Malware Scanning scan result": "Malicious",
    "Malware Scanning scan time UTC": "2023-03-29 05:36:28Z"
  }
}
{
  "name": "eicar.com.txt",
  "tag": {
    "Malware Scanning scan result": "Malicious",
    "Malware Scanning scan time UTC": "2023-03-29 05:36:27Z"
  }
}
```

## 4.4 Defender アラートの例
Defender for Storage では、マルウェアスキャン判定の際にアラートとして Microsoft Defender for Cloud のセキュリティ警告に通知します。メール通知などと組み合わせて確認を行うことをお勧めします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/31b3d9cf-69cb-7185-6a72-1a23948aab4c.png)

## 4.5 Log Analytics ワークスペースへの監査ログ
Override 設定で Log Analytics ワークスペースを設定すると ```StorageMalwareScanningResults``` テーブルが作成されて、ログが残るようになります。証跡監査用途に用いると良さそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/5e61eb33-2b60-1499-5fbb-444ad6c4ca1d.png)

# 5. ニアリアルタイムで自動削除を行ってみる
マルウェアスキャンの結果から、マルウェア感染したファイルを blob に残すのではなく、自動削除や別の Storage に隔離するようなニーズが考えられます。本機能ではほぼリアルタイム（ニアリアルタイム）で駆動する Event-Grid トピックと連携して Azure Functions やロジックアプリを起動することが出来るようになっています。
今回、以下のような構成を取ってみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/b8b913c7-0f14-bed4-f456-8a3b707f3f5d.png)
設定手法を以下ご紹介します。
## 5.1 Event Grid 側でトピックを作成する
はじめに Defender for Storage malware scanning から受け取るための Event Grid Topic を作成します。Defender for Storage 設定と同一のリソースグループで管理することをお勧めします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/e9447217-e3e9-553a-7755-aa032bd920ae.png)

## 5.2 Defender for Storage 設定より、Event-Grid Topic のターゲットを設定する
Antimalware Scanning 稼働時に送る Event Grid のトピック先を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/3bba22b5-6f42-2464-0a47-d0aa73da18ad.png)

なお、Event-grid のトピック設定側で**高度なフィルター**を設定して、Defender for Storage が Malicious 判定したイベントだけに絞り込む設定が出来ます。スキャン時の情報は[公式 Docs](https://learn.microsoft.com/en-us/azure/event-grid/subscription-creation-schema?WT.mc_id=Portal-Microsoft_Azure_EventGrid#filter-object) に掲載されていますので、``Malicious`` のイベント時にロジックアプリが駆動する設定を入れるのが良いと思います。

``data.scanResultType`` に ``Malicious`` が入る設定例です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/dda9746d-a215-ba55-ac14-cb904873cf65.png)

https://learn.microsoft.com/en-us/azure/event-grid/subscription-creation-schema?WT.mc_id=Portal-Microsoft_Azure_EventGrid#filter-object

## 5.3 ロジックアプリを作成する
Event-grid のトピックから起動し、ターゲットの Azure blob Storage の blob ファイルを削除するロジックアプリを作成します。ステップはそれほど複雑ではなく、コツを掴めば簡単なので、ご興味ある方は以下参考例をご確認頂いてチャレンジしてみて下さい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/e3be20cd-f75b-fe15-cf26-c897a0d238d8.png)
### 5.3.1 Event-grid のトピック（リソースイベント）を拾う
パラメータにサブスクリプションと、事前に設定した Event-grid のトピックを選択しています。
これでマルウェアスキャン検知時に Event-grid よりロジックアプリが起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/06a57f59-4bbd-72b5-e318-cd9fe498ae09.png)
### 5.3.2 Malware 判定条件の設定
Event-grid に流入するイベントが Defender for Storage によるマルウェア判定かどうかを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/1583f923-2613-fe40-1e69-bb14c8dc576e.png)
条件として、[contains 関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#contains)を用いて、event-grid の JSON フィールドより、``['data'][scanResult']`` の値が ``Malicious`` であった場合に **true** 判定を返す設定を入れています。以下内容を式に設定して下さい。
```
contains(triggerBody()?['data']['scanResultType'],'Malicious')
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/855f33aa-18ed-1493-43da-086e4631c874.png)
### 5.3.3 Event-grid から流れるマルウェアスキャン情報を正規化で分解する
条件判定でマルウェアだった場合、トピックから拾うデータを JSON で正規化して、後続の Blob アクションに使えるように正規化します。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/0beac2ed-22a0-45e5-dab3-0c9e9ebe8812.png)
マルウェア検知時の結果を流してサンプルペイロードから生成することが出来るようになっています。
```json
{
    "properties": {
        "blobUri": {
            "type": "string"
        },
        "correlationId": {
            "type": "string"
        },
        "eTag": {
            "type": "string"
        },
        "scanFinishedTimeUtc": {
            "type": "string"
        },
        "scanResultDetails": {
            "properties": {
                "malwareNamesFound": {
                    "items": {
                        "type": "string"
                    },
                    "type": "array"
                },
                "sha256": {
                    "type": "string"
                }
            },
            "type": "object"
        },
        "scanResultType": {
            "type": "string"
        }
    },
    "type": "object"
}
```
### 5.3.4 BLOB を削除する
ロジックアプリの BLOB コネクタを用いてターゲットのBLOBを削除します。
注意点として「BLOB を削除する (v2)」コネクタの設定では、対象の BLOB は以下のようなコンテナ以下の URI を指定して上げる必要があります。
- ```/aaa/bbb.txt```
- ```/bbb.csv```

前のステップで正規化されたデータでは、以下のような ``bloburi`` が取れるのですが、``/test/example2.txt`` だけを抽出するため、

```
"blobUri": "https://storagedefender004lrs.blob.core.windows.net/test/example2.txt"
```
以下のように [uriPath 関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#uriPath)を用いて抽出する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/94d05262-9dab-6bf8-2fd2-bcc07d168b95.png)
設定したイメージは以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/e4a3bbca-5516-22e5-357c-86a926ff8132.png)
なお、Azure Storage の Blob コネクタの認証方法としては、ストレージアクセスキーを用いるか、AAD 認証を通すか、マネージド ID を用いて 5.3.5 で紹介する「ストレージ BLOB データ共同作成者」のロールを付与する方法の 3 通りが有ります。
マネージド ID 場合は、接続する ID は後続で作成するマネージド ID を設定して下さい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/0b48f5fb-ebf1-fff6-ae91-5a274acaff98.png)
### 5.3.5 [おまけ] メール通知をしておく
削除したことを通知するため、今回は O365 のコネクタを用いてメール通知を入れてみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/eca5a3ab-1e36-39a7-1f40-21fbf3fe0e33.png)
### 5.3.6 ロジックアプリにマネージド ID を用いて blob データの削除権限を持たせる
最後に作成したロジックアプリに対して、Azure blob データの読み取り・削除権限を持たせます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/2687e2a6-9931-a2fa-ea7a-80773c2df648.png)
今回は「ストレージ BLOB データ共同作成者」の権限を割り当てました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/cc98ddc0-9eeb-8c77-d855-13ee7ffe5f7c.png)
### 5.3.7 テスト結果
無事ロジックアプリが動作すれば、実行履歴からデータの削除の出力が確認出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/fcd835c2-8b06-511b-ed37-db004acd1bd1.png)
最終ステップでメール通知を入れていたので、以下のように対象のファイルを削除した通知も確認が出来ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/114d3a21-1152-4923-94aa-f8a93a4c2876.png)

なお、Event-grid トピック側の情報でも履歴をみることが出来ます。
エラーや遅延時間なども見れますので、troubleshooting に活用してみて下さい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/371db413-d586-a467-6dd1-7bd471824423.png)

なお、今回は Blob データの削除を行いましたが、別の blob ストレージに copy することで隔離 (quarantine) も出来ます。**隔離については、以下記事を投稿しましたので参考として下さい。**

https://qiita.com/hisnakad/items/0f577fa1e712fb0d7ed2

# 6. まとめ
新しく発表された Defender for Storage のアンチマルウェアスキャン機能をご紹介いたしました。即時性があり、ファイルベースでのニアリアルタイムスキャンが実現出来るため、外部から受け付ける Azure Blob ストレージサービスを構築されているお客様に待望の機能が発表された形になります。今後のロードマップに期待しつつ、プレビューを試していただければと思います。
本記事がどなたかの参考になれば幸いです。

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