ストレージアカウントでSASトークンを使ってみる

## 初めに
Azureのストレージアカウントにアクセスする場合、Shared Access Signature(SAS)トークンを使用してのアクセス方法が提供されています。
このSASトークンを使用する場合、IPアドレスんを指定したり、リンクの有効期間を指定したり、書き込み等の権限を指定したりといったことを簡単に実施できます。
そこで今回は、SASトークンを使用してのアクセス方法を紹介します。

## SASトークンについて
SASトークンは、基本的に

* IP制限
* トークンの有効期限指定
* ファイルやデータ書き込み、読み込み等の制限

といったことが可能です。
またSASトークンは、コンテナへのアクセス許可、特定のファイルへのアクセス許可など細かくアクセス制限することが可能です。

## SASトークンを生成する
SASトークンは、基本的にプログラム的に生成する方法と、ツールを使って生成する方法があります。
ツールを使う場合、ポータルから生成する方法や、Microsoft Azure Storage Explorerを使用する方法が一般的です。
今回は、C#での生成方法を紹介します。

### 必要な情報を取得する
SASトークンを生成するには、

* ストレージアカウント名
* ストレージアカウントキー
* Blobコンテナ名等SASトークンを発行したいものの名前

が必要になります。

ストレージアカウント名とキーは、ポータルから取得できます。
下記の図のようにポータルのストレージアカウントの項目からアクセスキーを選択すると表示されます。
![storage.png](https://qiita-image-store.s3.amazonaws.com/0/28367/f0e87931-514b-eaa8-96fa-a36a4513090d.png)


### C\#での実装
必要な情報が得られたらプログラムから生成してみましょう。
ざっくりとSASトークンを生成するサンプル実装です。(変数名等は適当です。)

#### コンテナ用のSASトークン
```csharp

var storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
var blobClient = storageAccount.CreateCloudBlobClient();
var container = blobClient.GetContainerReference("test");
container.CreateIfNotExists();

var sasConstrains = new SharedAccessBlobPolicy();
sasConstrains.SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24);

var ipRange = new IPAddressOrRange("192.168.192.168");

sasConstrains.Permissions = SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.List;
var sasContainerToken = container.GetSharedAccessSignature(sasConstrains);
```
#### Blob用のSASトークン
```csharp
var storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));

var blobClient = storageAccount.CreateCloudBlobClient();

var container = blobClient.GetContainerReference("test");
container.CreateIfNotExists();

var blob = container.GetBlockBlobReference(blobName);

var sasContraints = new SharedAccessBlobPolicy();
sasContraints.SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5);
sasContraints.SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24);
sasContraints.Permissions = SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.Write;

var ipRange = new IPAddressOrRange("192.168.192.168");

var sasBlobToken = blob.GetSharedAccessSignature(sasContraints, null, null, null, ipRange);
```
#### キュー用のSASトークン
```csharp
var storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
var queuClient = storageAccount.CreateCloudQueueClient();
var container = queuClient.GetQueueReference("test");
container.CreateIfNotExists();

var sasQueue = new SharedAccessQueuePolicy();
sasQueue.SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5);
sasQueue.SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24);
sasQueue.Permissions = SharedAccessQueuePermissions.Read | SharedAccessQueuePermissions.Add | SharedAccessQueuePermissions.ProcessMessages;

var ipRange = new IPAddressOrRange("192.168.192.168");

var sasQueueToken = container.GetSharedAccessSignature(sasQueue, null, null, ipRange);
```
#### テーブル用のSASトークン
```csharp
var storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
var tableClient = storageAccount.CreateCloudTableClient();
var container = tableClient.GetTableReference("test");
container.CreateIfNotExists();

var sasPolicy = new SharedAccessTablePolicy();

sasPolicy.SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5);
sasPolicy.SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24);
sasPolicy.Permissions = SharedAccessTablePermissions.Add | SharedAccessTablePermissions.Delete | SharedAccessTablePermissions.Query | SharedAccessTablePermissions.Update;

var ipRange = new IPAddressOrRange("192.168.192.168");

var sasToken = container.GetSharedAccessSignature(sasPolicy, null, null, null, null, null, null, ipRange);

```
#### ファイル用のSASトークン
```csharp
var storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
var fileClient = storageAccount.CreateCloudFileClient();

var container = fileClient.GetShareReference("test");
container.CreateIfNotExists();

var sasPolicy = new SharedAccessFilePolicy();
sasPolicy.SharedAccessStartTime = DateTime.Now.AddMinutes(-5);
sasPolicy.SharedAccessExpiryTime = DateTime.Now.AddHours(24);
sasPolicy.Permissions = SharedAccessFilePermissions.Create | SharedAccessFilePermissions.Read | SharedAccessFilePermissions.Write | SharedAccessFilePermissions.Delete | SharedAccessFilePermissions.List;

var ipRange = new IPAddressOrRange("192.168.192.168");
var sasToken = container.GetSharedAccessSignature(sasPolicy, null, null, ipRange);
```

このコードを動かすと?st=~といった文字列が返ってきます。
これがSASトークンになります。

## SASトークンを使用してBlobにアクセスしてみる
トークンが生成出来たらストレージにアクセスしてみましょう。
今回は、Blobにアクセスしてみます。
SASトークンを使用したアクセス方法をC\#で実装すると下記のような感じです。

```csharp

var auth = new StorageCredentials(sasToken);
var blobClient = new CloudBlobClient(uri, auth);

var blob = blobClient.GetBlobReferenceFromServer(uri);

Console.WriteLine(blob.Name);
```

今回は、Blobを取得してファイル名を表示するコードです。
また、BlobのURI + SASトークンでWebブラウザからアクセスも可能なので

```
https://test.blob.core.windows.net/test/test.txt?st=~
```

といったURLでのアクセスも可能です。

## まとめ
SASトークンを使用するとファイルダウンロードの際のURLに時間制限を設けたり、IPアドレスによって特定の拠点からのみアクセスを許可するといったことができるようになり、ストレージの運用を簡単にセキュアにすることが可能になるので、機会があればぜひ使用してみてください。