Azure Storage Blob にバージョンレベルの不変性ポリシーを構成する(Azure SDK for .NET)

## 概要

Azure SDK for .NET (Azure Storage.Blobs) で Azure ストレージアカウントにあるBlobに対して、BLOBレベルで不変性ポリシーを設定する。
Portal上から設定してる記事はあったが、SDKを使ってやってみたみたいな記事なかったので書いてみた。（公式Documentにほとんど書いてあるけど）

## 参考リンク

- [BlobBaseClient](https://docs.microsoft.com/en-us/dotnet/api/azure.storage.blobs.specialized.blobbaseclient?view=azure-dotnet)

## Azure Storage Accountを作成する

BLOB レベルで不変性ポリシーを構成させるには、ストレージアカウント作成時に「バージョンレベルの不変性のサポート」を有効にしないといけない。  
注意したいのがこれは作成時にしか変更できないらしい。  
設定ができたらPortalから作成したストレージアカウントへ行き、[データ管理] -> [データ保護] のアクセス制御の [バージョンレベルの不変性のサポートを有効にする] にチェックが入っているのが確認できる。  
これにより、BLOBに対して不変性ポリシーを構成できる

## 試しに Azure Portal 上から不変性ポリシーをBLOBに構成してみる

[データストレージ] -> [コンテナー] からコンテナーを適当に作成する。  

作成したらそこになんでもいいので適当なファイルをあげる
👇の画像のようにアクセスポリシーが選択できるようになっている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467168/3667cc86-efda-6d75-0397-b995695b77cc.png)
※[バージョンレベルの不変性のサポートを有効にする]にチェックが入っていないと出てきません。

[アクセスポリシー] -> [ポリシーの追加] を行うと以下の2つのポリシーの種類が選択できる

- 訴訟ホールド
- 時間ベースのアイテム保持

※ポリシーの種類の説明は[公式Doc](https://docs.microsoft.com/ja-jp/azure/storage/blobs/immutable-storage-overview)をみましょう

いずれかのポリシーを設定したのち、対象のBLOBを削除してみると、削除できないことが確認できます。(時間ベースの場合は設定時間次第ですが)

## SDK を用いて上記のことをコーディングしてみる

実装に用いたのは  

Azure.Storage.Blobs にある Azure.Storage.Blobs.Specialized の BlockBlobClient Class です

公式 Document：[BlockBlobClient 概要](https://docs.microsoft.com/en-us/dotnet/api/azure.storage.blobs.specialized.blockblobclient?view=azure-dotnet)

## 目次

[1.BLOB にアクセスする](#1-blob-にアクセスできるClient作る)
[2.BLOB にアクセスできるか疎通確認](#2-blob-にアクセスできるか疎通確認)
[3.時間ベースの不変性ポリシーを構成する](#3時間ベースの不変性ポリシーを構成する)
[4.訴訟ホールドの不変性ポリシーを構成する](#4訴訟ホールドの不変性ポリシーを構成する)
[5.不変性ポリシーの削除 (時間ベース) ](#5不変性ポリシーの削除-時間ベース)
[6.不変性ポリシーの削除 (訴訟ホールド) ](#6不変性ポリシーの削除-訴訟ホールド)

## 1. BLOB にアクセスできるClient作る

BlockBlobClient を作成してBlobにアクセスする

```C#
var client = new BlobBaseClient(
  connectionString: "[接続文字列]",
  blobContainerName: "[Container Name]",
  blobName: "[Blob Name]" // 例 "契約書/04/file.pdf"
);
```

- 接続文字列：作成したストレージアカウントから参照しましょう
- blobContainerName / blobName：それぞれコンテナ名 / ブロブ名 を設定する

## 2. BLOB にアクセスできるか疎通確認

```C#
var res1 = client.Exists();
var res2 = client.ExistsAsync(); 
```

エラーも吐かず、res.ValueがtrueになってればひとまずOK。
Blobが存在しなかったら Value は false が返却される。

参考：[BlobBaseClient.GetProperties](https://docs.microsoft.com/en-us/dotnet/api/azure.storage.blobs.specialized.blobbaseclient.getproperties?view=azure-dotnet#azure-storage-blobs-specialized-blobbaseclient-getproperties(azure-storage-blobs-models-blobrequestconditions-system-threading-cancellationtoken))

## 3.時間ベースの不変性ポリシーを構成する

```C#
var immutabilityPolicy = new BlobImmutabilityPolicy() {​​​ 
  ExpiresOn = DateTimeOffset.MaxValue,
  PolicyMode = BlobImmutabilityPolicyMode.Unlocked
}​​​;
client.SetImmutabilityPolicy(immutabilityPolicy: immutabilityPolicy);
```

- ExpiresOn： (DateTimeOffset) そのポリシーの有効期限。上記ではとりあえずポリシー効けばいいやと思ってるのでMaxValueとかにしてます。お好きな日時にしてください。
- PolicyMode：詳しくは調べてないが、lockedにするとポリシー削除ができなかったのでそのポリシーが編集できるかどうかの設定

参考：[BlobBaseClient.SetImmutabilityPolicy](https://docs.microsoft.com/en-us/dotnet/api/azure.storage.blobs.specialized.blobbaseclient.setimmutabilitypolicy?view=azure-dotnet)

## 4.訴訟ホールドの不変性ポリシーを構成する

```C#
await client.SetLegalHoldAsync(hasLegalHold: true, cancellationToken: default);
```

訴訟ホールドのほうはtrue/false入れるだけで設定できる。

参考：[BlobBaseClient.SetLegalHold](https://docs.microsoft.com/en-us/dotnet/api/azure.storage.blobs.specialized.blobbaseclient.setlegalhold?view=azure-dotnet#azure-storage-blobs-specialized-blobbaseclient-setlegalhold(system-boolean-system-threading-cancellationtoken))

### Portal 上ではこんな感じに設定されているのが確認できる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/467168/f5b973cc-2370-816f-d80f-29896d2e746c.png)

※👆画像ではロック済みになってるポリシーがありますが、Unlockedで設定すればロックされないです

## 5.不変性ポリシーの削除 (時間ベース)

```C#
await client.DeleteImmutabilityPolicyAsync();
```

- ロックしてる場合、削除できないので注意

## 6.不変性ポリシーの削除 (訴訟ホールド)

```C#
await client.SetLegalHoldAsync(hasLegalHold: false);
```

- 訴訟ホールドは false を設定するだけでPortal上から消えました

## 問題

- 既にあるストレージアカウントこれやりたい場合はストレージアカウントを作り直さないといけない（作成時にしか設定できないため）
- local 実行時に azurite 使ってみたがエラーで落ちる。（[バージョンレベルの不変性のサポートを有効にする]みたいな設定がazuriteにある？未調査）
- BlobBaseClientを使用するため（BlobレベルでClientを作らないとなので）、ポリシーの追加/削除の処理をするたびにClientを作らないといけないのでインスタンスの作りすぎとか起きないように注意が必要

## まとめ

- BLOBレベルで不変ポリシーを設定する場合はストレージアカウントを作る際に[**バージョンレベルの不変性のサポートを有効にする**]にチェックを入れましょう
- ポリシーの削除を考えている場合は PolicyMode をUnlockedにすること
- 時間ベースはSetImmutabilityPolicy() / 訴訟ホールドはSetLegalHoldAsync()