Amazon Cognitoで認証してCloudFrontの署名付きCookieで制限するライブ配信環境を作りたい~後編~

記事タイトルとURLをコピーする

こんにちは、矢野(喬)です。

こちらの記事は前編の続きになっています。前編ではCognito環境を準備して後編で残りは一気に用意する流れとなります。
構成図や流れは繰り返しになりますがこちらにも載せておきます。

前編はこちらです。
https://blog.serverworks.co.jp/livestreaming-cookie-cognito-1

構成図

f:id:swx-kyosuke-yano:20220123085909p:plain

視聴者

① 視聴者が ALBのURL にアクセス
② ALB→リスナールールでCognitoに飛ばされ、登録されたユーザーで認証
③ 認証OKの場合、次のリスナールール「固定レスポンス」でhtmlを返却
④ html内でcookieを付与した後にCloudFrontへリダイレクト
⑤ CloudFrontのオリジンのS3にあるビデオプレーヤーを埋め込んだhtmlでライブ配信を再生

配信者

① OBSでライブ配信ボタン押下
② IVSがOBSからデータ取得してライブ配信開始
③ IVSのストリームURLをS3のhtmlに記載
④ S3のIVS用ビデオプレーヤーを再生するhtmlで映像視聴できることを確認

環境構築の流れ

1.Cognitoユーザープール設定
2.CloudFront用のキーペア作成・登録
3.CloudFrontディストリビューション設定
4.署名付きCookie準備
5.ALB設定
6.IVS設定
7.動作確認

後編では 2 以降を扱います

環境構築詳細

2.CloudFront用のキーペア作成・登録

署名付きCookieで制限するためのキーペアを作成し、CloudFrontディストリビューションで設定できるようにします。
公式ページを参考にキーペアを用意します。
署名付き URL と署名付き Cookie を作成できる署名者の指定 - Amazon CloudFront

opensslコマンドで秘密鍵を作成し、秘密鍵から公開鍵を作成します

## 秘密鍵作成 
openssl genrsa -out cookie.pem 2048
## 公開鍵作成
openssl rsa -pubout -in cookie.pem -out cookie.pub

CloudFront → パブリックキー → パブリックキーを作成 をクリック f:id:swx-kyosuke-yano:20220123110804j:plain
名前や説明を入れ、キーの枠内に作成した公開鍵の内容を貼り付けます f:id:swx-kyosuke-yano:20220123110855j:plain
作成されたパブリックキーのIDを後ほど使うのでメモします。本記事では KWKXF3G9HD476 ですね f:id:swx-kyosuke-yano:20220123111020j:plain
CloudFront → キーグループ → キーグループを作成 でディストリビューションで使えるように登録します f:id:swx-kyosuke-yano:20220123115102j:plain
先程の KWKXF3G9HD476 を指定して「キーグループを作成」でOKです f:id:swx-kyosuke-yano:20220123115139j:plain

3.CloudFrontディストリビューション設定

ここではディストリビューションの作成を行います。本記事の環境では、IVSからの映像を読み込むindex.htmlをS3バケットに配置して、S3をオリジンとして視聴することを想定しています ディストリビューション作成は設定箇所を表にして簡単にまとめてみます。

オリジン
設定内容 設定値 備考
オリジンドメイン htmlを置くS3バケットを指定
名前 わかりやすければ何でも
S3バケットアクセス はい、OAIを使用します S3にはCloudFrontからのアクセスのみに制限するため、OAIを用います
既存OAIが無ければ「新しいOAIを作成」でOK
バケットポリシー はい、バケットポリシーを自動で更新します 自動上書き便利
デフォルトのキャッシュビヘイビア
設定内容 設定値 備考
オブジェクトを自動的に圧縮 NO
ビューワープロトコルポリシー Redirect HTTP to HTTPS
許可された HTTP メソッド GET, HEAD
ビューワーのアクセスを制限する Yes
ー 信頼された認可タイプ Trusted key groups (recommended) 作成したキーグループを指定します
キャッシュキーとオリジンリクエスト Legacy cache settings ポリシーは作成していないのでレガシーの方で
ー ヘッダーを追加 ・Access-Control-Request-Headers
・Access-Control-Request-Method
・Origin
本記事とは要件が異なるかもしれませんがCORS用に記事参考にして設定
※1
ー オブジェクトキャッシュ Use origin cache headers

※1 CloudFront の「「Access-Control-Allow-Origin」ヘッダーが存在しません」というエラーを解決する

設定
設定内容 設定値 備考
カスタム SSL 証明書 ACMで取得したCloudFront用FQDNの証明書
ー セキュリティポリシー TLSv1.2_2021
デフォルトルートオブジェクト index.html S3バケットにindex.htmlを配置するので指定します


ディストリビューションを作成したら
「代替ドメイン名(CNAME)」をACMと同じCloudFront用FQDNで設定し、
Route53のホストゾーンで CloudFront用FQDNでCloudFrontのエイリアスレコードを設定しておきます

4.署名付きCookie準備

以下公式ユーザーガイドを頼りに署名付きCookieの準備を進めていきます
カスタムポリシーを使用する署名付き Cookie の設定 - Amazon CloudFront
Linux コマンドおよび OpenSSL を使用した Base64 エンコードおよび暗号化 - Amazon CloudFront

まとめると以下3つを用意することになり、それぞれの値をALBの固定レスポンスに埋め込みます

  • CloudFront-Policy
    • 対象や期限を指定するポリシー
  • CloudFront-Signature
    • キーペアで署名したポリシー
  • CloudFront-Key-Pair-Id
    • 先程メモした キーペアID ( KWKXF3G9HD476 )
CloudFront-Policy

リソースはCloudFront用FQDNを指定し、
期限は2022年3月31日をUNIX時間変換して記載する形で、jsonファイルを作成

{
    "Statement":
    [
        {
            "Resource":"https://CloudFront用FQDN/*",
            "Condition":
            {
                "DateLessThan":
                {
                    "AWS:EpochTime":1648738799
                }
            }
        }
    ]
}

jsonファイルをガイドを参考に変換

cat custompolicy.json  | tr -d "\n" | tr -d " \t\n\r" |openssl base64 | tr '+=/' '-_~'
CloudFront-Signature

CloudFront-Policy で用意したjsonと、作成したキーペアの秘密鍵を使ってガイドを参考に変換します

cat custompolicy.json  | tr -d "\n" | tr -d " \t\n\r" |openssl sha1 -sign cookie.pem|openssl base64 | tr '+=/' '-_~'

これで3つとも準備ができました

5.ALB設定

ALBを用意し、Cognito認証→固定レスポンスでCookieを埋め込んでCloudFrontに飛ばす所まで設定します
本記事では主にCognitoに繋げるリスナールールを説明しそれ以外は以下に簡単にまとめることにします(盛り沢山になりすぎたので)

  • ALBをインターネット向きに作成
  • 用意したALB用FQDNで取得したACM証明書を適用したHTTPSリスナーをセット
  • Route53のホストゾーンで ALB用FQDNでALB向きのエイリアスレコードを設定しておきます
  • 見せたい人に制限するセキュリティグループをアタッチ

作成したALB → リスナー → ルールの表示/編集 をクリックします f:id:swx-kyosuke-yano:20220123124311j:plain
鉛筆マークでデフォルトアクションを編集します
THEN → アクションの追加 → 認証 と進み、

認証 : Amazon Cognito
Cognitoユーザープール : 作成したユーザープールIDを指定
アプリクライアント : 作成したアプリクライアントを指定

その他はそのまま (え?これだけで良いの感がはじめはありました) f:id:swx-kyosuke-yano:20220123124559j:plain
ALB→Cognito設定が出来たので、次はCloudFrontへ飛ばすところです
Cognito認証の下の アクションの追加 → 固定レスポンスを返す と進み、

レスポンスコード : 200
Content-Type : text/html
レスポンス本文 : ここに用意した署名付きCookie情報やリダイレクトを仕込みます

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Cookieを付与してリダイレクトするページ</title>
</head>
<body>

<h1>CloudFrontに移動します</h1>

<p id="msg">OK</p>

<script>
document.cookie = 'CloudFront-Policy=用意した文字列; Domain=ALBやCloudFront用のRoute53ホストゾーンドメインを記載';
document.cookie = 'CloudFront-Signature=用意した文字列; Domain=ALBやCloudFront用のRoute53ホストゾーンドメインを記載';
document.cookie = 'CloudFront-Key-Pair-Id=メモしたキーペアID ( KWKXF3G9HD476 ); Domain=ALBやCloudFront用のRoute53ホストゾーンドメインを記載';
document.location.href = "https://CloudFront用FQDN";
</script>

</body>
</html>

設定が終わったらチェックを入れて保存すればOKです
これでALB→Cognito→ALBからCloudFront→S3まで飛べるようになったはずです
前編でも触れた無理矢理感は主にこの辺りで、固定レスポンスにCookieを埋めたりしていますが、社内で試す分には十分と思ってこの形を採用しました
私としてはここまで設定するのも結構大変だったので、ブラッシュアップはまた次の機会に回します。スモールスタートええやんの精神

6.IVS設定

IVSのチャンネル作成は私の以前の記事を見ていただきまして、作成したIVSチャンネルの配信URL(~.m3u8)をメモしておきます

blog.serverworks.co.jp


メモしたm3u8アドレスを例えば以下のようなindex.htmlを作成し埋め込みます
IVSのビデオプレーヤーは随時更新されていっているので、その時の最新バージョンを選択してください
player.loadにm3u8のURLを書き込みして、CloudFrontでオリジンに指定したS3バケットにアップロードすればOKです

<head>
  <script src="https://player.live-video.net/1.5.0/amazon-ivs-player.min.js"></script>

  </head>

<body>
    <video id="video-player" width="960" height="540" controls playsinline></video>
    <script>
  if (IVSPlayer.isPlayerSupported) {
    const player = IVSPlayer.create();
    player.attachHTMLVideoElement(document.getElementById('video-player'));
    player.load("配信URL.m3u8");
    player.play();
  }
</script>
</body>

IVS Playerはこちらから確認できます
Amazon Interactive Video Service プレイヤー: SDK for Web のガイド - Amazon Interactive Video Service

7.動作確認

これで全ての準備が整ったので、テストしてみます
先ずはOBSでIVSから配信できるように設定(前述のブログをご参考ください)して「配信開始」します

IVSで問題なくプレビューが見ることが出来たら、ちゃんとバケットポリシーで制限されていることを確認するためにS3に格納したindex.htmlのURLを直接見てみます
想定通りに AccessDenied が表示されました f:id:swx-kyosuke-yano:20220123163214j:plain
ではALBにアクセスしてみます、ALBのリスナールールに設定した通りCognitoの認証画面が表示されました
作成したユーザーでログインします
f:id:swx-kyosuke-yano:20220123163459j:plain
一瞬固定レスポンスに記載したメッセージが表示された後、CloudFront用FQDNにリダイレクトされて配信画面が表示されました
f:id:swx-kyosuke-yano:20220123163715j:plain
ちゃんとCookieが効いてくれていることを確認するために開発者ツールでCookie情報を覗いてみます…
きちんと3つともALBからCookieを引き継いでくれていますね
f:id:swx-kyosuke-yano:20220123164048j:plain
Cookieが無い場合も試してみます
Cookie情報を引き継がないように固定レスポンスの記載を直して再度アクセスしてみると…
Missing Key-Pair-Id となり、Cookieも見当たらない状態で映像が見られませんね
f:id:swx-kyosuke-yano:20220123164725j:plain
よし

おわりに

前編から後編にかけて長くなってしまいました。構成は力技ではありますが、今までの私のブログでの構成に比べて実践に近づいたものが出来たなと思っています。
特定の誰かにだけ映像を見せたい、不特定多数でも対応して管理したい、そういった当然求められるであろう状況を考えながらCognitoやCookieを設定していくのはとても楽しかったです。
もっと色々なパターンを試したり突き詰めていったり、今後のアップデートによる変化を追ったりとやることは尽きませんが、楽しく望めるのはシンプルに良いことですね。
これができたからこれもやってみようと思えるものも幾つか出てきたので、小さく試す気持ちを忘れずにまたこうしてブログでご紹介出来たらと思います。

ありがとうございました。

矢野 喬亮 (記事一覧)

クラウドインテグレーション部

ウクレレと陶芸とMediaServicesが好きです