tl;dr
Amazon S3 で言うところの Presigned URL 的なものが Azure Blob ストレージにもきっとあるだろうと思って調べたらあったのでメモ。
その名も Shared Access Signature(共有アクセス署名)という名前。Southern All Stars や Scandinavian Airlines System や Serial Attached SCSI 等、我々の周りにはいくつかの SAS が存在しているが、今回、新しい SAS が加わった形となる。
参考
- Shared Access Signature: SAS モデルについて | Microsoft Azure
- BLOB サービスによる SAS の作成および使用 | Microsoft Azure
- コンテナーと BLOB への匿名アクセスを管理する |Microsoft Azure
- 共有アクセス署名 URI の構築
共有アクセス署名とは(ドキュメントをざっくりと纏める)
ざっくり
- Blob ストレージ内のオブジェクトに対して期間とアクセス許可を指定してクライアントにアクセスさせる為の仕組み
- クライアントに対してストレージアクセスキーを付与することなく比較的安全にオブジェクトにアクセスさせることが出来る
- URL クエリパラメータ内にストレージリソースへの認証アクセスに必要な情報が含まれている
共有アクセス署名の機能(URI)
共有アクセス署名で利用される URI には下図のようなパラメータが含まれる。(オレンジ色は必須項目)
(出典:https://msdn.microsoft.com/en-us/library/azure/dn140255.aspx)
- ストレージリソース
- コンテナーと Blob
- ファイル共有とファイル
- キュー
- テーブルとテーブルエンティティの範囲
- 開始時刻(SAS が有効になる時刻)
- 有効期限(SAS が無効になる時刻)
- アクセス許可
以下は URL の例。
https://myaccount.blob.core.windows.net/sascontainer/sasblob.txt?sv=2012-02-12&st=2013-04-29T22%3A18%3A26Z&se=2013-04-30T02%3A23%3A26Z&sr=b&sp=rw&sig=Z%2FRHIX5Xcg0Mq2rqI3OlWTjEg2tYkboXr1P9ZUXDtkk%3D
以下は URL パラメータの詳細。
名前 | リンク / セクション | 説明 |
---|---|---|
Blob URI | https://myaccount.blob.core.windows.net/sascontainer/sasblob.txt | BLOB のアドレス。HTTPS の使用を推奨。 |
ストレージサービスのバージョン | sv=2012-02-12 | ストレージ サービス バージョン 2012-02-12 以降では、このパラメーターは、使用するバージョンを示す。 |
開始時刻 | st=2013-04-29T22%3A18%3A26Z | ISO 8061 形式で指定。SAS をすぐに有効にする場合は、開始時刻を省略する。 |
有効期限 | se=2013-04-30T02%3A23%3A26Z | ISO 8061 形式で指定。 |
リソース | sr=b | リソースは BLOB を指定。 |
アクセス許可 | sp=rw | SAS で付与されるアクセス許可には、読み取り (r) および書き込み (w) が含まれる。 |
署名 | sig=Z%2FRHIX5Xcg0Mq2rqI3OlWTjEg2tYkboXr1P9ZUXDtkk%3D | BLOB へのアクセスを認証するために使用する。署名は、SHA256 アルゴリズムを使用して署名対象文字列とキーを計算した後に、Base 64 エンコードを使用してエンコードした HMAC 値。 |
SAS の種類
以下の形式の SAS が利用可能。
以下に整理。
形式 | 詳細 |
---|---|
アドホック SAS | 開始時刻、有効期限、アクセス許可が SAS URL で指定される(コンテナ、Blob、ファイル共有、ファイル、テーブル、キューで作成可能) |
アクセスポリシー + SAS | コンテナに付与するアクセスポリシー(プライベート/パブリックコンテナー/パブリック Blob)と SAS の併用 |
アクセスポリシーについては以下のドキュメントにて。
Azure SDK for Ruby による SAS の実装
せっかくなので...
Azure SDK for Ruby(0.6.4) を利用して Blob オブジェクトの SAS URI を作成してみる。
参考
共有アクセス署名の生成
ドキュメントの共有アクセス署名 URI の構築に詳細に記載されている(※「署名の指定」及び「署名文字列の作成」セクション)。ストレージのバージョン毎に署名に利用する対象の文字列が異なるので注意が必要。また、署名の生成に際しては署名対象文字列以外にストレージアカウントキーが必要となる。
尚、署名は以下のステップで生成する。
上記のステップはドキュメントとサンプルソースをななめ読みした個人的な解釈なので誤りがあるかもしれない。
尚、以下のサンプルに関しては「2012/02/12 よりも以前のバージョン」を参考に以下の署名対象文字列を利用した。
StringToSign = signedpermissions + "\n" signedstart + "\n" signedexpiry + "\n" canonicalizedresource + "\n" signedidentifier
各文字列については以下のとおり。(ドキュメントより一部抜粋)
フィールド名 | クエリパラメーター | 説明 |
---|---|---|
signedstart | st | 省略可能。共有アクセス署名が有効になる時刻 (ISO 8601 形式)。省略した場合には現在時刻となる。2012-02-12 より前のバージョンではコンテナー ポリシーを使用する場合を除き signedstart から signedexpiry までの期間が 1 時間を超えた指定は出来ない。 |
signedexpiry | se | 必須。共有アクセス署名が無効になる時刻 (ISO 8601 形式)。 |
signedpermissions | sp | 必須。共有アクセス署名と関連付けられているアクセス許可。BLOB の場合には「読み取り(r )と書込(w )と削除(d )」を指定することが出来る。 |
signedresource | sr | 必須。共有リソースが BLOB の場合は、b を指定する。共有リソースがコンテナーの場合は、c を指定する。 |
canonicalizedresource | 署名対象リソースへの正規化されたパス。この部分にはストレージ アカウント名とリソース名が含まれている必要がある。 |
サンプル
上記の参考記事を参考に以下のようなサンプルをこさえた。
Dockerfile もあるので docker run
で試す。(事前にストレージアカウントとコンテナを作成しておく)
# # SAS URI 発行 # $ docker run \ > --env 'STORAGE_ACCOUNT_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \ > --env 'STORAGE_ACCOUNT_NAME=komanechi' \ > --env 'STORAGE_CONTAINER_NAME=foo' \ > --env 'EXPIRE_TIME=30' \ > --env 'CONTENT_KEY=foo' \ > --env 'CONTENT=bar' \ > inokappa/azure-storage-sas-ruby SAS URI : https://komanechi.blob.core.windows.net/foo/foo?se=2015-09-10T01%3A02%3A01Z&sig=sNl%2BAq8lOOqspapwcYVGrELZTaUBRTxNN3QIITc6DEY%3D&sp=r&sr=b&st=2015-09-10T01%3A01%3A31Z Start Time : 2015-09-10T01:01:31Z End Time : 2015-09-10T01:02:01Z Response Status Code : 200 Response Body : bar # # 確認 # # アクセス OK $ curl "https://komanechi.blob.core.windows.net/foo/foo?se=2015-09-10T01%3A02%3A01Z&sig=sNl%2BAq8lOOqspapwcYVGrELZTaUBRTxNN3QIITc6DEY%3D&sp=r&sr=b&st=2015-09-10T01%3A01%3A31Z" bar $ curl "https://komanechi.blob.core.windows.net/foo/foo?se=2015-09-10T01%3A02%3A01Z&sig=sNl%2BAq8lOOqspapwcYVGrELZTaUBRTxNN3QIITc6DEY%3D&sp=r&sr=b&st=2015-09-10T01%3A01%3A31Z" bar $ curl "https://komanechi.blob.core.windows.net/foo/foo?se=2015-09-10T01%3A02%3A01Z&sig=sNl%2BAq8lOOqspapwcYVGrELZTaUBRTxNN3QIITc6DEY%3D&sp=r&sr=b&st=2015-09-10T01%3A01%3A31Z" bar $ curl "https://komanechi.blob.core.windows.net/foo/foo?se=2015-09-10T01%3A02%3A01Z&sig=sNl%2BAq8lOOqspapwcYVGrELZTaUBRTxNN3QIITc6DEY%3D&sp=r&sr=b&st=2015-09-10T01%3A01%3A31Z" bar $ curl "https://komanechi.blob.core.windows.net/foo/foo?se=2015-09-10T01%3A02%3A01Z&sig=sNl%2BAq8lOOqspapwcYVGrELZTaUBRTxNN3QIITc6DEY%3D&sp=r&sr=b&st=2015-09-10T01%3A01%3A31Z" bar $ curl "https://komanechi.blob.core.windows.net/foo/foo?se=2015-09-10T01%3A02%3A01Z&sig=sNl%2BAq8lOOqspapwcYVGrELZTaUBRTxNN3QIITc6DEY%3D&sp=r&sr=b&st=2015-09-10T01%3A01%3A31Z" bar $ curl "https://komanechi.blob.core.windows.net/foo/foo?se=2015-09-10T01%3A02%3A01Z&sig=sNl%2BAq8lOOqspapwcYVGrELZTaUBRTxNN3QIITc6DEY%3D&sp=r&sr=b&st=2015-09-10T01%3A01%3A31Z" bar $ curl "https://komanechi.blob.core.windows.net/foo/foo?se=2015-09-10T01%3A02%3A01Z&sig=sNl%2BAq8lOOqspapwcYVGrELZTaUBRTxNN3QIITc6DEY%3D&sp=r&sr=b&st=2015-09-10T01%3A01%3A31Z" bar $ curl "https://komanechi.blob.core.windows.net/foo/foo?se=2015-09-10T01%3A02%3A01Z&sig=sNl%2BAq8lOOqspapwcYVGrELZTaUBRTxNN3QIITc6DEY%3D&sp=r&sr=b&st=2015-09-10T01%3A01%3A31Z" bar $ curl "https://komanechi.blob.core.windows.net/foo/foo?se=2015-09-10T01%3A02%3A01Z&sig=sNl%2BAq8lOOqspapwcYVGrELZTaUBRTxNN3QIITc6DEY%3D&sp=r&sr=b&st=2015-09-10T01%3A01%3A31Z" bar $ curl "https://komanechi.blob.core.windows.net/foo/foo?se=2015-09-10T01%3A02%3A01Z&sig=sNl%2BAq8lOOqspapwcYVGrELZTaUBRTxNN3QIITc6DEY%3D&sp=r&sr=b&st=2015-09-10T01%3A01%3A31Z" bar # 30 秒後...アクセス不可 $ curl "https://komanechi.blob.core.windows.net/foo/foo?se=2015-09-10T01%3A02%3A01Z&sig=sNl%2BAq8lOOqspapwcYVGrELZTaUBRTxNN3QIITc6DEY%3D&sp=r&sr=b&st=2015-09-10T01%3A01%3A31Z" ・ソ<?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signa ture. RequestId:da998a44-0001-0032-5464-ebccc4000000 Time:2015-09-10T01:02:01.4635058Z</Message><AuthenticationErrorDetail>Signature not valid in the specified time frame: Start [Thu, 10 Sep 2015 01:01:31 GMT] - Expiry [Thu, 10 Sep 2015 01:02:01 GMT] - Current [Thu, 10 Sep 2015 01:02:01 GMT]</AuthenticationErrorDetail></Error>
まとまってないまとめ
共有アクセス署名とは
- Amazon S3 の Presigend URL のようにアクセス権限と期限を設けた一時的な URL を発行する際に利用する
- 署名は対象の文字列(ストレージバージョンによって異なる)をハッシュ化等して生成する
- 共有アクセス署名 URI には署名に合わせて、対象となるリソース、期限や権限をパラメータとして定義する
- 各ストレージ(Blob / テーブル / キュー)に指定することが出来る
- Azure SDK for Ruby の 0.6.4 だと署名の生成、URL の生成は独自に実装する必要がありそう(最新の 0.7.0 だと実装されているようだけどどのように使うのか不明...すいません)