前提
当方では、Ploneを用いて動画(Video)をストリーミング再生させるプロダクトを公開しています。その際に、Ploneのユーザ情報(ログインユーザ情報)を元に、閲覧の制限をさせたいと考えました。ストリーミング動画のアクセス管理は非常に手間のかかることですが、AWS CloudFrontのサイン付きURL(signed url)機能を使うことで実現できます。
Ploneとの組合せで使用する際には、 c2.app.streamingaws を用いることで、ソースコードを書かずにセキュアに動画配信が可能です。
ここでは、 Python + boto を使って、サイン付きURLの生成方法及びVideoJSを用いたHTMLの書き方をまとめます。
必要な条件・情報
- Python 2.7 or 3.4 (botoに依存/他のバージョンでも可能かもしれないが試していない) (私は 2.7系のみで試した)
- boto (使用したのは、boto 2.36.0 (現状の最終バージョン) / 以前のバージョンでも機能すると思う)
- AWS アカウント (IAMユーザでも可能 / 適切な権限付は必要)
- CloudFront keyペア
- S3 及び CloudFront の設定 (別のエントリーを見て下さい)
- URL有効時間の決定 (ストリーミング動画再生の場合、動画の時間以上を設定する必要がある)
ここまで準備、決まったら実装するのみ。
サイン付きURLの生成
import time
from boto.cloudfront import CloudFrontConnection
from boto.cloudfront.distribution import Distribution
access_key_id = "YOUR_KEY_ID" # AWS (or IAM) アカウントのID
secret_access_key = "YOUR_SECRET_KEY" # AWS (or IAM) アカウントのシークレットキー
cloudfront_key_id = "CLOUD_FRONT_KEY_ID" # CloudFront のID
cloudfront_private_key_str = """XXXXXXXXXXXXX
""" # CloudFront の 秘密鍵 (-----BEGIN RSA PRIVATE KEY-----を含めて)
expire_time = int(time.time() + 3600) # 有効時間を3600秒 (1時間) に設定
conn = CloudFrontConnection(access_key_id, secret_access_key)
distribution = Distribution(connection=conn)
def get_signed_url(url, policy_url):
signed_url = distribution.create_signed_url(url=url,
keypair_id=cloudfront_key_id,
expire_time=expire_time,
policy_url=policy_url,
private_key_string=cloudfront_private_key_str)
return signed_url
if __name__ == '__main__:
url = ""
policy_url = ""
print get_signed_url(url, policy_url)
VideoJSでの表示
video.js を用いる場合、以下のように video
タグ や source
タグ を記述します。video.js でのHTMLの記述方法は以下のエントリーを参照してください。
画像の場合
form .create_url import get_signed_url
domain = "xxxx.cloudfront.net" # ClundFront の HTTP(S) の Domain
base_path = "video/" # 画像が保管されているS3上のPATH
img_id = "thumb.png" # 画像のファイル名
url = "https://" + domain + "/" + base_path + img_id
policy_url = "https://" + domain + "/" + base_path + "*"
signed_url = get_signed_url(url, policy_url)
<video id="video_1" class="video-js vjs-default-skin"
controls preload="auto" width="640" height="360"
poster="${signed_url}" <!-- 上記のsigned_urlを動的にはめる -->
data-setup='{}'>
<source src="" type="" />
</video>
RTMPの場合
form .create_url import get_signed_url
domain = "xxxx2.cloudfront.net" # ClundFront の RTMP の Domain
base_path = "video/" # 動画が保管されているS3上のPATH
video_id = "video.mp3" # 動画のファイル名
url = "rtmp://" + domain + "/cfx/st/&mp4:" + base_path + video_id
policy_path = "base_path + video_id # RTMPの場合はドメイン等を含まない
signed_url = get_signed_url(url, policy_path)
policy_path
には、 rtmp://を含むドメイン
等は含めない。
<source src="${signed_url}"
type='rtmp/mp4' />
HLSの場合
HLSの場合は、 m3u8
というメタデータファイルをCloudFront経由で取得し、メタデータファイルを動的に書きなおしたものを、HTTP(S)通信で渡す必要があります。
まずは、この m3u8
ファイルを自身のサーバにリクエストが来るようにHTMLを記載します。
<source src="http://MY_SERVER_DOMAIN/${signed_url}"
type="application/x-mpegURL" />
次に、 m3u8
を動的に生成する必要があります。
m3u8ファイルには、分割された動画ファイルのURL(m3u8と同じ階層ならファイル名のみ)が列挙されています。それらの動画ファイルのURLを、サイン付きURLに書き換えます。
m3u8ファイルはシンプルなテキストファイルなので、書き換えは容易です。以下のようにファイルを書き換え、何かしらで自身のサーバからHTTP(S)通信で提供します。
m3u8ファイルを取得するための signed_url
の取得。
form .create_url import get_signed_url
domain = "xxxx.cloudfront.net" # ClundFront の HTTP(S) の Domain
base_path = "video/" # 動画が保管されているS3上のPATH
meta_id = "index.m3u8" # 動画メタデータのファイル名
url = "https://" + domain + "/" + base_path + meta_id
policy_url = "https://" + domain + "/" + base_path + "*"
signed_url = get_signed_url(url, policy_url)
取得した、 signed_url
から、m3u8ファイルデータを取得し、以下の様なスクリプトで、データ内部を書き換え、HTTP(S)通信で提供します。
import urllib2
def _adding_param_for_m3u8(data, base_url, signed_param):
for li in data.split("\n"):
if not li.strip():
yield li
elif li.startswith("#"):
yield li
else:
yield base_url + "/" + li + "?" + signed_param
class View:
def render(self, signed_url):
"""
"""
sp_signed_url = signed_url.split("?", 1)
if len(sp_signed_url) < 2:
return None
base_url = sp_signed_url[0].rsplit("/", 1)[0]
signed_param = sp_signed_url[1]
m3u8_data = urllib2.urlopen(signed_url)
data_list = _adding_param_for_m3u8(m3u8_data.read(),
base_url, signed_param)
m3u8_data.close()
self.request.RESPONSE.setHeader('Content-Type', 'application/x-mpegURL')
return "\n".join(data_list)
関連コンテンツ
- AWS S3 + CloudFront で動画ストリーム
- iOS向けにAWS S3 + CloudFrontで動画ストリーム
- AWS CloudFrontでプライベートコンテンツを配信
- iOS対応ストリーミングをプライベート(制限付き)に対応
最後に
このエントリーは、Ploneに実装したプロダクトから、サイン付きURLを作る部分を抜き出し、VideoJSで表示させる部分の解説をしました。
部分的に記載ミスが残っている可能性があります。ミスについてはご指摘いただけたら幸いです。
著者関連Blog記事とあわせてお読みください。