CloudFrontで署名付きCookieを実装し、CORSを設定する
経緯
開発中のアプリケーションで署名付きCookieで制限しながらCloudFrontから別ドメインのS3にある動画ストリーミング用のHLSファイルにアクセスする要件がありました。
HLS(HTTP Live Streaming)とは?概要・仕組み・課題など|Agora Go Real|オンラインイベント・ウェビナー・Web会議ブイキューブ
構成
構成は下記の通りです。
発生した問題
問題1 リクエストヘッダーの値とCORS設定
S3からOACでアクセスするためにCloudFrontのオリジンリクエストポリシーはCORS-S3Originで設定し、署名付きCookieを使用してアクセスすると下記のようなエラーが発生しました。
Access to XMLHttpRequest at '[https://video.domain/filename.m3u8](https://video.domain/filename.m3u8)' from origin '[https://origin.domain](https://origin.domain/)' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
よくわからないのでChatGPTに聞いてみました。
このエラーはCORS(Cross-Origin Resource Sharing)ポリシーに関連しており、あるオリジンから別のオリジンにあるリソースへのアクセスが制限されていることを示しています。具体的には、'Access-Control-Allow-Origin'ヘッダの値がワイルドカード'*'であるときに、リクエストの資格情報モードが'include'であってはならないという制約に違反しています。この問題を解決するには、AWS S3バケットとCloudFrontのCORS設定を確認し、適切に設定する必要があります。
以下にその手順を説明します。イメージとしては、あなたが鍵を持っている部屋のドアを開けるような感じです。鍵が合っているときだけドアを開けることができます。
調べてみると、S3のCORS設定でAllowedOriginsがワイルドカードであるとわかりました。
解決策
AllowdOriginsをワイルドカード(*)からクロスオリジンクエストを許可する設定に変更します。
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET"
],
"AllowedOrigins": [
"https://*.origin.domain"
],
"ExposeHeaders": []
}
]
また、ChatGPTによるとリクエストヘッダーに基づくコンテンツキャッシュの設定も良くないことがわかりました。
- 次に、CloudFrontの設定を確認します。特に「Behaviors」設定の「Cache and origin settings」で、「Cache Based on Selected Request Headers」を「Whitelist」に設定し、「Whitelist Headers」に
Origin
を追加します。
これは、ドアが正しい鍵で開けられるように設定するようなものです。
今回は動画配信なのでキャッシュするヘッダーはOriginだけ設定します。
さらにエラーが発生
このように設定すると先ほどと同じエラーはなくなったものの、次のようなエラーが発生しました。やはりAccess-Control-Allow-Originに何か問題があるようです。
Access to XMLHttpRequest at 'https://video.domain/filename.m3u8' from origin 'https://origin.domain' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
問題2 Cookieを許可するためのヘッダーが足りない
この問題は、クライアントが送信している署名付きCookieをCORSリクエストで送信する際に起こっていたようです。
下記の記事を参考にさせていただきました。
CORSリクエストでクレデンシャル(≒クッキー)を必要とする場合の注意点 - Qiita
署名付きクッキーによるCloudFront配信コンテンツの保護 - Qiita
Cookieを許可してCORSリクエストを送信するレスポンスヘッダーの条件は下記のとおりです。
- Access-Control-Allow-Credentialsがtrueであること
- Access-Control-Allow-Originがワイルドカード(*)でないこと
解決策
ビヘイビアの設定でCloudFrontのレスポンスヘッダーにカスタムポリシーを追加します。
※今回はAccess-Control-Allow-Headersが*ではエラーが発生するので、適当な値を設定していましたがこのままで正しいのか不明でした。
結果
今回は上記の設定で無事に動画のストリーミング配信ができるようになりました。
結果的にはうまくいったものの試行錯誤で進めており、検証不十分な部分があるのではないかと考えています。
よろしければご指摘などいただけますと幸いです!
追記:AllowedOriginについて
こちらのCORS設定のエラーはAccess-Control-Allow-Originの設定がTrueの際に許可をするドメインが指定されていない時に発生します。
このヘッダーはCloudFront側のレスポンスヘッダーに設定することもできます。この場合、CloudFront側の設定が上書きされるためS3のCORS設定はワイルドカードでもリクエストが通ることになります。
詳しくはこちらのドキュメントをご参照ください。
Discussion