13
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Azure Storageへのアクセス方法 【Shared Access Signatures (SAS)】

Last updated at Posted at 2016-12-01

Azure SAS(Shared Access Signatures)とは

協力会社や他ベンダーなどの外部のパートナーに対して安全に自前のAzure Storageにアクセスさせるために払い出す制限付きキーのことです。トークンを利用するAzure DocumentDBとは異なり、Azure Storageに対してはSASの利用が提案されています。Azure Storageバージョン"2015-04-05"以降、特定のコンテナ内にのみ効果がある「サービスSAS」と、コンテナ自体も操作ができるようなAdmin向けの「アカウントSAS」という2種類のSASが用意されています。

本記事の概要

Microsoft社のチュートリアルは謎構造となっている場合がありまして、御多分に洩れずAzure Storage資料も謎構造となっています。そのため本記事では改めて一通り動かしてドキュメント化しています。特にAzure Storageへのセキュアなアクセス方法について調査し、実際に動かした流れをまとめています。本記事では主に「サービスSAS」を利用します。Microsoftより提供されているドキュメントは以下です。本記事はメンテされずに古い資料となってしまうことが予想されるので、必ず、大元の最新版の資料を御参照ください。

Using Shared Access Signatures (SAS)
https://docs.microsoft.com/en-us/azure/storage/storage-dotnet-shared-access-signature-part-1

段階を踏んで上記の記事に到達するためのサンプルプログラムなども記載してあります。
結論から言えば、謎構造の正体は「Azure Storage自体のアップデートによるバージョン毎の差異」によるものでした。
まずはバージョン関係の資料をサッと読んで頂き、上手くプログラム等が動かない場合には当該資料に立ち戻って頂ければ良いかと存じます。
2016年11月時点での最新バージョンは"2015-12-11"です。

https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/versioning-for-the-azure-storage-services

目次

前提

  • すでにAzureアカウントを作成済みであること
  • すでに課金アカウント設定、リソースグループの作成など済ませており、ストレージアカウントを作成可能な状態であること

ストレージアカウントとコンテナーの作成、BLOB Storageにデータ保存

ササっと作成します。

SAS001.png

こんな右端にクイックスタートが…。
SAS002.png

AWSで用意されているサンプルデータを利用してみます。BLOBにアップロードしてください。アクセスポリシーをコンテナーにしておくと公開、プライベートにすれば非公開です。

AWS Documentation » Amazon DynamoDB » 入門ガイド
http://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/gettingstartedguide/GettingStarted.NodeJs.02.html

2016年11月時点で3.7MBありました。
下記の画像の右側の「URL」をコピーして、ブラウザからアクセスすると、公開状態の場合は保存したファイルの内容が表示されます。
SAS003R.png

非公開の場合は以下のエラーメッセージが表示されているかと思います。
The specified resource does not exist.

ちなみに、誰でも使えるGUIのツールとして以下の純正 MicrosoftAzureストレージエクスプローラー がある模様。車輪の再開発は不要ですね。
http://storageexplorer.com/

※以下から、自力で捻り込んでURIを組み立てる方法と、ツールを使ってURIを得る方法を記載します。
※100%ツールを使った方が早くて簡単なので、ツールを使った方が良いです。
http://qiita.com/snomoto/items/c2793866dee81b4718e9#ツールで超簡単にsasを払い出す方法

#1.PHPでアクセス(without SAS)

AzureDocumentが思ったより不親切な感じなので、githubにあるREADMEを読みながら進めます。

https://github.com/Azure/azure-sdk-for-php

VMの用意

ベースとなるVMはなんでも良いのですが、GCE(CentOS7)を使ってみます。

Apache webサーバのインストール

  • 何はともあれApache webサーバをインストールします。
    $sudo yum install httpd httpd-devel -y

  • "httpd -v"でバージョンを確認します。2.4系。

terminal
$httpd -v
Server version: Apache/2.4.6 (CentOS)  
Server built:   Jul 18 2016 15:30:14  

その他必要なパッケージのインストール

  • git,zip,unzipもインストールします。(全部sudo使うの?と思った方がいるかも知れませんが、流れが確認できたらこのVMは潰しましょう)
    $sudo yum install -y git zip unzip

PHP7系のインストール

  • PHPに関しては7系を入れたいので、EPELから入れていきます。
$sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm```

- PHPの7系を探してみます。2016年11月時点でphp71が最新のようです。

```html:terminal
$sudo yum search --enablerepo=remi php-devel
php-devel.x86_64 : Files needed for building PHP extensions
php54-php-devel.x86_64 : Files needed for building PHP extensions
php55-php-devel.x86_64 : Files needed for building PHP extensions
php56-php-devel.x86_64 : Files needed for building PHP extensions
php70-php-devel.x86_64 : Files needed for building PHP extensions
php71-php-devel.x86_64 : Files needed for building PHP extensions
  • php71をインストールします。

$sudo yum install --enablerepo=remi -y php71-php php71-php-devel php71-php-mbstring php71-php-pdo php71-php-pecl php71-php-pdo php71-php-pear

  • PHPが入ったか確認します。
terminal
$php71 -v
PHP 7.1.0RC6 (cli) (built: Nov  9 2016 08:59:00) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.1.0-dev, Copyright (c) 1998-2016 Zend Technologies
  • Apache webサーバと連携できているか確認します。
    /var/www/html に移動し、index.phpファイルを作成しましょう。
$sudo vi index.php```

```php:index.php
<?php

phpinfo();

  • ブラウザ経由でアクセスしてみます。これでPHPはOK。
php71.png

Composerのインストール

  • Composerをインストールします。
    公式ドキュメントに沿ってインストールすればOKです。

https://getcomposer.org/download/

terminal
$sudo php71 -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
$sudo php71 -r "if (hash_file('SHA384', 'composer-setup.php') === '※※期限ありのハッシュ値が入ります。ページ更新で最新版が表示されます
$sudo php71 composer-setup.php
$sudo php71 -r "unlink('composer-setup.php');"
  • Composerがインストールできたか確認します。
terminal
$ php71 composer.phar
   ______
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                    /_/
Composer version 1.2.2 2016-11-03 17:43:15

VMの準備はここまで。
【2016年12月】一発スクリプトを追記しました。
$ sudo sh ./LAMP71.sh

LAMP71.sh
echo "Author: snomoto (http://qiita.com/snomoto)"
echo "for CentOS7"

## Apache

sudo yum install -y git wget zip unzip
sudo yum install -y httpd httpd-devel

sudo systemctl start httpd
sudo systemctl stop httpd

## MariaDB

cat << EOS |sudo tee /etc/yum.repos.d/MariaDB.repo
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.1/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
EOS

sudo yum install -y MariaDB-server MariaDB-client

sudo systemctl start mariadb
sudo systemctl stop mariadb

## PHP71

sudo yum install -y epel-release
sudo yum install -y epel-release
sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
sudo yum install --enablerepo=remi -y php71-php php71-php-devel php71-php-mbstring php71-php-pdo php71-php-pecl php71-php-pdo php71-php-pear

## Composer

php71 -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php71 composer-setup.php
php71 -r "unlink('composer-setup.php');"
php71 composer.phar

## ReSTART
sudo systemctl start httpd
sudo systemctl start mariadb

Azure SDK for PHPのインストール

上述のgithubリンクを参照してください。

https://github.com/Azure/azure-sdk-for-php

$sudo git clone https://github.com/Azure/azure-sdk-for-php.git

  • /var/www/html配下にcomposer.jsonファイル作成します。
    $sudo vi composer.json
composer.json
{
    "require": {        
        "microsoft/windowsazure": "^0.4"
    }  
}
  • Composerを利用してプロジェクト整備します。
terminal
$sudo php71 composer.phar install

  • 公式docからサンプルコードをコピペして動かしてみます。

https://docs.microsoft.com/en-us/azure/storage/storage-php-how-to-use-blobs#list-the-blobs-in-a-container

ん?
Azureの自分のアカウントへの紐つけ、エンドポイント設定などがサンプルに書いてないですね。
stackoverflowに答えがありました。

http://stackoverflow.com/questions/13930880/connect-to-azure-blob-through-azure-website-with-php

$connectionString として設定せよと。
そして公式docに書式が書いてありました。
DefaultEndpointsProtocol=[http|https];AccountName=[yourAccount];AccountKey=[yourKey]

ここのyourAccountと、yourKeyはどこで見つけられるんだ?と思っていたら、やはりstackoverflowに答えがありました。

http://stackoverflow.com/questions/6985921/where-can-i-find-my-azure-account-name-and-account-key

Azureポータルから、アクセスキーを開いてみましょう。ここに「アカウント」と「キー」があります。
SAS004.png

また、自分が作成したコンテナーのIDを確認してください。
サンプルコードを以下のように、自分の環境に沿って3点書き換えます。(①、②、③としてあります。)

listblob.php
<?php


    require_once 'vendor/autoload.php';

    use WindowsAzure\Common\ServicesBuilder;
    use MicrosoftAzure\Storage\Common\ServiceException;

    //Endpoint
    $connectionString = "DefaultEndpointsProtocol=http;AccountName=①ストレージアカウント;AccountKey=②プライマリキー";

    // Create blob REST proxy.
    $blobRestProxy = ServicesBuilder::getInstance()->createBlobService($connectionString);


    try    {
        // List blobs.
        $blob_list = $blobRestProxy->listBlobs("③自分が作ったコンテナーのID");
        $blobs = $blob_list->getBlobs();

        foreach($blobs as $blob)
        {
            echo $blob->getName().": ".$blob->getUrl()."<br />";
        }
    }
    catch(ServiceException $e){
        // Handle exception based on error codes and messages.
        // Error codes and messages are here:
        // http://msdn.microsoft.com/library/azure/dd179439.aspx
        $code = $e->getCode();
        $error_message = $e->getMessage();
        echo $code.": ".$error_message."<br />";
    }


  • Webブラウザか、コマンドで挙動を確認してみる。
    Webブラウザからphpファイルにアクセスしても良いですし、コマンドで動かしても良いです。確認してみましょう。
    `$php71 listblob.php'

この記事の上の方でコンテナーの中に保存した、moviedata.jsonが保存されていることが表示されればOKです。

terminal
$ php71 listblob.php 
moviedata.json: http://自分のストレージアカウント.blob.core.windows.net/gyaoazuresastestblob/moviedata.json<br />

Azure Storageからダウンロード

引き続き「アカウントキー」を利用してアクセスします。
ダウンロードするサンプルコードを編集します。ダウンロード対象は自分で保存したmoviedata.jsonだったり、上記のリストアップ用サンプルコードの結果から読み替えてください。

getblob.php
<?php

    require_once 'vendor/autoload.php';

    use WindowsAzure\Common\ServicesBuilder;
    use MicrosoftAzure\Storage\Common\ServiceException;

    //Endpoint
    $connectionString = "DefaultEndpointsProtocol=http;AccountName=自分のストレージアカウント;AccountKey=プライマリキー";


    // Create blob REST proxy.
    $blobRestProxy = ServicesBuilder::getInstance()->createBlobService($connectionString);


    try    {
        // Get blob.
        $blob = $blobRestProxy->getBlob("自分が作ったコンテナーのID", "moviedata.json");
        fpassthru($blob->getContentStream());
    }
    catch(ServiceException $e){
        // Handle exception based on error codes and messages.
        // Error codes and messages are here:
        // http://msdn.microsoft.com/library/azure/dd179439.aspx
        $code = $e->getCode();
        $error_message = $e->getMessage();
        echo $code.": ".$error_message."<br />";
    }

  • 実行すると fpassthru によりターミナル上に書き出されるだけですが、下記のコマンドによりテキストとして保存できます。
    $sudo php71 getblob.php | sudo tee -a ./moviedata.txt

Azure Storageにアップロード

基本的にはlistblob.phpのコピペから作成してます。
ダウンロードしたばかりのファイルを、別名で保存しています。

upblob.php
<?php
    require_once 'vendor/autoload.php';

    use WindowsAzure\Common\ServicesBuilder;
    use MicrosoftAzure\Storage\Common\ServiceException;

    //Endpoint
    $connectionString = "DefaultEndpointsProtocol=http;AccountName=ストレージアカウント;AccountKey=プライマリキー";

    // Create blob REST proxy.
    $blobRestProxy = ServicesBuilder::getInstance()->createBlobService($connectionString);

    $content = fopen("/var/www/html/moviedata.txt", "r");
    $blob_name = "movieuploadeddata";

    try    {
        //Upload blob
        $blobRestProxy->createBlockBlob("自分が作ったコンテナーのID", $blob_name, $content);
    }
    catch(ServiceException $e){
        // Handle exception based on error codes and messages.
        // Error codes and messages are here:
        // http://msdn.microsoft.com/library/azure/dd179439.aspx
        $code = $e->getCode();
        $error_message = $e->getMessage();
        echo $code.": ".$error_message."<br />";
    }

ここまでで、SASではなく「アクセスキー」を利用して、Azure Storageからデータをダウンロード/アップロード出来るようになりました。

#1-1.PHPでアクセス(with SAS)

アクセスキーではなく、SASを利用してデータをダウンロード/アップロードするようにしたいと思います。

MicrosoftAzureストレージエクスプローラーを利用すると、簡単にSASを払い出せます。

ちなみに、誰でも使えるGUIのツールとして以下の純正 MicrosoftAzureストレージエクスプローラー がある模様。車輪の再開発は不要ですね。
http://storageexplorer.com/

しかし該当ツールが弊社の社内利用可能ソフトウェア一覧に無い!OMG!
自力で捻り込んで払い出します。

自力でSASを払い出す方法

サンプルとなるSASを見てみます。

https://docs.microsoft.com/en-us/azure/storage/storage-dotnet-shared-access-signature-part-1#examples-of-sas-uris

https://myaccount.blob.core.windows.net/sascontainer/sasblob.txt?sv=2015-04-05&st=2015-04-29T22%3A18%3A26Z&se=2015-04-30T02%3A23%3A26Z&sr=b&sp=rw&sip=168.1.5.60-168.1.5.70&spr=https&sig=Z%2FRHIX5Xcg0Mq2rqI3OlWTjEg2tYkboXr1P9ZUXDtkk%3D
  • 各パラメータを紐解く
    頭のBLOBのURLについてはGUI画面から取得可能。
    https://ストレージアカウント.blob.core.windows.net/コンテナーID/moviedata.json

パラメータの意味については、別のドキュメントを見た方がわかりやすいかもです。。

https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/constructing-a-service-sas

サンプル 概要 書き換え例
sv=2015-04-05 Azure Strageのバージョン† sv=2015-12-11
st=2015-04-29T22%3A18%3A26Z Unicode化したSASの有効開始時刻(UTC)†† (省略可能)
se=2015-04-30T02%3A23%3A26Z Unicode化したSASの有効期限 se=2016-12-31T00%3A00%3A00Z
sr=b 対象リソース。bはBLOB,cはコンテナ sr=c
sp=rw 権限。Read&Write sp=rw
sip=168.1.5.60-168.1.5.70 アクセス許可IP範囲 (省略可能)
spr=https 許可プロトコル spr=https,http
sig=Z%2FRHI...kk%3D 署名 次のパートで説明

† Azure Storageのバージョン"2015-04-05"については以下。
https://docs.microsoft.com/ja-jp/rest/api/storageservices/fileservices/version-2015-04-05

†† Unicodeで「%3A」は「:」を意味する。T22%3A18%3A26Zは「T22:18:26Z」となる

sigパラメータの作成

サンプルURIの記載あるページには以下のような説明があります。

"Used to authenticate access to the blob. The signature is an HMAC computed over a string-to-sign and key using the SHA256 algorithm, and then encoded using Base64 encoding."
https://docs.microsoft.com/en-us/azure/storage/storage-dotnet-shared-access-signature-part-1#examples-of-sas-uris

各パラメータを説明しているページには以下のような説明があります。

"The string-to-sign is a unique string constructed from the fields that must be verified in order to authenticate the request. The signature is an HMAC computed over the string-to-sign and key using the SHA256 algorithm, and then encoded using Base64 encoding.

Constructing the Signature String
To construct the signature string of a shared access signature, first construct the string-to-sign from the fields comprising the request, then encode the string as UTF-8 and compute the signature using the HMAC-SHA256 algorithm. Note that fields included in the string-to-sign must be URL-decoded."
https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/constructing-a-service-sas#specifying-the-signature

つまり。
SHA256アルゴリズムを使いつつ string-to-signとkey をHMACに通し、そしてそれをBase64円コードしたものがSignatureだ。ということになるのですが、意味がわからないですね。各パラメータを説明しているページにおいてはUTF-8でエンコードせよ、とも書いてあります。
別のドキュメントに正解が書いてありました。

https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/service-sas-examples

※このページのサンプルコード、versionの指定が適当のようなので読み替え能力が必要そうです。

sampleSig
signedstart=2013-08-16  
signedexpiry=2013-08-17  
signedresource=c  
signedpermissions=r  
signature=dD80ihBh5jfNpymO5Hg1IdiJIEvHcJpCMiCMnN/RnbI=  
signedidentifier=YWJjZGVmZw==  
signedversion=2013-08-15  
responsecontent-disposition=file; attachment  
responsecontent-type=binary


StringToSign = r + \n   
               2013-08-16 + \n  
               2013-08-17 + \n  
               /myaccount/pictures + \n  
               YWJjZGVmZw== + \n  
               2013-08-15 + \n  
               + \n    
               file; attachment + \n  
               + \n  
               + \n  
               binary  

HMAC-SHA256(URL.Decode(UTF8.Encode(StringToSign))) = a39+YozJhGp6miujGymjRpN8tsrQfLo9Z3i8IRyIpnQ=

唐突に出てくる"/myaccount/pictures"。これは"canonicalizedResource"を意味する模様。

https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/constructing-a-service-sas#see-also

sample$StringToSign
$signedexpiry="2016-12-31T01:01:01Z";
$signedresource="c";  
$signedpermissions="rwl";  
$signedversion="2015-12-11";

$canonicalizedresource = '/blob/ストレージアカウント名/作成したコンテナーID'

$StringToSign = $signedpermissions."\n".  
                ''."\n".  
                $signedexpiry."\n".  
                $canonicalizedresource."\n". 
                ''."\n".
                ''."\n".  
                ''."\n".  
                $signedversion."\n".  
                ''."\n".
                ''."\n".  
                ''."\n". 
                ''."\n".
                '';

  • 改めて各パラメータを説明しているページを見直すと、signatureの記載が無い。また、sampleSigをよくよく見て見るとsignatureの値を使っていない。。。

https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/constructing-a-service-sas#specifying-the-signature

  • signedidentifierについてはこちら。

https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/constructing-a-service-sas#specifying-the-signed-identifier

  • hash_hmacで利用するキーはアクセスキーをBase64_decodeしたものらしい。
    "Base64_decode azure sas"で検索すると 最近のIoT系のドキュメントが出てくるのだが、最初に発見した人はどうやったのだろう。。。

https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-devguide-security

  • sigを払い出しつつ、URIを組み立てます。

まず、特に何もせずにBlobへアクセスすると、以下のようなエラーメッセージが出ると思います。

https://自分のストレージ.blob.core.windows.net/コンテナーID/moviedata.json
error-message
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
<Code>ResourceNotFound</Code>
<Message>
The specified resource does not exist. RequestId:a380b3c7-0001-000d-7637-4a18a7000000 Time:2016-11-29T11:53:05.8184599Z
</Message>
</Error>

PHPwithSASサンプルコード

以下のサンプルコードで、sigを生成しつつ、moviedata.jsonの中身にアクセスするURIを表示します。
大切なお知らせ:このサンプルコードは"2015-12-11"向けのものです

sampleFor20151211.php
<?php
/** 
  * Sample code, for Azure Storage Version 2015-12-11.
  * @author snomoto
*/

$key = 'accessKey'; //copy&paste from Azure Portal

$azureStorageAccount = "azureStorageAccount";  //copy&paste from Azure Portal
$azureContainerID    = "azureContainerID";     //copy&paste from Azure Portal
$azureBlobName       = "moviedata.json";
$azureURL = "https://".$azureStorageAccount.".blob.core.windows.net/".$azureContainerID."/".$azureBlobName."?";

$sasEnd = "2016-12-03T19:43:58Z"; //sample.
$sasIP  = "xxx.xxx.xxx.xxx";      //your IP address

$sigStr20151211 =        "rwl"."\n". //permission.Read,Write,List
                         ""."\n".    //start
                         $sasEnd."\n".    //end
                         "/blob/".$azureStorageAccount."/".$azureContainerID."/".$azureBlobName."\n". //canonicalizedresource
                         ""."\n".    //identifier
                         $sasIP."\n".   //IP address
                         "https,http"."\n".     //protocol
                         "2015-12-11"."\n".     //VERSION
                         ""."\n".    //rscc
                         ""."\n".    //rscd
                         ""."\n".    //rsce
                         ""."\n".    //rscl
                         "";         //rsct

$sig20151211 = base64_encode(
     hash_hmac('sha256', urldecode(utf8_encode($sigStr20151211)), base64_decode($key), true)
     );

$URI = $azureURL."se=".urlencode($sasEnd)."&sr=b&sp=rwl&sip=".$sasIP."&spr=https,http&sig=".urlencode($sig20151211)."&sv=2015-12-11";

echo $URI."\n";

ドキュメントによってはsipとsprが"Optional"だとあるのですが、バージョン資料には"must"と記載あります。入れておいたほうがよさそうです。

When constructing the string-to-sign for an account SAS or a service SAS in version 2015-04-05, you must include the signed IP and signed protocol in the signature string.
https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/version-2015-04-05

★謎

Beginning with version 2015-04-05, the optional signed IP (sip) field
https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/constructing-a-service-sas#specifying-ip-address-or-ip-range

ツールで超簡単にSASを払い出す方法

会社環境ではインストールできないので、
個人で利用しているAzureアカウントとPCで、Microsoft Azure Storage Explorerを利用してみます。

  • ログインできたら、自分が作ったコンテナーを右クリックし、"Get Shared Access Signatures"をクリックしてください。
azuretool.png
  • SASの有効期間と、権限を設定します。
sastool001.png
  • SASが作成されました。上の方でかなり捻り込んだ自力作業が、2分くらいで完了しました。。
sastool002.png

ブラウザから叩く場合は、'comp=list&restype=container'というパラメータを追加すればアクセスできます。

http://stackoverflow.com/questions/25038429/azure-shared-access-signature-signature-did-not-match

EOF

あまりに長くなったので、PART分けすることにしました・・・
NEXT: please check bellow link...

13
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?