S3 にホストした Web サイトで HTTPS を強制する

Study

概要

CloudFront + S3 で HTTPS を強制した Web サイトを構成する2種類の方法を知った話。

経緯

S3 にホスティングした Web サイトを HTTPS 対応させるために、CloudFront が必要だということは元々知っていた。

S3 と CloudFront を構築後、HTTPS を強制するために Origin Access Control (OAC) を設定しようとしたが、CloudFront の設定項目に OAC が見当たらなかったので、調査を開始。

調べていると、CloudFront のオリジンとして、S3 の Web ホスティング用エンドポイントを使用しているものと、S3 の Rest API エンドポイントを使用しているものの2種類が見つかり、ちょっと混乱した。

S3 での Web ホスティング

S3 (Simple Storage Service) は、AWS においてストレージを提供するサービスである。S3 は大規模データの保存に適したオブジェクトストレージであり、AWS のリソースから取得されたログや、バックアップ・スナップショットのデータを保存するために使用されることが多い。

S3 には静的 Web サイトホスティングという機能があり、S3 に保存されたデータをコンテンツとする Web サイトを構築することができる。メリットは、比較的低コストで Web サーバを構築できる点、アクセス増加にも対応できる点である。あくまで静的コンテンツ用なので、使用可能なのは HTML、CSS、JavaScript 辺り。

しかし、S3 による Web サイトホスティングだけでは HTTPS に対応することができない。そのため、HTTPS に対応させる際には、CloudFront を利用する。

CloudFront はコンテンツ配信の高速化のために用いられる CDN (Content Delivery Network) サービスである。CloudFront では SSL 証明書を設定することができるため、クライアントからの HTTPS 通信を実現できる。

CloudFront 経由の強制

Web サイトへのアクセスで HTTPS を強制したい場合には、S3 にアクセスする際に CloudFront 経由を必須化する設定が必要になる。

CloudFront と S3 を使用して静的 Web サイトを構成する場合、2種類のエンドポイントが使用できるが、それぞれ、CloudFront 経由を必須化するための設定方法が異なる

  • REST API エンドポイント
  • Web サイトエンドポイント

ここからは、それぞれのエンドポイントにおける、CloudFront 経由を強制する設定について説明する。

なお、動作確認の際には、S3 バケット s3-web-hosting-bucket に以下のような index.html を配置している。

<!DOCTYPE html>
    <html>
        <head>
            <title>Content from the S3 bucket</title>
        </head>
    <body>
        <h1>Content from the S3 bucket</h1>
        <p>This content was retrieved from the S3 bucket.</p>
    </body>
</html>

REST API エンドポイントの場合

REST API エンドポイントを使用している記事。

CloudFront 経由で S3 のファイルにアクセスする - Qiita
もくじCloudFront 経由で S3 のファイルにアクセスできるようにする独自ドメインで CloudFront にアクセスできるようにするCloudFront 経由の時だけ S3 のファイ…

REST API エンドポイントは、[バケット名].s3.ap-northeast-1.amazonaws.com のような形式。

REST API とは何か。それは今後の課題としたいが、要は REST API エンドポイントとは、S3 で通常使用できるエンドポイントである。

CloudFront でオリジンを設定する際に、プルダウンに現れる。

CloudFront 経由を必須化する場合、Origin Access Control (OAC) を使用することになる。設定するのは、CloudFront の OAC と S3 のバケットポリシーの2点。

CloudFront のオリジンの設定を開き、「Origin access control settings (recommended)」を選択後、「Create control setting」をクリック。

「Control setting」を作成する。

「Copy policy」をクリックして、ポリシーをコピーする。

コピーしたポリシーを、S3 のバケットポリシーとして設定する。

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::s3-web-hosting-bucket/*",
            "Condition": {
                "StringEquals": {
                  "AWS:SourceArn": "arn:aws:cloudfront::[アカウント ID]:distribution/[ディストリビューション ID]"
                }
            }
        }
    ]
}

REST API エンドポイントからアクセスした場合。
(※ Web サイトエンドポイントではないため、アクセスしたいファイルのパス「index.html」を指定する必要がある。)

CloudFront のドメインからアクセスした場合。
(※ Web サイトエンドポイントではないため、アクセスしたいファイルのパス「index.html」を指定する必要がある。)

CloudFront 経由の場合のみコンテンツが表示された。

Web サイトエンドポイントの場合

Web サイトエンドポイントを使用している記事。

S3静的webサイトへのアクセスをCloudFront経由のみに制限する - Qiita
CloudFrontのOrigin Custom HeaderとS3バケットポリシーを設定していきます。CloudFront経由時のみに付加されるヘッダーを利用してバケットポリシーで制御する、とい…

Web サイトエンドポイントは、[バケット名].s3-website-ap-northeast-1.amazonaws.com のような形式。

Web サイトエンドポイントとは、S3 で静的 Web サイトホスティングを有効化すると利用可能になるエンドポイントである。

静的 Web サイトホスティングとは、S3 のコンテンツを 静的 Web サイトとして利用する際に設定する機能である。次に示すように、サイトのトップページやエラーページ、リダイレクトのルール等を設定することができる。

CloudFront 経由を必須化する場合、Referer ヘッダでの制限を使用することになる。設定するのは、CloudFront のヘッダと S3 のバケットポリシーの2点。

CloudFront のオリジンの設定で、Referer ヘッダ(Name:Referer、Value:任意の値)を追加する。コンテンツを取得する際には、このヘッダを含むリクエストが S3 に送られる。

S3 のバケットポリシーを設定する。ここでは、コンテンツを取得するリクエストに対して、「from-cloudfront」 という Referer ヘッダを含む場合のみアクセスを許可している。
(※ ヘッダさえ設定されていれば CloudFront 経由以外でのアクセスも可能なため、Referer ヘッダには、簡単に推測されないような値を設定することが推奨される。)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion"
            ],
            "Resource": "arn:aws:s3:::s3-web-hosting-bucket/*",
            "Condition": {
                "StringLike": {
                    "aws:Referer": "from-cloudfront"
                }
            }
        }
    ]
}

Web サイトエンドポイントからアクセスした場合。

CloudFront のドメインからアクセスした場合。

CloudFront 経由の場合のみコンテンツが表示された。

どっちがいい?

ここからは半ば感想。選択肢があるならどっちがいいのか。

今のところ、「Web サイトエンドポイント + Referer 制限」推し。メリットはこれくらい。

  • 静的 Web ホスティングの機能(トップページ、エラーページ、リダイレクト等)が利用できる。
  • 新たなリソース(Origin Access Control setting)を作成しなくていい。

1つ目については、CloudFront でもデフォルトルートオブジェクトの設定とかがあるから、ある程度は対応できるだろうけど、オリジンごとに設定できた方が柔軟性があるような気がする。
2つ目については、リソースを増やさずに対応できるなら増やしたくないかなって感じ。

デメリットは、ヘッダさえ正しく設定されていれば、CloudFront 以外からもアクセスできてしまうこと。逆に言うと、「REST API エンドポイント + OAC」の方が設定としては厳格という印象

2022年12月18日追記。「REST API エンドポイント + OAC」推しになった。理由はこちらから。

感想

CloudFront と S3 で Web サイトを公開する場合でも、静的 Web サイトホスティングの有効化は必須の設定だと思っていた。CloudFront を使用する場合、静的 Web サイトホスティングを有効化しなくとも、Web サイトとしての公開は可能である。

CloudFront 経由を必須化するために、OAC を使用することは何となく知っていたが、REST API エンドポイントの場合のみ使用できるとは知らなかった。

ちなみに、今回の内容は友人に教えようとしたときに詰まったところ。アウトプットの重要性を改めて感じた。

関係ないけど、AWS コンソールのダークテーマ対応ありがたい。ちょこちょこ対応してない部分もあるけど。特に古の画面。
そもそも AWS CLI で構築できるようになれっていう話。

参考

CDN(Content Delivery Network)
CDNとは、インターネット上のウェブコンテンツを安定的に配信するために最適化されたネットワークのことです。
CloudFront を使用して Amazon S3 でホストされている静的ウェブサイトを提供する
Amazon Simple Storage Service (Amazon S3) バケットを使用して静的ウェブサイトをホストしたいと考えています。それから、Amazon CloudFront ディストリビューションを通じてウェブサイトを提...
バケットポリシーの例 - Amazon Simple Storage Service
Amazon S3 バケットポリシーの一般的なユースケースの例。
タイトルとURLをコピーしました