S3 見習い兼 PHP と Ruby 初心者のかっぱ(@inokara)です。

はじめに

既にご存知の方もいらっしゃると思いますが、Amazon S3 の各バケットに保存されているコンテンツ(オブジェクト)に期限をつけてアクセスさせることが出来る機能(以下、「期限付き URL 生成機能」)があります。これは一時的に一部の方にだけファイルをダウンロードさせたい時等に非常に便利な機能だと思います。

この期限付きの URL 生成方法について AWS SDK for PHP と AWS SDK for Ruby の二種類を利用した手順を簡単にまとめてみたいと思います。

尚、上記のドキュメントでは Pre-Signed URL(事前署名付き URL)とありますが、本記事はタイトルを除いて、全編を通して期限付き URL と呼びたいと思います。

制限

いきなり制限で恐縮ですが、この期限付き URL 生成機能は SDK でのみ利用可能です。尚、今回利用する AWS SDK for PHP と AWS SDK for Ruby のドキュメントは下記の通りです。

必要に応じて見ましょう。

やってみよう

まずは AWS SDK for PHP を使って期限付き URL 生成機能を使ってみたいと思います。

準備

AWS SDK for PHP のインストール(Composer を使う方法)

こちら を参考にして Composer というツールを利用して AWS SDK for PHP をインストールします。尚、インストールした環境は下記の通りです。

  • MacOS X 10.9 Marvericks
  • PHP 5.4.24

まずは適当なディレクトリを作成しましょう。

mkdir -p ~/aws/

次に composer.json という Composer が利用するプロジェクトファイルを生成します。

cat << composer.json > EOT
{
    "require": {
        "aws/aws-sdk-php": "2.*"
    }
}
EOT

次に Composer のインストールを行います。

curl -sS https://getcomposer.org/installer | php

この時点で Composer のインストールが終了です。Composer のインストールが終わったら AWS SDK for PHP のインストールです。

php composer.phar install

正常にインストールが終了した場合には以下のようなディレクトリ構成となっている(はず)です。

.
├── composer.json
├── composer.lock
├── composer.phar
└── vendor

1 directory, 4 filesction_requests

上記のようになっていない場合には改めて手順や composer.json の中身等に間違いがないか確認しましょう。また、Composer を使わない AWS SDK for PHP のインストールについては以下のおまけをご確認ください。尚、インストールされる SDK のバージョンは 2.6.7 となります。これは composer.lock というファイルにて確認することが可能です。

    "packages": [
        {
            "name": "aws/aws-sdk-php",
            "version": "2.6.7",
            "source": {
                "type": "git",
                "url": "https://github.com/aws/aws-sdk-php.git",
 

バケットにファイルを置く

バケットを作って適当なファイルを置きましょう。既に対象のオブジェクトがある場合にはこのステップはすっ飛ばしましょう。

バケットを作成

20140707_aws-s3-url-with-expiration_001

オブジェクトをアップロード

20140707_aws-s3-url-with-expiration_002

こちらのロゴ画像を利用させて頂きアップロードしました。

20140707_aws-s3-url-with-expiration_003

この時点で既にエンドポイント(リンク)が生成されているのが判りますが、このリンクにアクセスしても…

20140707_aws-s3-url-with-expiration_004

アクセス出来ませんね。

期限付きの URL を生成してみる

では、先ほどアップロードしたファイルにアクセス出来るように期限付きの URL を生成してみましょう。

いきなりソースコード

先ほど SDK をインストールしたディレクトリと同じディレクトリに test.php というファイルを作成し、こちらを参考にして以下のようなコードを書きました。

 'AKxxxxxxxxxxxxxxxxxxxxxxxxx',
  'secret' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
);

use AwsS3S3Client;
$s3 = S3Client::factory($config);
$url = $s3->getObjectUrl("kappa-test", "fluentd.png", "1 minutes");

print $url;

見て判る通り…

  • key には AWS のアクセスキー
  • secret には AWS のシークレットアクセスキー
    をそれぞれ設定します。

次に getObjectUrl の引数に…

  • バケット名(kappa-test)
  • ファイル名(fluentd.png)
  • 期限(時間)(1 minutes)
    を指定します。

この test.php を以下のように実行します。

php test.php

実行すると…

20140707_aws-s3-url-with-expiration_005

上記のように長ったらしい URL が表示されますのでこの URL をコピーしてブラウザでアクセスしてみます。

20140707_aws-s3-url-with-expiration_006

おお、画像が表示されました。しばらくリロードを繰り返し続けると…

20140707_aws-s3-url-with-expiration_007

期限切れとなりアクセスが出来なくなりました。

2014-06-19T05:42:34Z

上記のように期限が切られていたことが判ります。

AWS SDK for Ruby でもやってみる

インストール

環境は以下のような環境でインストールします。

  • MacOS X 10.9 Marvericks
  • ruby 2.0.0p451

既に Ruby がインストールされていれば gem 一発です。

gem install aws-sdk --no-ri --no-rdoc -V

簡単ですね。

URL を生成する

こちらを参考にして以下のようなコードを書いてみました。

#!/usr/bin/env ruby

require 'aws-sdk'

AWS.config(
  :access_key_id => 'AKxxxxxxxxxxxxxxxxxxx',
  :secret_access_key => 'xxxxxxxxxxxxxxxxxxxxxxx',
)
obj = AWS::S3.new.buckets['kappa-test'].objects['fluentd.png']
print obj.url_for(:read, :expires => 5*60)

アクセスキーやシークレットアクセスキーが必要になるのは PHP 版と同様です。処理の流れとしては…

  • AWS::S3 クラスの bucket collection でバケットを object でファイル名を指定した上でオブジェクトを生成
  • オブジェクトの url_for メソッドで URL を生成
  • url_for メソッドで URL を生成する際に権限(:read)と期限(:expires)を引数として指定

このコードを test.rb というファイル名で作成して実行権限を与えてから以下のように実行します。

./test.rb

以下のように URL が生成されます。

20140707_aws-s3-url-with-expiration_008

生成された URL をブラウザで確認してみましょう。

20140707_aws-s3-url-with-expiration_009

ロゴが表示されました。しばらくリロード繰り返しているうちに…

20140707_aws-s3-url-with-expiration_010

アクセス出来なくなりました。

ちなみに Expires を修正すればなんとかなるんぢゃないかなと思った方、ご安心(お諦め)ください。Expires を巻き戻しても問題なくアクセス制限が掛かった状態でした。

まとめ

今回やったこと

  • PHP と Ruby 版の AWS SDK を利用して S3 にアップロードしたファイルにに期限付きの URL を設定してみました

意外に…

  • SDK さえ準備できれば簡単に期限付きの URL を生成することが出来ますね

おまけ

Amazon Linux で AWS SDK for PHP をインストールする

yum -y install php-amazon-sdk2

上記の場合には、バージョン 2.6.6 がインストールされます。また、

yum -y install php-amazon-sdk

の場合には、バージョン 1.6.2 がインストールされます。

おまけ(2)ファイルダウンロード中に期限が過ぎてしまった場合にどうなるの?

むむ確かに…

記事をアップした後に記事を読んで下さった方から…

大容量なデータで期限内にダウンロードできなかった場合でもセッションが生きていたら大丈夫なんですか?

という鋭い質問を頂きましたので試してみました。

実験くん

ざっくり手順

以下のような手順で実験を行いました。

  1. でっかいファイル(CentOS の iso ファイル)をアップロードしておく
  2. 期限を人間が操作出来るくらいのレベルで出来るかぎり短くして URL を発行する
  3. ファイルの転送を開始する
確認ポイント
  1. 期限が過ぎても最初のダウンロードは継続するのか?しないのか?
  2. 期限が切れた際の挙動
iso ファイルのアップ

20140707_aws-s3-url-with-expiration_011

結構デカイですね。

期限を 60 秒に設定

以下のようにスクリプトを修正してダウンロード期限を 60 秒間に設定します。

obj = AWS::S3.new.buckets['kappa-test'].objects['CentOS-6.5-x86_64-minimal.iso']
print obj.url_for(:read, :expires => 1*60)

スクリプトは AWS SDK for Ruby を利用します。

URL を発行
./test.rb

を実行して URL を発行します。

curl にてダウンロード開始

以下のようなダウンロードをあらかじめ用意しておいて…

#!/usr/bin/env bash

cd ~/tmp/
echo "start : `date`"
echo ""
curl --limit-rate 10K -k -o test.iso "$1"
echo ""
echo "end : `date`"

以下のように実行すると…

download.sh https://kappa-test.s3.amazonaws.com/CentOS-6.5-x86_64-minimal.iso?AWSAccessKeyId=AKxxxxxxxxxxxxxxxxxxxxxxxx&Expires=1403227984&Signature=tgND5F1dc9NGQDMRWS3Y3Gk%2B5iM%3D

ダウンロードが開始されます…。

20140707_aws-s3-url-with-expiration_012

開始後 60 秒を経過したころに…

ブラウザから同じ URL を叩くと…

20140707_aws-s3-url-with-expiration_013

それれでも最初にダウンロードを開始したセッションは…

20140707_aws-s3-url-with-expiration_014

実験のまとめ

  • ダウンロード中に期限が切れてもセッションは継続されてダウンロードは継続されます
  • 期限切れの後の新しいセッションに関しては従来どおりオブジェクトへのアクセスは制限されます

元記事はこちら