もうコロナ収束しても出社する気がない streampack 木村です。

こういったご時世を反映してか、ライブ配信案件がかなり増加してきています。

HTTP ベースのストリーミングは基本、来るものは拒まずなので、何かで制限をかけてあげないといけないのですが、お手軽案として、CloudFront を利用した Signed Cookie (署名付き cookie)の簡単な例をご紹介します。

構成

使用するリソースは以下です。

  • MediaLive
  • MediaStore
  • S3
  • CloudFront

前提

  • MediaLive、MediaStore、S3、CloudFront については既に構築済みでストリーミングができる状態にあるところから開始します。
  • CloudFront には独自ドメインを設定しています。(タダで取得した streampack.ga

手順

それではさっそくまいりましょう。

CloudFront キーペアの作成

まずは CF のキーペアを作成します。 ローカルで作る方法もありますが、AWS コンソールから発行することもできます。(要 root アカウント)

【作成方法】
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/private-content-trusted-signers.html

出来上がった プライベートキーアクセスキーIDは大切に保存しておきましょう。

カスタムポリシーステートメントの用意

署名付き cookie で利用するポリシーを JSON ファイルとして作成します。

設定するパラメータは必要最低限として、これを policy.json として保存します。

{"Statement":[{"Resource":"http*://*.streampack.ga/*","Condition":{"DateLessThan":{"AWS:EpochTime":1621555191}}}]}
Items Values
Resource 対象となるホスト、パスを指定(ワイルドカード可)
AWS:EpochTime 有効期限を UNIXTIME で指定

1. ポリシーステートメントを base64 エンコード

下記コマンドを実行して結果をメモしておきましょう。

$ cat ./policy.json | openssl base64 | tr '+=/' '-_~'

2. ポリシーステートメントを署名して base64 エンコード

下記コマンドを実行して結果をメモしておきましょう。

$ cat ./policy.json | openssl sha1 -sign ./[privatekey].pem | openssl base64 | tr '+=/' '-_~'

3. cookie をセットする

上記を結果を用いてセットする cookie を作成します。
Player が CF にアクセスするときに下記 cookie を渡すことにより、認証をパスすることができます。

cookie value
CloudFront-Key-Pair-Id アクセスキーID
CloudFront-Policy 上記1の結果
CloudFront-Signature 上記2の結果

CloudFront 設定

Origins 設定

今回、マルチオリジンを利用して、Player と HLS 取得先をそれぞれ設定します。

Behaviors 設定

HTML5 Player を S3 から (Default)
HLS は MediaStore から (ts と m3u8) 取得するように設定します。

Restrict Viewer Access 設定

Behaviors の ts と m3u8 設定で Restrict Viewer Accessを有効にします。
Default はそのまま無効とします。 これは HTML を読み込ませて cookie を取得される為です。

Player の用意

今回 HTML で javascript を使用して cookie をセットし、同時に HTML5 Player も埋め込んでしまいます。

Player 例:

<!DOCTYPE html>
<html>
<head>
  <title>Clappr Player</title>
  <meta charset="UTF-8">
  <!-- Player -->
  <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/clappr/0.2.86/clappr.min.js"></script>
</head>
<body>
  <div id="player"></div>
  <script>
    document.cookie = "CloudFront-Key-Pair-Id=XXXXXXXXXXXXXXXXXXXX; path=/";
    document.cookie = "CloudFront-Policy=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX; path=/";
    document.cookie = "CloudFront-Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX; path=/";
    var player = new Clappr.Player({
      source: "https://xxx.streampack.ga/xxx/index.m3u8",
      parentId: "#player"
    });
  </script>
</body>

document.cookieに上記で作成した cookie を指定し、ついでに path=/も付与することで、サイト全体がこの cookie の対象となります。

sourceには CloudFront 経由の MediaStore の HLS URL を指定します。

視聴

S3 にアップした HTML ファイルに CF 経由でアクセスします。
Behaviors Default には制限をかけていないので、HTML ファイルまでは誰でもアクセスできます。

ブラウザがこの HTML を読み込む際に、cookie を取得して、続く m3u8 と ts のリクエストの際に、この cookie を付与することにより、CF の署名付き cookie が認証されて視聴が可能となります。

ちなみに同じ HTML から document.cookie 部分を削除すると CF に怒られて視聴不可になります。

当たり前だけど URL 直打ちも拒否ります!

kimura7:~ kimura$ curl https://xxx.streampack.ga/xxx/index.m3u8
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>D601B63B9BB1393C</RequestId><HostId>qV0Y6iA+8rZx0Q8TM/pn+r22UyykEKnsdyPUHmkFjRd4v8Y/7BHH3gM6prUe6v8d/zxHjSNjXz0=</HostId></Error>

まとめ

今回は超絶、全部手作業ですが、最小構成の場合は結構簡単に設定することができます。

これで ffmpeg -i -movflags faststart…. な人はサヨウナラです。

参考

cookie 生成にあたり、@suhirotakaさんが作成された下記の投稿が大変参考になりました。

https://qiita.com/suhirotaka/items/514a9e246779dc1b9489

元記事はこちら

CloudFront Signed Cookie でストリーミング URL を保護