MediaLiveのWorkflow Wizardで作成されるリソースをカスタマイズ! ~MediaStoreのCORSとCDN認証の設定を入れてみよう~

AWS Elemental MediaLiveのWorkflow Wizard機能で作成したリソースについて、CloudFormationのTemplateを変更してStackをUpdateすることでカスタマイズを行なってみました。
2021.04.30

はじめに

清水です。先月アップデートされたAWS Elemental MediaLiveのWorkflow Wizard機能、リソースの作成はCloudFormation Stackで行われており、このTemplateを編集することでリソースのカスタマイズが可能です。本エントリではこの一例として、AWS Elemental MediaStoreをライブオリジンとした場合のCORS設定とCDN設定ををカスタマイズで追加してみたのでまとめてみます。

カスタマイズ内容の詳細については、以下エントリなどをあわせてご確認ください。

MediaLiveのWorkflow Wizardで作成されるリソースをカスタマイズしてみる

ベースとなるWorkflowの作成

まずは編集のベースとなるWorkflowをWorkflow Wizardから作成していきます。MediaLiveマネジメントコンソールのWorkflow Wizard、[Create workflow]ボタンから進みます。Step 1 Enter basic detailsではWorkflow名やChannel class(今回はSINGLE_PIPELINEとしました)、IAM roleを設定します。

続いてStep 2 Choose a video sourceでInput typeなどを設定します。今回はRTMP (push)を利用します。

Step 3 Add video outputsではOutput groupsを設定を行います。MediaStore(HLS to MediaStore)を選択しました。MediaStore Containerは新規に作成するとします。Video renditionsはデフォルトのままとしました。

最後のStep 4 Review and create resourcesで内容を確認して、[Create workflow resources]ボタンでリソースを作成します。

Workflowsが作成されるまで、しばらく待ちましょう。

Workflowに対応するCloudFormation Stackの確認

Workflowが作成されるのを待ちながら、このWorkflowに対応するCloudFormation Stackについて確認しておきます。先ほどの画面の上部、「This workflow is deployed as a CloudFormation stack」に続くリンクから、もしくはCloudFormationのマネジメントコンソールでWorkflow名のStackを直接確認することもできます。

ここでTemplateタブを確認すると、このCloudFormation Stackに対応するTemplateが参照できます。JSONでしかも改行がないため見辛いですが、編集のため、コピペしてファイルなどにまとめておきましょう。

Workflowに対応するCloudFormation Templateの編集

それではCloudFormation Templateを編集していきます。(以降、私の試行錯誤の結果でWorkflow名称の末尾に「2」がつくようになっていますが、内容は同じです。適宜読み替えてください。)

先ほどのマネジメントコンソールで確認したJSONファイルを、まずはjqコマンドにとおして整形しました。(pbpaste | jq . > template.jsonなぐあいです。)

そのファイルを編集していきます。お好みのエディタで行いましょう。私はCloudFormation (JSON)編集にカスタマイズしているEmacsを使用しました。

編集内容はCORS設定として、MediaStoreのCorsポリシーの変更(追加)とCloudFrontのOriginヘッダ転送を行います。またCDN認証設定として、MediaStoreのコンテナポリシーのUserAgentを具体的に指定、CloudFront側でもOriginCustomHeadersのUser-AgentにMediaStore側コンテナポリシーと同じUserAgentの値を指定します。この値はsesame-ouvre-toiとしました。

これらを編集したファイルの差分は下記となります。

 % diff -u customize-workflow2-before.json customize-workflow2-edit.json
--- customize-workflow2-before.json     2021-04-30 23:11:03.000000000 +0900
+++ customize-workflow2-edit.json       2021-04-30 23:10:53.000000000 +0900
@@ -28,7 +28,15 @@
             "Properties": {
                 "AccessLoggingEnabled": false,
                 "ContainerName": "customize-workflow2",
-                "Policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"MediaStoreFullAccess\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::123456789012:root\"},\"Resource\":\"arn:aws:mediastore:ap-northeast-1:123456789012:container/customize-workflow2/*\",\"Action\":\"mediastore:*\",\"Condition\":{\"Bool\":{\"aws:SecureTransport\":\"true\"}}},{\"Sid\":\"CloudFrontRead\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:mediastore:ap-northeast-1:123456789012:container/customize-workflow2/*\",\"Action\":[\"mediastore:GetObject\",\"mediastore:DescribeObject\"],\"Condition\":{\"StringEquals\":{\"aws:UserAgent\":\"\"},\"Bool\":{\"aws:SecureTransport\":\"true\"}}}]}",
+                "CorsPolicy": [
+                    {
+                        "AllowedHeaders" : [ "*" ],
+                        "AllowedMethods" : [ "GET", "HEAD" ],
+                        "AllowedOrigins" : [ "*" ],
+                        "MaxAgeSeconds" : 3000
+                    }
+                ],
+                "Policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"MediaStoreFullAccess\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::123456789012:root\"},\"Resource\":\"arn:aws:mediastore:ap-northeast-1:123456789012:container/customize-workflow2/*\",\"Action\":\"mediastore:*\",\"Condition\":{\"Bool\":{\"aws:SecureTransport\":\"true\"}}},{\"Sid\":\"CloudFrontRead\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"arn:aws:mediastore:ap-northeast-1:123456789012:container/customize-workflow2/*\",\"Action\":[\"mediastore:GetObject\",\"mediastore:DescribeObject\"],\"Condition\":{\"StringEquals\":{\"aws:UserAgent\":\"sesame-ouvre-toi\"},\"Bool\":{\"aws:SecureTransport\":\"true\"}}}]}",
                 "Tags": [
                     {
                         "Key": "MSAM-Diagram",
@@ -109,7 +117,8 @@
                         ],
                         "Compress": false,
                         "ForwardedValues": {
-                            "QueryString": false
+                            "QueryString": false,
+                            "Headers": [ "Origin" ]
                         },
                         "SmoothStreaming": false,
                         "ViewerProtocolPolicy": "redirect-to-https",
@@ -152,7 +161,7 @@
                             "OriginCustomHeaders": [
                                 {
                                     "HeaderName": "User-Agent",
-                                    "HeaderValue": ""
+                                    "HeaderValue": "sesame-ouvre-toi"
                                 }
                             ]
                         }

編集したTemplateでUpdate Stack

CloudFormation Templateの編集ができたら、実際にCloudFormation StackをUpdateしてみます。なお、MediaLiveのChannelは停止しており、そもそもいちどもStartさせていない状態で確認をしています。

CloudFormationのマネジメントコンソールから、Update stackで「Replace current template」を選択、テンプレートファイルをアップロードします。

パラメータ、オプションについてはそのまま次に進みます。Review画面では、最後のChange set previewについても確認し、[Update stack]でスタックをUpdateします。

Update Stackが完了しました。リソースの操作としてはMediaStoreコンテナ、ならびにCloudFrontディストリビューションのアップデートとなりました。

実際にカスタマイズした環境を確認

Update Stackが完了したので、実際にカスタマイズした環境を確認してみましょう。まずはCORS設定まわりから、MediaStoreのCORSポリシーが設定されていますね。

CloudFrontディストリビューションでのOriginヘッダ転送も設定されています。

続いてCDN認証です。MediaStoreのコンテナポリシー、UserAgent部分に値が入っています。

CloudFrontのオリジン設定でも、指定したUser-Agentヘッダの値をオリジンに転送するようになっていますね。

設定自体がカスタマイズできていることが確認できました。実際にHTTPリクエストでも確認してみましょう。MediaLiveのChannelをスタートさせ、映像を打ち上げます。MediaStoreにMediaLiveからのファイルが書き込まれたところで、これらのファイルを取得してみます。

CORS設定が行われており、Access-Control-Allow-Originヘッダが付与されていることがわかりますね。またオリジンであるMediaStoreにきちんとリクエストが許可されている(CDNが認証されている)状態です。

% curl -I -H"Origin: https://example.com" https://dXXXXXXXXXXXXX.cloudfront.net/livea/main.m3u8
HTTP/1.1 200 OK
Content-Type: application/vnd.apple.mpegurl
Content-Length: 641
Connection: keep-alive
x-amzn-RequestId: AUTUOFBF6EWYAO6ME4VPAJRRGAG5TEO5HVPFQMTKWWV4XZXFZWFNNXMBKTSJZ6C2YPKSH5NXXXXXXXXXXXXXXXX
Last-Modified: Fri, 30 Apr 2021 14:31:39 GMT
Access-Control-Allow-Origin: https://example.com
Cache-Control: max-age=3
ETag: 85461318f951e177ae130ab54539470a142c4e509d9d5a45XXXXXXXXXXXXXXXX
Access-Control-Expose-Headers: Content-Range,X-Forwarded-Proto,Last-Modified,Date,x-amzn-cipher-suite,x-amzn-ErrorMessage,Cache-Control,ETag,x-amzn-RequestId,x-amzn-ErrorType,X-Forwarded-For,Content-Length,Content-Type
Access-Control-Allow-Credentials: true
Date: Fri, 30 Apr 2021 14:32:53 GMT
Vary: Origin
X-Cache: Miss from cloudfront
Via: 1.1 077f2d4a021fffecXXXXXXXXXXXXXXXX.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: NRT20-C1
X-Amz-Cf-Id: Qd3W66pGIfxIWwoJmrAveGuonVr7HVuzQoJ0G3XXXXXXXXXXXXXXXX==

まとめ

AWS Elemental MediaLiveのWorkflow Wizard機能で作成したリソースについて、CloudFormationのTemplateを変更してStackをUpdateすることでカスタマイズを行なってみました。AWS Elemental MediaStoreをライブオリジンに使用するケースで、CORS設定とCDN認証設定は定番のカスタマイズではないでしょうか。改行のない、そして最近ではあまり見かけなくなった(?)JSON形式のCloudFormation Templateをみたときはギョッとしましたが、ライブ動画配信環境をシンプルに作成できるMediaLiveのWorkflow Wizard、環境のカスタマイズも容易に行えますね。非常に強力な機能だなと改めて思いました。