やりたいこと
Azure Storage Account に一時的なアクセス権限を与える SAS トークンを発行するには、ストレージアカウントのキーをベースにするのではなく、user delegation SAS (ユーザー委任 SAS) がセキュリティ的に良さそうです。しかし、クライアントが Raspberry Pi など Azure 上にない場合は、ユーザー委任 SAS を発行するのにサービスプリンシパルの設定がややこしそうに思いました。
そこで、Azure Functions に マネージド ID を割り当ててユーザー委任 SAS トークンを発行できるようにしてみました。これにより、Azure Functions を呼び出すことで発行された SAS を取得できます。今度は Azure Functions 側のアクセス管理が問題になりますが、そこはまた別途検討しようと思います。
Azure Functions 側のコード
ユーザー委任 SAS を発行するための公式ドキュメントが .NET, Azure CLI, PowerShell しか見つからなかったため、今回は PowerShell のドキュメント に沿いました。なお、Azure Functions の Cold start の影響なのか、呼び出し間に時間が空くと応答に数十秒かかることもありました。いずれ他の言語でも試してみたいと思います。
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request. Create SAS Uri."
$StorageAccountName = "<お使いのストレージアカウント名>"
$ContainerName = "<お使いのコンテナ名>"
$BlobName = $Request.Body.fileName
# https://docs.microsoft.com/ja-jp/azure/storage/blobs/storage-blob-user-delegation-sas-create-powershell
$ctx = New-AzStorageContext -StorageAccountName $StorageAccountName -UseConnectedAccount
# https://docs.microsoft.com/ja-jp/powershell/module/az.storage/new-azstorageblobsastoken?view=azps-5.7.0#example-2--generate-a-blob-sas-token-with-life-time
$StartTime = Get-Date
$EndTime = $StartTime.AddHours(2.0)
if ($BlobName)
{
$Uri = New-AzStorageBlobSASToken -Context $ctx `
-Container $ContainerName `
-Blob $BlobName `
-Permission racwd `
-StartTime $startTime `
-ExpiryTime $EndTime `
-FullUri
}
else
{
# Blob 単位の SAS を発行したい場合
# https://docs.microsoft.com/ja-jp/azure/storage/blobs/storage-blob-user-delegation-sas-create-powershell#create-a-user-delegation-sas-for-a-blob
$Uri = New-AzStorageContainerSASToken -Context $ctx `
-Name $ContainerName `
-Permission racwdl `
-ExpiryTime $EndTime `
-FullUri
}
# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = "{`"url`":`"" + $Uri + "`"}"
})
マネージド ID の割り当て
公式ドキュメント: ユーザーの委任 SAS の作成 - RBAC を使用してアクセス許可を割り当てる
に記載があるように、generateUserDelegationKey 権限および、発行した SAS に許可したい操作権限を持つ Azure ロールを割り当てる必要があります。
今回は組み込みロールの中から ストレージ BLOB データ共同作成者 を選びました。お使いのストレージアカウントに対して割り当てます。
アプリファイルの設定
前述のコードを利用するための設定が必要です。
requirementes.psd1 では Az モジュールを使えるようにします。
# This file enables modules to be automatically managed by the Functions service.
# See https://aka.ms/functionsmanageddependency for additional information.
#
@{
# For latest supported version, go to 'https://www.powershellgallery.com/packages/Az'.
# To use the Az module in your function app, please uncomment the line below.
'Az' = '5.*'
}
profile.ps1 では、Enable-AzureRmAlias を実行するようにします Azure.Storage モジュールはまだ AzureRm なのかな...?
# Azure Functions profile.ps1
#
# This profile.ps1 will get executed every "cold start" of your Function App.
# "cold start" occurs when:
#
# * A Function App starts up for the very first time
# * A Function App starts up after being de-allocated due to inactivity
#
# You can define helper functions, run commands, or specify environment variables
# NOTE: any variables defined that are not environment variables will get reset after the first execution
# Authenticate with Azure PowerShell using MSI.
# Remove this if you are not planning on using MSI or Azure PowerShell.
if ($env:MSI_SECRET) {
Disable-AzContextAutosave -Scope Process | Out-Null
Connect-AzAccount -Identity
}
# Uncomment the next line to enable legacy AzureRm alias in Azure PowerShell.
Enable-AzureRmAlias
# You can also define functions or aliases that can be referenced in any of your PowerShell functions.
実行結果
Azure Functions の「関数の URL を取得」で取得した URL にアクセスして、SAS トークン付きの URL が返ってくることを確認しましょう。
{
"url": "https://<ストレージアカウント名>.blob.core.windows.net/<コンテナ名>?<SAS トーコン>"
}
こちらのトークンをもとにマネージド ID に割り当たっている権限の操作が可能です。
おわりに
Cold Start の問題をまだ解消できていないですが、次は SORACOM Funk とも組み合わせることでデバイス <=> Azure Functions のアクセス問題を解決してみようかと思います。マネージド ID の使い方がわかってよかったです。