ここでは、CDPデザインパターンに以下のようなパターンがありました。
CDP:Private Cache Distributionパターン
このパターンによると、CloudFrontに対して署名付きURLを送信することで、アクセス条件を制限することができるようです。今回はこれを使ってみたいと思います。
S3バケットの作成
まず、S3バケットをひとつ用意して適当にファイルをアップします。
<html> <head> <title>private</title> </head> <body> <h1>This is Private Contents</h1> </body> </html>
CloudFrontディストリビューションの作成
次にCloudFrontでディストリビューションを追加します。「Create new Distribution」をクリックします。
すると、以下のようにディストリビューションの設定画面が表示されるので、以下のように入力します。
Origin Settings
- Origin Domain Name:先ほど追加したS3バケットを選択
- Origin ID:自動で設定されるので今回はこのまま
- Restrict Bucket Access:Yes(YesにするとCloudFrontからしかS3にアクセスできないようにできます)
- Origin Access Identity:Create a New Identity(S3にアクセスするこのCloudFrontの接続子です)
- Comment:コメントです
- Grant Read Permissions on Bucket:Yes(S3に対してCloudFrontからのBucketPolicyを設定します。)
Default Cache Behavior Settings
- PathPattern:Default
- View Protocol Policy:HTTP and HTTPS
- Object Caching:Use Origin Cache Headers(Customizeにすると次の3項目が設定出来ます。)
- Minimum TTL:0(最短TTL、デフォルト24時間)
- Forward Cookies:None(キャッシュURLにCookieを含めることができます)
- Whitelist Cookies:Forward Cookiesを有効にすると、Whitelist内のCookieだけをオリジンに転送することができます。
- Forward Query Strings:No(YesにするとQueryParameter付きURLでキャッシュできます)
- Restrict View Access:Yes(署名付きURLでしかアクセスできないようにします)
- Trusted Signers:Self (Specify Accoutsにチェックを入れると別アカウントの署名も有効になります。)
Distribution Settings
ここの項目はひとまずデフォルトのままにしておきます。
ここまで設定できたら「Create Distribution」をクリックします。
すると以下のように、CloudFrontをprivateアクセスするために必要な次の手順が表示されます。
ざっくり訳すと以下のような内容です。
Step1:S3バケットへのアクセス制限
- ディストリビューションを新規作成したままS3の設定をいじっていないのであれば、S3バケットはCloudFrontとバケットオーナーからしかアクセスを受け付けないように正しく設定されています。
Step2:署名付きURL
- 信頼された署名者用にCloudFrontのキーペアを作成します。
- 署名付きURLを作成するには、コーディングするかサードパーティツールを使用する必要があります。
- ディストリビューションへ信頼された署名者を追加します。
どうやら自動でS3のパーミッションが変更されたようです。
S3のパーミッションを見てみます。
S3のバケットのPermissionsからEdit Bucket Policyをクリックします。
すると以下のように設定されています。
{ "Version": "2008-10-17", "Id": "PolicyForCloudFrontPrivateContent", "Statement": [ { "Sid": "1", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E366VCXL4Q6CB9" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::memorycraft-private/*" } ] }
Cloud Front Origin Access Identityとして設定されています。
また、作成されたディストリビューションを確認すると、以下のように無事登録されているのがわかります。
ディストリビューションのホスト名は
dapubd7a26puj.cloudfront.net
となっています。
この段階でブラウザでアクセスすると以下のようになります。
これは、すでに署名付きURLしか受け付けないため、通常のURLではエラーになるためです。
署名付きURLの作成
次に署名付きURLを作成してみたいと思います。
まず、署名をするためのCloudFront用のキーペアを取得します。
AWSの証明書のページで「一対の鍵」のタブをクリックします。
CloudFrontの一対の鍵という項目があるので、「新しい一対の鍵を作成する」をクリックします。
作成完了のモーダルウィンドウが表示されるので、確認して閉じます。
すると、「一対の鍵」にCloudFront用のキーペアが追加されているのがわかります。
「一対の鍵ID」というキーペアIDが表示され、下にダウンロードリンクが現れます。
「(公開鍵をダウンロード)」をクリックすると、rsa-キーペアID.pem, pk-キーペアID.pemというファイルがダウンロードされます。
どこか適当な環境にSDKをダウンロードします。
ここではPHPのSDKを利用します。
また、keysというディレクトリを作りpk-キーペアID.pemを配置します。
$tree -L 2 . . ├── app │ ├── key.php │ ├── sdk -> sdk-1.6.0 │ ├── sdk-1.6.0 │ └── sdk-latest.zip └── keys └── pk-キーペアID.pem
そして、以下のようにAmazonCloudFrontクラスを使って署名付きURLを生成します。
cat key.php <?php require_once('sdk/sdk.class.php'); date_default_timezone_set('Asia/Tokyo'); //CloudFrontクラスを初期化 $cf = new AmazonCloudFront(array('key'=>'通常のAWSアクセスキー', 'secret'=>'通常のAWSシークレットキー')); //キーペアIDをセット $cf->set_keypair_id('CloudFrontのキーペアID'); //配置した鍵ファイルの中身をセット $cf->set_private_key(file_get_contents(dirname(__FILE__).'/../keys/pk-キーペアID.pem')); //index.htmlのURLを期限付きで取得します(expireはstrtotimeが解釈できる文字列かUnixTimeならOK) $url = $cf->get_private_object_url('dapubd7a26puj.cloudfront.net', 'index.html', strtotime('+5 minutes')); echo $url;
確認
これを実行します。
# php app/key.php http://dapubd7a26puj.cloudfront.net/index.html?Expires=1360671363&Key-Pair-Id=APKAIGNAXKEEXGUYEZ5A&Signature=UQantZ1gIp5-mm6d6Lb-HKQr1jxKDRW2NfFyC-E2dDx33ekBbFjLKmO6vHCOhv7liBrfcaTFc7~yKZCd4P1tfZE4TltU6TilhnAUFT6mCC-Db-dmnrU7XbcWSjt29~yOVVhLTv5RoPtIjoW~iPFR2BTyoM~4vlV40y9ypbO5M1U_
URLが出力されました。
これをつかってアクセスしてみます。
表示されました!
先ほどのコードでは5分後がアクセス期限でした。
5分以上経過してからアクセスすると、、、
ちゃんとアクセス拒否になりました。
おまけ
ユーザーがアクセスするごとにURLの期限を設定したい場合があります。
その場合は、以下のように元のURLにクエリーパラメータを付与してあげるといいかもしれません。
$url = $cf->get_private_object_url('dapubd7a26puj.cloudfront.net', 'index.html?u='.session_id(), strtotime('+5 minutes'));
以上の手順の多くはAWSのAPI経由でも設定可能です。必要に応じてプログラムで設定てもよいかもしれません。
また、署名の仕方や署名ポリシーにはいくつかパターンがあるため、機会があればもっといろいろな方法を試してみたいと思います。