Refererヘッダーを使用してCloudFront経由でS3コンテンツを配信する

目次

CloudFrontからS3コンテンツを配信する際に、オリジンへのアクセスをReferer ヘッダーで制限する

以下のページで、静的ウェブサイトホスティング機能を有効化したS3バケットのコンテンツを、CloudFront経由で配信する方法をご紹介しました。

あわせて読みたい
CloudFront経由でS3コンテンツを配信する – 静的ウェブサイトホスティング版 【CloudFront経由でS3コンテンツを配信する】 CDNサービスであるCloudFrontを使用して、S3バケットに配置したコンテンツを配信することができます。今回は静的ウェブサ...

ただし上記の構成には1つ課題があります。
それはオリジンであるS3バケットに直接アクセスできてしまうという点です。

今回は以下の公式ページを参考に、CloudFront経由のアクセスを強制することを目指します。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudfront-serve-static-website/

今回ご紹介する方法のポイントをまとめます。

  • CloudFront:オリジンカスタムヘッダーのRefererヘッダーを設定する。
  • S3:バケットポリシーでコンテンツへのアクセスを許可する条件に、Refererヘッダーの値を含める。

なおOAI(Origin Access Identity)を使用することで、今回の構成と同様の動作を実現するすることもできます。こちらも併せてご確認ください。

あわせて読みたい
OAIを使用してCloudFront経由でS3コンテンツを配信する 【CloudFrontからS3コンテンツを配信する際に、OAIでオリジンへのアクセスを制限する】 以下のページで、S3バケットのコンテンツをCloudFrontから配信する際に、Referer...

構築する環境

Diagram of S3 content delivery via CloudFront - Referer header ver

全体的な構成は以前と同様です。
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ヘッダーのチェックを行います。
以下の公式サイトを参考に設定します。

https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies.html#example-bucket-policies-use-case-4

ポイントはConditionプロパティです。
本プロパティの内部で、StringLikeおよびaws:Refererプロパティを使用することで、Refererヘッダー値をチェックすることができます。
この項目に「fa-049」を設定することで、Refererヘッダーにこの文字列がセットされている場合に限り、アクセスを許可するという挙動を実現できます。
これでCloudFront側で設定したヘッダー情報と等しくなりますので、CloudFront経由でアクセスした場合は、アクセスが許可されることになります。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

あわせて読みたい
CloudFormationのネストされたスタックで環境を構築する 【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を確認します。

CloudFront Referer header settings.

S3のバケットウェブサイトエンドポイントがオリジンとして設定されています。
ポイントはヘッダー情報です。
Refererヘッダーに対して「fa-049」という文字列が設定されています。

次にS3バケットのバケットポリシーを確認します。

Bucket Policy Referer Header Settings.

Refererヘッダーの条件が設定されています。

動作確認

準備が整いましたので、CloudFrontディストリビューションにアクセスします。

Access results with Referer header set.

S3バケットのコンテンツが表示されました。
CloudFrontを経由して、オリジンであるS3バケットのウェブサイトエンドポイントにアクセスしているということです。

次にオリジンであるS3バケットに、直接アクセスしてみます。

Access results when Referer header is not set.

エラーが返ってきました。
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経由でアクセスすることを強制する方法をご紹介しました。

目次