しばやん雑記

ASP.NET Core とメイドさんが大好きなフリーランスのプログラマーのブログ

Managed Identity と RBAC を使って Azure Storage をアクセスキー無しで扱ってみる

Azure Storage への Managed Identity と RBAC を使ったアクセスが前に GA しましたが、試してなかったので使い方を確認しました。あとは App Service と User assigned managed identity の組み合わせもちゃんと試してなかったので、折角なので同時に使ってみました。

基本的には以下のドキュメントの通りで、良くまとまっています。なのではまった部分を中心に書きます。

まずは開発環境の Visual Studio から Azure Storage に対して AAD を使った操作が行えるか確認しました。組み込まれている Azure サービス認証のおかげで AzureServiceTokenProvider を使っておけば、開発環境と Azure 上の両方で同じコードが利用できます。

Azure SDK は Preview 版も出てますが、今回は以下の NuGet パッケージをインストールしました。

  • Microsoft.Azure.Services.AppAuthentication
  • Microsoft.Azure.Storage.Blob

基本は Access Token を取得して、各ストレージの処理を呼び出すという流れです。アクセストークンを取得する時の Resource ID は https://storage.azure.com/ を使いました。Blob と Queue でさらに細分化されてますが、とりあえず Azure Storage 全体を触れるもので試します。

普段なら Connection String を Parse して CloudStorageAccount を作ってると思いますが、Access Token を使う場合は StorageCredentials を用意してから、CloudStorageAccount を作成します。コンストラクタの引数がちょっと面倒かも知れません。

var accessToken = await new AzureServiceTokenProvider().GetAccessTokenAsync("https://storage.azure.com/");

var credentials = new StorageCredentials(new TokenCredential(accessToken));
var storageAccount = new CloudStorageAccount(credentials, "demoappstorage1", null, true);

var blobClient = storageAccount.CreateCloudBlobClient();

var container = blobClient.GetContainerReference($"{DateTime.Now:yyyyMMdd}");

await container.CreateIfNotExistsAsync();

var blob = container.GetBlockBlobReference($"{DateTime.Now:HHmmss}.txt");

await blob.UploadTextAsync("kazuakix");

ドキュメントでは TokenCredential に用意した Access Token 取り直し用のメソッドを指定してますが、Managed Identity で取得できるトークンは期限が切れる 5 分前に自動で更新されるので、時間のかかる処理以外では都度 Access Token を取得して使えば良いと思います。

この辺りの設計は Azure Management Library と異なっているので統一感がないです。Preview SDK だと改善されていますが、それは後で述べます。

上のコードで AAD を使った Azure Storage の操作が行えるようになりますが、デフォルトでは Blob を操作するためのロールが付いていないので、Storage か Container の IAM からロールの割り当てを追加します。

Azure Portal から Container を選んで接続方法を AAD に変えると、権限の有無が簡単に確認できます。

f:id:shiba-yan:20190915000131p:plain

Azure Storage の AAD 対応に伴って、いくつかロールが追加されています。今回は Storage Account に対して Storage Blob Data Contributor を割り当てました。

f:id:shiba-yan:20190915000142p:plain

User assigned managed identity と自分自身にもロールを割り当てておきます。自分にも割り当てておかないと Visual Studio から確認することが出来ないので、忘れないようにします。

f:id:shiba-yan:20190915000929p:plain

暫く待つと、先ほどエラーになっていた Container の AAD でのアクセスが行えるようになります。

f:id:shiba-yan:20190915000302p:plain

これで先ほどのコードを実行すると、アクセスキー無しで Blob の作成が行えるようになりました。

f:id:shiba-yan:20190915002527p:plain

Azure Storage SDK がアクセストークンを使うように最適化されてないので多少面倒な感じですが、RBAC を使ったアクセス制限も問題なく行えるようになっています。

App Service で動かす

アクセストークンが取れれば問題なく動くことを開発環境で確認出来ているので、後は App Service にデプロイして試します。User assigned managed identity を使うので、App Service に割り当てておきます。

f:id:shiba-yan:20190915002302p:plain

これだけで最初は動くだろうと思っていましたが、実際にデプロイしてみるとアクセストークンが取れずにエラーとなりました。System assigned だと問題なかったので調べると、User assigned の場合は Client ID を指定する必要がありました。

Managed Identity はドキュメントが散らばっていてアレですが、接続文字列で Client ID を渡せます。

接続文字列は環境変数 AzureServicesAuthConnectionString を参照してくれるので、App Service の場合は App Settings にキーと値を追加すると、指定した User assigned managed identity の Access Token が取れるようになります。期待していたのと動作が異なっていました。

運用する場合には、この Client ID の管理がめんどくさくなりそうなので、基本は System assigned を使って行きたい気持ちになりました。App Service の場合はアプリ単位での権限管理になるので、System assigned だからと言って管理が煩雑になることもないでしょう。

おまけ : Azure SDK Preview について

設計がイマイチだった Access Token 周りですが、Azure SDK Preview では Azure.Identity によって AAD 認証と Managed Identity がデフォルトになっていきそうな気配があります。

現在公開されている SDK は、大体が AAD に対応したサービスです。統一感のある API が提供されているので、現在の秩序の無い SDK に比べると大幅に使い勝手が改善されそうです。