[アップデート] AWS Elemental MediaPackageでCDN認証が利用可能になりエンドポイントが保護できるようになりました!

2020.01.05

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

はじめに

清水です。AWS Media Servicesの2020年1つ目のアップデート情報はこちら!動画配信におけるジャストインタイムパッケージングサービスであるAWS Elemental MediaPackageでCDN認証が利用可能になり、エンドポイントを保護できるようになりました。(2020/01/02にポストされたアップデートになります。)

動画配信を行う際にはMediaPackageなどをオリジンとして、実際のアクセスはAmazon CloudFrontなどCDNを利用することが多いかと思います。この際MediaPackageのエンドポイントに対してはCDN以外からのアクセスができないよう、オリジン保護をしておきたいですね。今回アップデートされたMediaPackageのCDN認証(オリジン保護)機能では、コンテンツをリクエストする際に特定のHTTPオリジンヘッダと認証コードが必要となります。イメージとしては以下のような、CloudFront+ALB構成でオリジンを保護する方法と同様になるかと思います。

なお、現在のところCDN認証機能はMediaPackageのライブパッケージングのみで利用可能とのことです。VODパッケージングでは現段階ではサポートされていないので注意しましょう。

AWS Elemental MediaPackageでCDN認証を行いオリジン保護してみた

それでは実際にMediaPackageでCDN認証機能を使ってみます。User Guideの以下ページを参考に進めました。(2020/01/03現在、日本語版ページがまだなかったため、英語版ページを参照しています。)

IAMロールの準備

MediaPackageでCDN認証機能を使用する場合、MediaPackageからAWS Secrets Managerへのアクセスが必要となります。このアクセスを許可するIAMロールを準備します。必要なアクセス許可については、こちらもUser Guideを参考に決定しました。(こちらも2020/01/03現在、日本語版ページがなかったため英語版ページを参照しています。)

IAMポリシーの作成

マネジメントコンソールのIAM > Access managementのPoliciesから、[Create policy]でポリシーを作成します。ポリシーの内容は以下のJSONとします。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret",
        "secretsmanager:ListSecrets",
        "secretsmanager:ListSecretVersionIds"
      ],
      "Resource": [
        "*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
         "iam:GetRole",
         "iam:PassRole"
       ],
       "Resource": "*"
     }
  ]
}

IAMポリシー名はMediaPackageCDNAuthPolicyとしました。

IAMロールの作成

続いて作成したIAMポリシーをアタッチするIAMポリシーを作成します。マネジメントコンソールのIAM > Access managementのRolesから[Create role]で進みます。ロールを使用するサービスの選択箇所ではMediaPackageがないので、ひとまずEC2を選択して次に進みましょう。

アタッチするポリシー選択画面では、先程作成したIAMポリシー、MediaPackageCDNAuthPolicyを選択します。

IAMロール名はMediaPackageCDNAuthRoleとしました。

IAMロールの信頼関係の編集

続いて作成したIAMロールの信頼関係を編集します。ロール作成時には使用するサービス選択箇所でMediaPackageがなかったため、EC2を選択していました。この箇所を編集して、MediaPackageから使用可能にします。マネジメントコンソールのIAM > Access managementのRolesから、作成したIAMロール(MediaPackageCDNAuthRole)の詳細画面に進みます。[Trust rrelationships]のタブから、[Edit trust relationship]ボタンで編集画面に進みます。

JSON中の"Service": "ec2.amazonaws.com"の箇所を"Service": "mediapackage.amazonaws.com"と変更します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"  // ここを "mediapackage.amazonaws.com" に変更
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

編集後は[Trust relationships]タブのTrusted entitiesの箇所がThe identity provider(s) mediapackage.amazonaws.comになります。

以上でIAMロールが準備できました。後ほどMediaPackageの設定でこのIAMロールのARNが必要となるので、控えておきます。(Role ARN)

認証コードの作成とSecrets Managerへの登録

認証コードを作成(決定)し、MediaPackageから参照するためSecrets Managerに保存します。

認証コードについて

認証コードについては、「長さが8~128文字であること」という制限があるとのことです。またUser Guideではversion 4 UUIDを使用することを推奨しているので、これにならいます。こちらのページを参考に、手元のMac環境でversion 4 UUIDを生成しました。

 $ python
Python 3.7.3 (default, Apr 23 2019, 11:32:00)
[Clang 10.0.1 (clang-1001.0.46.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import uuid
>>> str(uuid.uuid4())
'8e2f1c52-f77f-4147-940d-5574975a1f81'

この8e2f1c52-f77f-4147-940d-5574975a1f81を本エントリでは認証コードとして扱います。

認証コードのSecrts Managerへの登録

作成した認証コードをMediaPackageから参照できるよう、Secrets Managerへ登録します。使用するMediaPackageと同じリージョンのSecrets Managerを使う点に注意しましょう。マネジメントコンソールのSecrets ManagerのページのSecretsから、[Store a new secret]ボタンで進みます。

secret typeはOther type of secretsを選択、Secret key/valueの左側にKeyとしてMediaPackageCDNIdentifierを、右側にキーの値として先ほど作成した認証コード8e2f1c52-f77f-4147-940d-5574975a1f81を入力します。encryption keyはデフォルトキー(DefaultEncryptionKey)としました。

Secret nameはMediaPackage/プレフィックスを付けておきます。今回はMediaPackage/CDNAuthTestとしました

automatic rotationについてはDisableとしました。

内容を確認して、[Store]で認証コードをSecrets Managerに登録します。

以上で認証コードのSecrets Managerへの登録が完了です。後ほどMediaPackageの設定で作成したSecretのARNが必要になるので、控えておきます。

MediaPackageでCDN認証を有効にする

MediaPackage用のIAMロールの準備、そして認証コードの準備とSecrets Managerへの登録が完了したら、実際にMediaPackageのChannelを作成して、CDN認証を有効にしてみます。

現在のところCDN認証機能はMediaPackageのライブパッケージングのみで利用可能です。MediaPackageのマネジメントコンソール、Live > Channelsから[Create]でLive用のChannelを作成します。このMediaPackage Channel作成段階でCloudFrontディストリビューションもあわせて作成することもできますが、今回は後ほど別途作成することとします。

続いて作成したChannelにEndpointを作成します。Channelの詳細画面からEndpoints欄の[Add endpoints]ボタンで進みます。

Endpoint作成画面、今回はHLS用のEndpointとしました。Access control settingsの箇所でUse authorizationにチェックを入れます。Secrets role ARNCDN identifier secretの項目が現れます。Secrets role ARNには冒頭で作成したSecrets Managerへのアクセス権限を持つIAMロール(今回はMediaPackageCDNAuthRole)のARNを入力します。CDN identifier secretの欄にはSecrets Managerで作成したSecret(今回はMediaPackage/CDNAuthTest-EDgwFi)のARNを入力します。

  • Secrets role ARN
    • arn:aws:iam::[AWSアカウントID]:role/MediaPackageCDNAuthRole
  • CDN identifier secret
    • arn:aws:secretsmanager:ap-northeast-1:[AWSアカウントID]:secret:MediaPackage/CDNAuthTest-EDgwFi

入力できたら[Save]でEndpointの追加を完了します。

CDN認証用のカスタムヘッダをつけてアクセスするようCloudFrontを設定する

続いてCDNとなるAmazon CloudFrontの設定です。今回はMediaPackageのマネジメントコンソールからではなく、CloudFrontのマネジメントコンソールからディストリビューションを作成してみました。

Origin Settingsの項目でOrigin Domain Nameについては、一覧から作成したMediaPackage ChannelのEndpointを選択します。今回、Origin Protocol PolicyについてはHTTPS Onlyにしました。そしてCDN認証用のカスタムヘッダの設定です。Origin Custom Headersの欄に、Header NameとしてX-MediaPackage-CDNIdentifierを、Valueとして認証コード(今回であれば8e2f1c52-f77f-4147-940d-5574975a1f81を)入力します。

その他の項目を適切に設定し、CloudFrontディストリビューションを作成します。(今回は基本デフォルト設定ですが、Object CachingをUse Origin Cache Headersであることを確認し、またComment欄に確認用コメントを記載しました。)

CDN認証されていることを確認する

CloudFrontディストリビューション作成、利用可能になったら実際にCDN認証されていることを確認してみます。MediaPackageへはMediaLiveから映像を送信し、ライブ視聴が可能な状況としました。

まずは先ほど認証用の設定を行ったCloudFrontディストリビューション経由でアクセスしてみます。MediaPackageのEndpoint URLは以下となります。

  • https://15bcxxxxxxxxxxxx.mediapackage.ap-northeast-1.amazonaws.com/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index.m3u8

ドメイン名をCloudFrontディストリビューションのものに置き換えて、以下でアクセスしてみます。

  • https://d1dxxxxxxxxxx.cloudfront.net/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index.m3u8

視聴確認にはVideoJS HTTP Streamingを使用しました。Video URLにCloudFrontドメイン名のURLを入力し、MimeType:application/x-mpegURLを確認して、[Load]ボタンを押します。問題なく再生できますね!

続いて、MediaPackageのエンドポイント(オリジン)に直接アクセスしてみましょう。以下のように403エラーとなってしまいました。オリジンへの直接アクセスが無効となっていることがわかります。

これらの内容を、curlコマンドを使って確認してみます。まずは認証設定を行ったCloudFrontからのアクセスです。m3u8ファイル、tsファイルとも、問題なくアクセスできていることが確認できます。

# トップレベルマニフェストファイル
[shimizu.toshiya@classmethod] [~]
 $ curl https://d1dxxxxxxxxxx.cloudfront.net/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-STREAM-INF:BANDWIDTH=5889549,AVERAGE-BANDWIDTH=3735564,RESOLUTION=1280x720,FRAME-RATE=29.970,CODECS="avc1.640029,mp4a.40.2"
index_1.m3u8

[shimizu.toshiya@classmethod] [~]
 $ curl -I https://d1dxxxxxxxxxx.cloudfront.net/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index.m3u8
HTTP/2 200
content-type: application/x-mpegURL
content-length: 197
date: Sun, 05 Jan 2020 07:32:16 GMT
server: nginx/1.16.1
cache-control: max-age=2
access-control-allow-origin: *
access-control-allow-credentials: true
x-mediapackage-request-id: 1a7fdf73affd3507e97bf07a731bd9cb
x-cache: Miss from cloudfront
via: 1.1 9a4e1846c6e75906d748bf1a4ae650c7.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT20-C4
x-amz-cf-id: clTTa5a8UbQ7AeZRtmqELY3O8lwmxSLQAatjWwbk3r13vGs0G0qHAg==


# ビットレートごとのマニフェストファイル(今回は1つのビットレートのみです)
[shimizu.toshiya@classmethod] [~]
 $ curl https://d1dxxxxxxxxxx.cloudfront.net/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index_1.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:7
#EXT-X-MEDIA-SEQUENCE:102
#EXTINF:6.006,
index_1_102.ts?m=1578206347
#EXTINF:6.006,
index_1_103.ts?m=1578206347
#EXTINF:6.006,
index_1_104.ts?m=1578206347
#EXTINF:6.006,
index_1_105.ts?m=1578206347
#EXTINF:6.006,
index_1_106.ts?m=1578206347
#EXTINF:6.006,
index_1_107.ts?m=1578206347
#EXTINF:6.006,
index_1_108.ts?m=1578206347
#EXTINF:6.006,
index_1_109.ts?m=1578206347
#EXTINF:6.006,
index_1_110.ts?m=1578206347
#EXTINF:6.006,
index_1_111.ts?m=1578206347

[shimizu.toshiya@classmethod] [~]
 $ curl -I https://d1dxxxxxxxxxx.cloudfront.net/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index_1.m3u8
HTTP/2 200
content-type: application/x-mpegURL
content-length: 505
date: Sun, 05 Jan 2020 07:32:29 GMT
server: nginx/1.16.1
cache-control: max-age=2
access-control-allow-origin: *
access-control-allow-credentials: true
x-mediapackage-request-id: 28c5727713bc3dc21c1a15487196eceb
x-cache: Miss from cloudfront
via: 1.1 01fbd7d01ff1478611d3936344040a80.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT20-C4
x-amz-cf-id: TcwEscWE8nudxhDd8wLcsvrBuoxT2pgpIYVD5LkpBAC_oBfdcS7bHA==


# tsファイル
[shimizu.toshiya@classmethod] [~]
 $ curl -I https://d1dxxxxxxxxxx.cloudfront.net/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index_1_111.ts
HTTP/2 200
content-type: video/MP2T
content-length: 2664524
date: Sun, 05 Jan 2020 07:32:57 GMT
server: nginx/1.16.1
cache-control: max-age=21600
access-control-allow-origin: *
access-control-allow-credentials: true
x-mediapackage-request-id: a9c3998bebc6a268035cb0b34da0ef63
x-cache: Miss from cloudfront
via: 1.1 ff8441cf5ba1180f46877d00029f6fec.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT20-C4
x-amz-cf-id: bGOv0aY4XdnAxSDAkBV2OFrdY76fO8Af0la0BR1Miz99clyw104nDA==

続いてMediaPackageのエンドポイントに直接アクセスしてみます。以下のように、403エラーでアクセスできないことがわかります。

# トップレベルマニフェストファイル
[shimizu.toshiya@classmethod] [~]
 $ curl https://15bcxxxxxxxxxxxx.mediapackage.ap-northeast-1.amazonaws.com/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index.m3u8
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
</body>
</html>
[shimizu.toshiya@classmethod] [~]
 $ curl -I https://15bcxxxxxxxxxxxx.mediapackage.ap-northeast-1.amazonaws.com/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index.m3u8
HTTP/2 403
date: Sun, 05 Jan 2020 07:33:34 GMT
content-type: text/html
content-length: 127
server: nginx
etag: "5df11fcd-7f"
x-mediapackage-request-id: 39c3070eb09412e003f386bfe64f45ab


# ビットレートごとのマニフェストファイル(今回は1つのビットレートのみです)
[shimizu.toshiya@classmethod] [~]
 $ curl https://15bcxxxxxxxxxxxx.mediapackage.ap-northeast-1.amazonaws.com/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index_1.m3u8
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
</body>
</html>
[shimizu.toshiya@classmethod] [~]
 $ curl -I https://15bcxxxxxxxxxxxx.mediapackage.ap-northeast-1.amazonaws.com/ou
t/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index_1.m3u8
HTTP/2 403
date: Sun, 05 Jan 2020 07:33:47 GMT
content-type: text/html
content-length: 127
server: nginx
etag: "5df11fcd-7f"
x-mediapackage-request-id: e8375b190767db29b128cdf2a15d8bf9


# tsファイル
[shimizu.toshiya@classmethod] [~]
 $ curl -I https://15bcxxxxxxxxxxxx.mediapackage.ap-northeast-1.amazonaws.com/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index_1_111.ts
HTTP/2 403
date: Sun, 05 Jan 2020 07:33:53 GMT
content-type: text/html
content-length: 127
server: nginx
etag: "5df11fcd-7f"
x-mediapackage-request-id: 9b497f87a32cb71b3f340cf01b36db23

続いてCloudFrontディストリビューションに設定したように、認証情報となるオリジンヘッダと認証コードを付与してのアクセスを確認してみましょう。curlコマンドにオプションで、ヘッダ名: X-MediaPackage-CDNIdentifierヘッダの値: 8e2f1c52-f77f-4147-940d-5574975a1f81(認証コード)を付与してアクセスしてみます。結果としては以下の通り、問題なくアクセスできることが確認できます。

# トップレベルマニフェストファイル
[shimizu.toshiya@classmethod] [~]
 $ curl -H 'X-MediaPackage-CDNIdentifier:8e2f1c52-f77f-4147-940d-5574975a1f81' https://15bcxxxxxxxxxxxx.mediapackage.ap-northeast-1.amazonaws.com/out/v1/f030d80
624d54368b8de354f48d65dbb/index.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-STREAM-INF:BANDWIDTH=5889549,AVERAGE-BANDWIDTH=3735564,RESOLUTION=1280x720,FRAME-RATE=29.970,CODECS="avc1.640029,mp4a.40.2"
index_1.m3u8

[shimizu.toshiya@classmethod] [~]
 $ curl -I -H 'X-MediaPackage-CDNIdentifier:8e2f1c52-f77f-4147-940d-5574975a1f81' https://15bcxxxxxxxxxxxx.mediapackage.ap-northeast-1.amazonaws.com/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index.m3u8
HTTP/2 200
date: Sun, 05 Jan 2020 07:35:18 GMT
content-type: application/x-mpegURL
content-length: 197
server: nginx/1.16.1
cache-control: max-age=2
access-control-allow-origin: *
access-control-allow-credentials: true
vary: Origin
x-mediapackage-request-id: 9ce6de933e6737ca16306bc127c9e248


# ビットレートごとのマニフェストファイル(今回は1つのビットレートのみです)
[shimizu.toshiya@classmethod] [~]
 $ curl -H 'X-MediaPackage-CDNIdentifier:8e2f1c52-f77f-4147-940d-5574975a1f81' https://15bcxxxxxxxxxxxx.mediapackage.ap-northeast-1.amazonaws.com/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index_1.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:7
#EXT-X-MEDIA-SEQUENCE:133
#EXTINF:6.006,
index_1_133.ts?m=1578206347
#EXTINF:6.006,
index_1_134.ts?m=1578206347
#EXTINF:6.006,
index_1_135.ts?m=1578206347
#EXTINF:6.006,
index_1_136.ts?m=1578206347
#EXTINF:6.006,
index_1_137.ts?m=1578206347
#EXTINF:6.006,
index_1_138.ts?m=1578206347
#EXTINF:6.006,
index_1_139.ts?m=1578206347
#EXTINF:6.006,
index_1_140.ts?m=1578206347
#EXTINF:6.006,
index_1_141.ts?m=1578206347
#EXTINF:6.006,
index_1_142.ts?m=1578206347

[shimizu.toshiya@classmethod] [~]
 $ curl -I -H 'X-MediaPackage-CDNIdentifier:8e2f1c52-f77f-4147-940d-5574975a1f81' https://15bcxxxxxxxxxxxx.mediapackage.ap-northeast-1.amazonaws.com/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index_1.m3u8
HTTP/2 200
date: Sun, 05 Jan 2020 07:35:37 GMT
content-type: application/x-mpegURL
content-length: 505
server: nginx/1.16.1
cache-control: max-age=2
access-control-allow-origin: *
access-control-allow-credentials: true
vary: Origin
x-mediapackage-request-id: 116dd66eb954c59db8073c650d687918


# tsファイル
[shimizu.toshiya@classmethod] [~]
 $ curl -I -H 'X-MediaPackage-CDNIdentifier:8e2f1c52-f77f-4147-940d-5574975a1f81' https://15bcxxxxxxxxxxxx.mediapackage.ap-northeast-1.amazonaws.com/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index_1_142.ts
HTTP/2 200
date: Sun, 05 Jan 2020 07:35:46 GMT
content-type: video/MP2T
content-length: 2688212
server: nginx/1.16.1
cache-control: max-age=21600
access-control-allow-origin: *
access-control-allow-credentials: true
vary: Origin
x-mediapackage-request-id: 972f624d87acdd733c5400815314deeb

なお、当然ながらX-MediaPackage-CDNIdentifierのヘッダを持っていても、認証コードが正しいものでなければアクセスはできません。

# トップレベルマニフェストファイル
[shimizu.toshiya@classmethod] [~]
 $ curl -I -H 'X-MediaPackage-CDNIdentifier:happy-new-year' https://15bcxxxxxxxxxxxx.mediapackage.ap-northeast-1.amazonaws.com/out/v1/f030xxxxxxxxxxxxxxxxxxxxxxxxxxxx/index.m3u8
HTTP/2 403
date: Sun, 05 Jan 2020 07:43:28 GMT
content-type: text/html
content-length: 127
server: nginx
etag: "5df11fcd-7f"
x-mediapackage-request-id: 0f6f123ebeccf7d020ff34d6ed9c24f2

まとめ

AWS Elemental MediaPackageの認証機能によるオリジンエンドポイント保護について、実際に設定を行い確認してみました。これまでCloudFront側で署名付きCookieなどでアクセス可否を設定する場合などにおいて、オリジンとなるMediaPackageのアクセス保護は課題でした。IPアドレスでのアクセス許可設定は可能でしたが、CloudFrontの全IPを登録するなどはあまり現実的ではありません。仕方なく推測しにくいEndpoint URLのみで凌ぐ、ということもあったのではないでしょうか。今回の認証機能によるエンドポイント保護のアップデートで、よりセキュアに配信が行なえますね!非常にうれしいアップデートだと思います。2020年も引き続き、AWS Elemental MediaPackageをはじめとしたAWS Media Servicesの機能アップデートに注目していきたいと思います。