[UPDATE] Amazon CloudFrontのOACでAWS Elemental MediaStore Originをサポートしました!

CloudFront Origin Access Controlで新たにMediaStoreオリジンへのアクセス制御をサポートしました。カスタムヘッダを用いてMediaStoreオリジン保護を行っている場合、今後はOACを使用しましょう。
2023.02.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

清水です。本エントリでお届けするAWSアップデート情報はこちら!AWSのCDNサービスであるAmazon CloudFrontのオリジンへのアクセス制御方式であるOrigin Access Control (OAC)で、新たにメディア向けに最適化されたストレージサービスであるAWS Elemental MediaStoreをサポートしました!(2023/02/09付でAWS What's Newにポストされたアップデート情報となります。)

Amazon CloudFrontの新しいアクセス制御方式であるOACについて

CloudFrontでオリジンをAmazon S3とした場合のアクセス制御方式として、従来からOrigin Access Identity (OAI)というものがありました。しかしOAI自体にはS3側のSSE-KMSに対応していないなどといったいくつかの制限があり、これをカバーしつつよりセキュリティ体制について強化したOrigin Access Control (OAC)という制御方式が利用可能になりました。これが2022年8月のことです。

動作としてはCloudFront側のService PrincipalがSigV4で署名してオリジンとなるS3にアクセスします。S3側ではこのCloudFront Service Principalに対してアクセス許可を行うかたちになりました。

AWS Elemental MediaStoreと従来までのCloudFrontからのアクセス制御

AWS Elemental MediaStoreはメディア向けに最適化されたストレージサービスとして、2017年11月にAWS Media Servicesの1つとしてリリースされました。

「メディア向けに最適化されたストレージサービス」ということですが、その実態は当時Amazon S3ではカバーできなかった上書き操作後の読み込み整合性を提供し、HLS形式などでのライブオリジンとして利用可能としたものです。

なお2023年2月の時点では、2020年12月にAmazon S3が強い書き込み後の読み込み整合性をサポートしたことにより、S3をライブオリジンとして利用することも可能となっています。要件の詳細を確認して最適なライブオリジンを使用するようにしましょう。

さて、MediaStoreをOriginとしてCloudFrontを利用する場合、そのアクセス制御方式としてOAIのようなものは利用できず、CloudFrontのオリジンカスタムヘッダを使いUser-AgentやRefererヘッダを個別の値に設定、MediaStore側でそのヘッダの値をもとにアクセス制御を行う、といった手法が取られていました。

このオリジンカスタムヘッダの利用でアクセス制御自体はできていたのですが、セキュリティのベストプラクティスに従う場合はシークレット情報となるカスタムヘッダ(User-AgentやReferer)の値のローテーションを考えなければなりません。CloudFrontディストリビューションの設定変更ならびにOriginとなっているMediaStoreコンテナのコンテナポリシー変更が発生します。正直なところ手間ではありますよね。対象リソース数が少なければまだしも、たくさんあればなおさらです。

ここで今回のアップデートです。CloudFrontのOrigin Access Control (OAC)を用いることで、S3の場合と同様にCloudFront側はService PrincipalがSigV4で署名してオリジンとなるMediaStoreにアクセスすることとなります。MediaStore側ではこのCloudFrontのService Principalに対してアクセス許可を行うかたちです。シークレットのローテーションはユーザ側で意識する必要はありません。OACの提供開始の際、「短期間の資格情報とより頻繁な資格情報のローテーションをサポート、混乱した代理攻撃に対してより優れた保護を提供」ということだったので同様のメリットがMediaStoreをオリジンにした場合でも享受できるわけですね。

OACを使ってMediaStoreにアクセスしてみる

それでは実際にCloudFrontのOrigin Access Control (OAC)を使ってMediaStoreにアクセスしてみたいと思います。Amazon CloudFront Developer Guideを参考に進めていきます。

MediaStore Containerの作成

まずは今回、CloudFrontのOriginとするMediaStore Container(S3のバケットに相当)を作成します。MediaStoreのマネジメントコンソールで[Create container]ボタンから進みます。

Container作成後、InfoタブからData endpointを確認しておきます。このドメインがCloudFrontで指定するOriginとなります。

また後ほどの動作の確認のため、CORS policyを設定しておきました。CORS policyは検証用途の動作確認用ということで[Apply default policy]で設定しています。

CloudFront Origin Access Controlの作成

続いてCloudFrontのマネジメントコンソールで、MediaStore Origin用のOrigin Access Controlを作成します。Security > Origin accessのページから[Create control settings]ボタンで進みます。NameとDescriptionを適切に入力し、Signing behaviorはデフォルト設定(Sign requests (recommended)を選択、"Do not override authorization header"はチェックなし)としています。またOrigin typeの項目ではMediaStoreを選択します。

MediaStoreオリジン用のOrigin Access Controlが作成できました。

MediaStoreオリジンのCloudFront Distributionの作成

MediaStoreオリジン用のOACが作成できたら、このOACを使用するCloudFront Distributionを作成していきます。オリジンは先ほど作成したMediaStore Containerを使用するのでそのData endpointを確認しておきます。

なお、CloudFront Distributionの設定についてはAmazon CloudFront Developer Guideの以下の項目を参考にしました。

CORSについても最低限の設定をしていますが、利用しているクライアントなどにあわせて追加の設定が必要な場合もありますので注意しましょう。(参考: CloudFront の「「Access-Control-Allow-Origin」ヘッダーが存在しません」というエラーを解決する

CloudFrontのマネジメントコンソール、[Create distribution]ボタンから進みます。Origin domainのMediaStoreの項目の中から先ほど作成したMediaStore ContainerのData endpointを選択します。

OriginのProtocolはHTTPS onlyを選択しました。

Origin access controlの項目で、先ほど作成したOACを選択します。

OACを選択すると「You must update the container policy」と、MediaStore ContainerのPolicyをアップデートせよ、と警告されます。後ほど設定するので、ここではいったん先に進めます。

Default cache behaviorの項目については、Viewer protocol policyでRedirect HTTP to HTTPSを選択しました。

Cache key and origin requestsの項目、Cache policyはデフォルトのCachingOptimized、Origin request policyはCORS-CustomOriginを選択しました。

その他の項目はマネジメントコンソールのデフォルトの設定としています。最後にDescriptionをわかりやすいように設定し、[Create distribution]ボタンでDistributionを作成します。

MediaStore Container PolicyをOAC用に書き換え

CloudFront Distributionが作成できました。それと同時に、画面上部に「Successfully created new distribution.」と表示されていますね。その下に「The container policy need to be update」とMediaStore ContainerのPolicyをアップデートするよう、再度促されます。

ここで[Copy policy]ボタンを押下すると以下のPolicyが得られました。

{
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "CloudFrontRead",
                "Effect": "Allow",
                "Principal": {
                  "Service": "cloudfront.amazonaws.com"
                },
                "Action": [ 
                  "mediastore:GetObject"
                ],
                "Resource": "arn:aws:mediastore:ap-northeast-1:123456789012:container/cloudfront-origin-access-control-test/*",
                "Condition": {
                    "StringEquals": {
                      "AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E28JXXXXXXXXXX"
                    },
                    "Bool": {
                      "aws:SecureTransport": "true"
                    }
                }
            }
        ]
      }

CloudFront OACを用いた場合のMediaStore container policyの記載例については、Amazon CloudFront Developer Guideに記載例があります。

read-only accessかread and write accessかでActionの内容を変える必要があります。今回はread-onlyで検証を進めていきます。read-onlyの場合、上記の[Copy policy]ボタン押下で得られたPolicyの内容で問題なさそうですね。(ただし、GETリクエストのみの許可でHEADリクエストは未許可となります。HEADリクエストについても許可が必要な場合はmediastore:DescribeObjectも許可対象に追加しましょう。)Go to container permissions to update policyの文字列が該当のMediaStore ContainerのPolicy設定変更画面へのリンクとなっているので、ここをクリックして設定を進めます。

先ほど作成したMediaStore Container、Policyについては特に設定をしていなかったため、変更前は以下の状態(デフォルト設定)です。

CopyしたPolicyの内容でまるっと書き換えます。

MediaStore Container Policyの書き換えが完了しました。

MediaStoreをライブオリジンとするMediaLiveの作成

OACを使ったCloudFront+MediaStoreのライブストリーミング配信環境が整いました。実際にMediaLiveとMediaStoreを連携させて、ライブストリーミングをMediaStoreオリジンで配信、CloudFront経由で視聴することでOACの動作確認を行ってみます。

MediaStoreに書き込みを行うMediaLiveのリソース一式はMediaLive Workflowで作成しました。[Create workflow]ボタンから進みます。Workflow nameを適切に入力し、channel classについては今回は検証用とということでSINGLE_PIPELINEを選択しました。IAM roleは既存のロールを使用します。

InputはRTMP (push)を使用し、新規に作成しました。

Video Outputの設定です。出力先としてHLS to MediaStoreを選択します。MediaStore destinationの項目では既存のMediaStore container使用を選択し、先ほど作成したMediaStore containerを選びます。

作成されるリソース(MediaLiveのInputとChannelですね)を確認して、 [Create workflow resources]します。

ライブストリーミングを実施してOACを使ったMediaStoreの動作確認

MediaLiveのWorkflowリソースが作成できたら、実際に映像を打ち上げライブストリーミングを実施してOACを使ったMediaStoreのアクセス制限について動作を確認してみます。

MediaLive Workflow(もしくはMediaLive Channel)をStartさせ、映像の打ち上げにはZixi ONAIR on iPhone XSからのRTMP出力を用いました。

MediaStoreのマネジメントコンソールでマニフェストファイルのURLを確認し、このパスにCloudFrontのドメインでアクセスします。今回はMediaStoreのURLが

  • https://4cf6xxxxxxxxxx.data.mediastore.ap-northeast-1.amazonaws.com/livea/main.m3u8

でCloudFrontドメインが「d3caxxxxxxxxxx.cloudfront.net」ですので、 再生用のマニフェストファイルURLは以下となります。

  • https://d3caxxxxxxxxxx.cloudfront.net/livea/main.m3u8

ライブストリーミングはvideojs-http-streaming Demoのページで確認しました。CloudFront経由で問題なくライブストリーミングの視聴ができていますね!

Source URLをCloudFrontドメインではなく、MediaStore直接のアクセスにしてみます。MediaStoreのContainer Policyでは、CloudFront OACのみしかアクセスを許可していない状況ですので、MediaStoreへの直アクセスはできないはずですよね。

実際アクセスしてみると以下のように「The media could not be loaded, either because the server or network failed or because the format is not supported.」と表示され再生できません。デベロッパーツールで詳細を確認すると、Status Codeは 403 Forbiddenとなっており、アクセスができない状態でした。

マニフェストファイルへのアクセスについて、curlコマンドでも確認してみましょう。まずはCloudFront経由(CloudFrontドメイン)でのアクセスです。200 OKでアクセスできています。(なおContainer Policy設定の箇所でも記述しましたが、現在CloudFront Service Principalにアクセスを許可しているのはmediastore:GetObjectのみですのでGETリクエストのみが許可対象となります。curl -IのようなHEADリクエストを許可するためには追加でmediastore:DescribeObjectの権限も必要です。

% curl -i https://d3caxxxxxxxxxx.cloudfront.net/livea/main.m3u8

HTTP/2 200
content-type: application/vnd.apple.mpegurl
content-length: 201
x-amzn-requestid: 4IS7XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXCZ4I
last-modified: Mon, 13 Feb 2023 06:39:26 GMT
cache-control: max-age=3
date: Mon, 13 Feb 2023 06:52:47 GMT
etag: 8a2fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxe84a
x-cache: Miss from cloudfront
via: 1.1 28bfxxxxxxxxxxxxxxxxxxxxxxxxb2d6.cloudfront.net (CloudFront)
x-amz-cf-pop: KIX56-C1
x-amz-cf-id: Ay_LXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXTM3U

#EXT-X-VERSION:3
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-STREAM-INF:BANDWIDTH=3572008,AVERAGE-BANDWIDTH=3440800,CODECS="avc1.64001f,mp4a.40.2",RESOLUTION=1280x720,FRAME-RATE=29.970
main_720p30.m3u8

curlコマンドでMediaStore直アクセスも確認してみましょう。こちらは403 Forbiddenとなります。

% curl -i https://4cf6xxxxxxxxxx.data.mediastore.ap-northeast-1.amazonaws.com/livea/main.m3u8

HTTP/1.1 403 Forbidden
x-amzn-RequestId: NJTQXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXTCYI
x-amzn-ErrorType: AccessDeniedException
Content-Type: application/x-amz-json-1.1
Content-Length: 28
Date: Mon, 13 Feb 2023 06:52:57 GMT

{"Message":"Access Denied."}

まとめ

Amazon CloudFrontのOrigin Access Control (OAC)でAWS Elemental MediaStoreへのアクセス制御をサポートしたアップデートについてお届けしました。従来からOrigin Access Identity (OAI)と同じ仕組みがMediaStoreでも使用できれば、と思っていたのですが、新しいアクセス制御方式であるOACで実現されて大変喜ばしい限りです。

これまでカスタムヘッダを用いてMediaStore側でCDN認証をしていたという場合でも、特段の事情がない限りCloudFront OACの利用へ移行するのが良いのかと思います。(S3オリジンとしてのOACリリースの際には、OAIが「legacy, not recommended」と表記されるようになりました。MediaStoreオリジンの場合、そもそもOAIは対応しておらず、カスタムヘッダを用いたある意味力技での対応だったわけですが、AWS側で機能として提供している認証方式を利用するのがベストかと考えます。)

なお今回、MediaStore側でOAC、CloudFrontのService Principalへの許可はread-onlyとして設定していましたが、read and write accessでも設定可能ですのでCloudFrontを経由したMediaStoreへのPut構成でも利用可能と考えます。(AWS Elemental MediaStore: Ingest acceleration | AWS Media Blog) read and write accessやHEADリクエストを許可する場合などではContainer Policy内容が変わる点には注意しましょう。

また本文中にも記載しましたが、ライブオリジンとしてはS3の利用も検討できるようになってきています。要件などを確認して適切なライブオリジンを選択しましょう。