Azureの小ネタ (改)

~Azureネタを中心に、色々とその他の技術的なことなどを~

Shared Access Signature と Signed identifier

こんばんは、statemachineです。今回は、@さんからのつぶやきに反応して Blobの共有アクセス署名(SAS)についてです。


現象としては、1時間以上アクセス可能なSASを生成できないというものです。いままで、SASのサンプルとして提示してきたものは、比較的短時間の5分程度であったためいままで気づきませんでした。

再現

以下、再現コード。2時間のSASを生成して、取得できたURLにアクセスしてみます。

    var blobClient = account.CreateCloudBlobClient();
    var container = blobClient.GetContainerReference("pictures");
    var blob = container.GetBlobReference("Desert.jpg");

    var blobPolicy = new SharedAccessPolicy()
    {
       Permissions = SharedAccessPermissions.Read,
       SharedAccessExpiryTime = DateTime.Now.AddHours(2)
    };

    var sas = blob.GetSharedAccessSignature(blobPolicy);
    Console.WriteLine (blob.Uri.AbsoluteUri + sas);

表示されたURL先にアクセスすると、以下のエラーレスポンスが表示されます。超訳すると、「Singed identifierなしの場合は、1時間以上のアクセス権は与えられないよ」とのことです。

<Error>
  <Code>AuthenticationFailed</Code> 
  <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:f2cb846f-55c7-4440-aa43-ba25d823cd86 Time:2010-11-17T12:26:31.9118699Z</Message> 
  <AuthenticationErrorDetail>Access without signed identifier cannot have time window more than 1 hour</AuthenticationErrorDetail> 
</Error>

Singed identifier

Twitterのリンク先などから取りあえずの回避策は分かったものの、この制限は何ぞや? と、調べてみたところ、Delegating Access with a Shared Access Signature (REST API)にその記述があることを発見。詳細は、リンク先のSigned indentifierの部分を読んでいただくとして、多少引用すると以下。

ようするに、singed identifierなしの場合、最大1時間しか与えられない。これは既定の動作で、このポリシーは、signatureの流出とストレージアカウントを保護するものである。言われてみれば納得である。signed identifierなしのSASの場合は、それを取り消すことが出来ないことから、このような制限を設けていると考えられます。(というか、いままでSASを取り消すってことを考えていなかった)


If a signed identifier is not specified as part of the Shared Access Signature, the maximum permissible interval over which the signature is valid is one hour.
This is the default behavior for a Shared Access Signature if the signedidentifier field is not provided on the URL.
This policy is intended to protect the storage account in the event that the signature is leaked.

結局のところ、signed identifierとは、コンテナレベルで指定した、アクセスポリシーのことで、これとBlobのSASを関連づけるように生成しないと、1時間の制限は超えられないと言うことのようです。逆にこの仕組みを使うことで、生成したSASを無効にできたりするわけです。

1時間以上与える場合

ちょっと試行錯誤した結果のコードが以下。コンテナレベルにポリシーを設定しておいて、Blobではそのポリシーをそのまま利用します。これが、一般的なお作法なのかはよくわかってない。また、コンテナのポリシーと、Blobのポリシーに違う情報を入れておいたりすると、別のエラーが出たりするわけです。

    var blobClient = account.CreateCloudBlobClient();
    var container = blobClient.GetContainerReference("pictures");
    var blob = container.GetBlobReference("Desert.jpg");

    var containerPolicy = new SharedAccessPolicy()
    {
       Permissions = SharedAccessPermissions.Read,
       SharedAccessExpiryTime = DateTime.Now.AddYears(1)
    };
    
    // コンテナのポリシーは一度設定しておけば大丈夫。
    var perm = blob.Container.GetPermissions();
    if(perm.SharedAccessPolicies.ContainsKey("testpolicy"))
    {
        // 存在する場合は、なにもせず。
        Console.WriteLine ("already exist.");
    }
    else 
    {
       // 存在しない場合は、設定する。
       Console.WriteLine ("not exist .");
       perm.SharedAccessPolicies.Add("testpolicy", containerPolicy);
       blob.Container.SetPermissions(perm);
    }
    
    var sas = blob.GetSharedAccessSignature(new SharedAccessPolicy(), "testpolicy");
    Console.WriteLine (blob.Uri.AbsoluteUri + sas);

ポリシーの不一致

コンテナと、Blobでポリシーが異なると以下のようなエラーがでる。

<Error>
  <Code>AuthenticationFailed</Code> 
  <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:0e85654a-adee-4b66-8407-47529caeb43e Time:2010-11-17T15:04:45.6358077Z</Message> 
  <AuthenticationErrorDetail>Access policy fields can be associated with signature or SAS identifier but not both</AuthenticationErrorDetail> 
</Error>

とりあえず眠いので本日はここまでで、もうちょっと続くかも。