CloudFrontからS3コンテンツを配信する際に、オリジンへのアクセスをReferer ヘッダーで制限する
以下のページで、静的ウェブサイトホスティング機能を有効化したS3バケットのコンテンツを、CloudFront経由で配信する方法をご紹介しました。
ただし上記の構成には1つ課題があります。
それはオリジンであるS3バケットに直接アクセスできてしまうという点です。
今回は以下の公式ページを参考に、CloudFront経由のアクセスを強制することを目指します。
https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudfront-serve-static-website/
今回ご紹介する方法のポイントをまとめます。
- CloudFront:オリジンカスタムヘッダーのRefererヘッダーを設定する。
- S3:バケットポリシーでコンテンツへのアクセスを許可する条件に、Refererヘッダーの値を含める。
なおOAI(Origin Access Identity)を使用することで、今回の構成と同様の動作を実現するすることもできます。こちらも併せてご確認ください。
構築する環境
全体的な構成は以前と同様です。
CloudFrontとS3バケットポリシーに、Refererヘッダーの設定を行います。
CloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。
https://github.com/awstut-an-r/awstut-fa/tree/main/049
テンプレートファイルのポイント解説
本ページでは、Refererヘッダーを使用したオリジンへのアクセス制限方法を中心に取り上げます。
それ以外の内容については、冒頭でご紹介したページをご確認ください。
CloudFrontでオリジンカスタムヘッダーを設定する
Resources:
Distribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
Compress: true
ForwardedValues:
Cookies:
Forward: none
QueryString: false
TargetOriginId: !Ref BucketName
ViewerProtocolPolicy: allow-all
Enabled: true
Origins:
- DomainName: !Select
- 2
- !Split
- /
- !Ref BucketWebsiteURL
Id: !Ref BucketName
CustomOriginConfig:
OriginProtocolPolicy: http-only
OriginCustomHeaders:
- HeaderName: Referer
HeaderValue: !Ref Prefix
PriceClass: PriceClass_All
Code language: YAML (yaml)
静的ウェブサイトホスティング機能を有効化したS3バケットにおいて、CloudFrontを経由するアクセスを強制するためには、Refererヘッダーを使ったアクセス制限が有効です。
ディストリビューションにカスタムの Referer ヘッダーを設定し、次にバケットポリシーを使用してカスタムの Referer ヘッダーを持つリクエストにのみアクセスを許可することで、アクセスを制限します。
CloudFront を使用して、Amazon S3 でホストされた静的ウェブサイトを公開するにはどうすればよいですか?
CloudFrontからオリジンへのアクセス時のヘッダーをカスタムする場合、OriginCustomHeadersプロパティで設定が可能です。
このプロパティの内部では、HeaderNameおよびHeaderValueプロパティでヘッダー情報が設定可能です。
上記の引用に従い、HeaderNameプロパティは「Referer」を設定します。
HeaderValueプロパティに設定するべき値ついては、公式サイトで以下の通りに説明されています。
[値] には、オリジンに転送するカスタマーヘッダー値を入力します (S3 バケット)。オリジンへのアクセスを制限するために、ランダムな値または他の人は知らない秘密の値を入力します。
CloudFront を使用して、Amazon S3 でホストされた静的ウェブサイトを公開するにはどうすればよいですか?
ですから今回は組み込み関数Fn::Refを使用して「fa-049」という文字列を設定することにします。
バケットポリシーでRefererヘッダーの値を条件に含める
Resources:
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref Bucket
PolicyDocument:
Statement:
Action:
- s3:GetObject
Effect: Allow
Resource: !Sub "arn:aws:s3:::${Bucket}/*"
Principal: "*"
Condition:
StringLike:
aws:Referer:
- !Ref Prefix
Code language: YAML (yaml)
バケットポリシーでRefererヘッダーのチェックを行います。
以下の公式サイトを参考に設定します。
ポイントはConditionプロパティです。
本プロパティの内部で、StringLikeおよびaws:Refererプロパティを使用することで、Refererヘッダー値をチェックすることができます。
この項目に「fa-049」を設定することで、Refererヘッダーにこの文字列がセットされている場合に限り、アクセスを許可するという挙動を実現できます。
これでCloudFront側で設定したヘッダー情報と等しくなりますので、CloudFront経由でアクセスした場合は、アクセスが許可されることになります。
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
CloudFormationスタックを作成し、スタック内のリソースを確認する
CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。
各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- S3バケット:fa-049
- S3バケットのウェイブサイトエンドポイント:http://fa-049.s3-website-ap-northeast-1.amazonaws.com/
- CloudFrontディストリビューションのドメイン:https://d27wmgzizu923r.cloudfront.net/
AWS Management ConsoleからもCloudFrontを確認します。
S3のバケットウェブサイトエンドポイントがオリジンとして設定されています。
ポイントはヘッダー情報です。
Refererヘッダーに対して「fa-049」という文字列が設定されています。
次にS3バケットのバケットポリシーを確認します。
Refererヘッダーの条件が設定されています。
動作確認
準備が整いましたので、CloudFrontディストリビューションにアクセスします。
S3バケットのコンテンツが表示されました。
CloudFrontを経由して、オリジンであるS3バケットのウェブサイトエンドポイントにアクセスしているということです。
次にオリジンであるS3バケットに、直接アクセスしてみます。
エラーが返ってきました。
Refererヘッダーが設定されていないため、バケットポリシーでアクセス拒否されたということです。
ただしこの方法にも課題があります。
それはRefererヘッダーを設定しさえすれば、依然として直接オリジンにアクセスすることが可能だという点です。
curlコマンドでヘッダー情報を設定した上で、オリジンにアクセスします。
$ curl -H "Referer:fa-049" http://fa-049.s3-website-ap-northeast-1.amazonaws.com/
<html>
<head></head>
<body>
<h1>index.html</h1>
<p>fa-049</p>
</body>
</html>
Code language: Bash (bash)
直接オリジンにアクセスできてしまいました。
このようにRefererヘッダーを使ってアクセス制限する方法は効果的ですが、万能ではない点にご注意ください。
まとめ
S3バケットのコンテンツを配信する際に、Refererヘッダーを使用することによって、CloudFront経由でアクセスすることを強制する方法をご紹介しました。