LoginSignup
11
10

More than 5 years have passed since last update.

Python で Amazon CloudFront の Signed URL を発行する

Posted at

CloudFront x S3 => 期限付き URL

facebook や flickr などのように、一部ユーザにだけ画像を見せたいというケース、ありますよね。こういうサービスでは、画像に対して期限付きの URL を発行するのが一般的のようです。Amazon CloudFront と Amazon S3 を使うと、こんな形の期限付き URL を発行できます。

http://d3iwlid5dsmdb3.cloudfront.net/_default_san.png?Expires=1354332636&Signature=EWVDLqfSRDJFlOazy9ruQV96xPravIFbiUq9GOsTVaL0Uhj3u6LEWXoM3042rWddnc4+CLop/mBCY5P/WcMyDcR5LGFfxEvCltsLYXtjCR+Djnh0WEsp+ogWlGjYAn6eZNtjUfl9FlMbiC6tn7Ehs9oMJu+EaYgpGM6aSlyQ88A=&Key-Pair-Id=APKAJ4YNPASFVCNBXK3A

CloudFront と S3 のつなぎ込みや、鍵ペアの発行などの手順は公式ドキュメントの Serving Private Content through CloudFront に書いてあります。そして最終的な URL の生成についてのコードが Perl、PHP、C#(.NET Framework)、Java で書かれているのですが、Python がありません。これでは仕事になりませんね。

tlslite を使って Signed URL を発行する

Python で AWS といえば boto……なのですが、今回は違った方法を使います。boto が駄目だった理由は後述します。

"python sign private key" で検索したところ、Signing a string with RSA private key on Google App Engine Python SDK がヒットしました。そこにはこう書いてありました。

The library tlslite included in the gdata python library is a good option.

ふむふむ、tlslite がいいらしい。さっそくインストールしてみましょう。

(venv)rch850mba:Desktop rch850$ pip install tlslite
Downloading/unpacking tlslite
  Downloading tlslite-0.4.3.tar.gz (562Kb): 562Kb downloaded
  Running setup.py egg_info for package tlslite

Installing collected packages: tlslite
  Running setup.py install for tlslite
    changing mode of build/scripts-2.7/tls.py from 644 to 755
    changing mode of build/scripts-2.7/tlsdb.py from 644 to 755

    changing mode of /Users/rch850/Desktop/cloudfront/venv/bin/tls.py to 755
    changing mode of /Users/rch850/Desktop/cloudfront/venv/bin/tlsdb.py to 755
Successfully installed tlslite
Cleaning up...

そして例を見ながらコーディング。

from tlslite.utils import keyfactory
from base64 import b64encode
import time

url = "http://d3iwlid5dsmdb3.cloudfront.net/_default_san.png"
expires = int(time.time() + 60)
privkey_file = "pk-APKAJ4YNPASFVCNBXK3A-cloudfront.pem"
key_pair_id = "APKAJ4YNPASFVCNBXK3A"

policy = '{"Statement":[{"Resource":"%s","Condition":{"DateLessThan":{"AWS:EpochTime":%d}}}]}' % (url, expires)
privkey = keyfactory.parsePrivateKey(open(privkey_file).read())            
print '%s?Expires=%d&Signature=%s&Key-Pair-Id=%s' % (url, expires, b64encode(privkey.hashAndSign(policy)), key_pair_id)

これでできた!!!はずです!!!!このあたりの調査に数日かけたので、感嘆符が多くなるのは仕方ないです!!!!!

boto が駄目だった理由

boto で一応 CloudFront を使えそうだったので、適当に書いてみたところ……

import boto

c = boto.connect_cloudfront()
dist = c.get_all_distributions()[0].get_distribution()
dist.create_signed_url("http://d3iwlid5dsmdb3.cloudfront.net/apple-touch-icon.png", "APKAJ4YNPASFVCNBXK3A", expire_time=time.time() + 60, private_key_file="./pk-APKAJ4YNPASFVCNBXK3A-cloudfront.pem")

すると、以下のエラーが。

NotImplementedError: Boto depends on the python M2Crypto library to generate signed URLs for CloudFront

M2Crypto が要るとのこと。インストールしてみる。

pip install M2crypto
(略)
error: command 'swig' failed with exit status 1

swig コマンドが無くてインストールできないとのことです。そこまでして M2Crypto に頼るのは嫌だなぁ、ということで、紆余曲折を経て tlslite にたどり着きました。boto が M2Crypto を使うことになった経緯はこちら

インストールのしやすさ以外だと M2Crypto と tlslite どっちが優れてるんだろう?

調査にあたって参考にしたサイト

11
10
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
11
10