Azure Blob ストレージにアップロードされるマルウェア感染した Blob データを Microsoft Defender for Storage アンチマルウェアスキャンを行って隔離する

# 1. はじめに
先日、Microsoft Defender for Storage の新機能で発表された Antimalware Scanning の機能を記事に書きましたが、自動化設定でマルウェア感染したファイルを削除するのではなく、別のストレージに**隔離したい**要望が多かったため、本記事でご紹介したいと思います。

**Defender for Storage のアンチマルウェアスキャン機能の紹介にてついては、前記事のこちらをご参照下さい。**

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

# 2. 構成イメージ
Microsoft Defender for Storage マルウェアスキャンの**隔離 (Quarantine)** 構成イメージを以下のようになります。
プロダクション環境に対して、外部からマルウェア混入したファイルがアップロードされると、Defeneder for Storage のマルウェアスキャンがニアリアルタイムで動作し、マルウェア判定されるとファイルを SOC (Security Operation Team) チームが管理しているストレージに自動で隔離する構成となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/e7b12e58-4fd3-4c53-207d-06503f080827.png)

# 3. ロジックアプリの構成例
ロジックアプリの構成は、前回ファイル削除した自動化のロジックアプリと同じような構成です。Blob ファイルの移動を行うために、新たに以下 2 つのコネクタを追加しています。個々のロジックアプリのステップについて解説していきたいと思います。
- 「**パスを使用して SAS URI を作成する (V2)**」
- 「**BLOB をコピーする (V2)**」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/e9173d81-2fd7-29da-40cb-8742ca15192b.png)

Azure Storage 側の設定 (Defender for Storage の有効化) については、前回ご紹介した以下の設定を実施して下さい。

https://qiita.com/hisnakad/items/0d570e87490996d06146#41-defender-for-storage-%E3%82%92%E6%9C%89%E5%8A%B9%E5%8C%96%E3%81%99%E3%82%8B

## 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)

なお、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

## 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)
## 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"
}
```

## 3.4 SAS URI の作成
ロジックアプリのコネクタを用いた　Blob データのコピーを行う場合、プライベートなコンテナに対しては SAS (Shared Access Signature) を用いて取得する必要があります。（ここが分からなくて苦労しました。。）
パブリックのコンテナーであれば、blob ファイルの URL をそのまま張り付けることが出来ますが、プライベートのコンテナーに対しては SAS URL を発行してコピーする必要があるためご注意ください。
以下 MSDN コミュニティに詳細が記載されていますので参考として下さい。

https://social.msdn.microsoft.com/Forums/ja-JP/2dbb9170-6301-43c7-add7-b2110e03b765/logicapps1243420351299921237512383blobstorage3829112398124671250012540?forum=windowsazureja

SAS　URI のコネクタ設定は以下画面のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/b6b08b19-6f84-cf55-d872-cd9c50473afa.png)
以下設定が注意事項になります。
- BLOB パスは ``/aaa/bbb.txt``のような、コンテナー以下のURI なので注意
    - 3.3 で設定した ``blobUri`` に対して、[uriPath 関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#uriPath)を用いて URI を取得する
        - **``uriPath(body('Parse_JSON')?['blobUri'])``** を張り付ける
        - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/43d9565d-a858-6057-c8d7-5d82569aa313.png)
- SAS URI を発行するコネクター「パスを使用して SAS URI を作成する (V2)」は**アカウントキー認証**で設定する
    - マネージド ID / AAD 認証は本コネクターで用いるとエラーになります。
    - ストレージアカウントキーの認証が必要だったので、確認してみて下さい。

## 3.5 隔離設定：まずは宛先の BLOB をコピーする
別途、隔離先のAzure Blob ストレージを用意し、まずはコピーを行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/2e729df3-32d1-933a-cb06-f33ac377e5ba.png)
- 「**ストレージアカウント**」は、隔離先の Azure ストレージ名を設定します。
- 「**BLOB をコピーする(V2)**」コネクタは、ソース URL は 3.4 で作成した SAS URI で生成される動的コンテンツを用います。
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/7fd6da4c-5718-19eb-6154-19ea17bbf982.png)
- 宛先 BLOB のパスは ``/aaa/bbb.txt`` のようなパス情報になります。
    - 本記事では、コピー元のコンテナー名と同じものを隔離先のストレージ先にコピーする設定を想定しています。
        - もし、宛先の blob ストレージでコンテナー名を変更したいような場合は、[replace 関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#replace)などを使って、対象のコンテナー名を置換すると良いのではと思います。
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/a16f57e9-f0ce-e51f-2199-45dcb368b299.png)
    - 本設定例の場合、コピーした先の blob コンテナーも事前に同じ名前のものを用意しておく必要があるのでご注意ください。
    - 以下例です（宛先の Blob にも /test/ を用意しておく必要がある）
        - 転送元 ``https://[元の Storage アカウント].blob.core.windows.net/test/example1.txt``
        - 宛先 ``https://[隔離先の Storage アカウント].blob.core.windows.net/test/example1.txt``

## 3.6 隔離設定：アップロードされた側の BLOB を削除する
3.5 にてコピーが終わったので、アップロードされた側の Azure Blob Storage に対して BLOB データの削除を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/60e46af1-f4db-b659-6a94-6d69525bac68.png)
- BLOB の欄はパスになるため、[uriPath 関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#uriPath)を用いて URI を取得する設定を入れるようにしましょう。
    - ``uriPath(body('Parse_JSON')?['blobUri'])``

## 3.7 (おまけ) 隔離通知をメールで行う
最後は O365 コネクタを用いて、隔離したことを知らせるメール通知を設定してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/69b5c930-8c61-5111-2e2d-7413d5861e34.png)

## 3.8 ロジックアプリにマネージド 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)

# 4. テスト結果
無事ロジックアプリが動作すれば、実行履歴からデータの削除の出力が確認出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/06fc8894-51c5-0da7-2843-099b0ee5f2d5.png)
今回もメール通知を入れていますので、隔離した場合に気付くことが出来るようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/161c923a-05ed-d4dc-45fe-7252a57721c2.png)
隔離されたデータは、転送先の Azure Blob ストレージに移動されていることも確認できました。こちらも SOC チーム側で監視ができるように Defender for Storage の Antimalware Scanning を有効にしてタグで管理出来るようにしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653790/091240e2-4461-5d97-2bef-a7b70f2da2f5.png)

# 5. まとめ
前回に引き続き、Defender for Storage のアンチマルウェアスキャン機能を用いて、ロジックアプリを用いた隔離運用についてご紹介いたしました。実際の運用は本設定のようにファイルを削除せず、隔離を行ってセキュリティ担当者がマルウェアを駆除するような使われ方が想定されるのではと思います。本記事がどなたかの参考になれば幸いです。

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