コンテンツにスキップ

CloudFront@AWSリソース

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. CloudFrontとは

CDN (グローバルなキャッシュサーバー) かつクラウドリバースプロキシサーバーとして働く。

リバースプロキシでもあるため、CloudFrontの後段にアプリケーションをおけば、アプリケーションをそのまま公開できる。

VPCの外側 (パブリックネットワーク) に配置されている。

オリジンサーバー (コンテンツ提供元) をS3とした場合、動的コンテンツに対するリクエストをEC2に振り分ける。

また、静的コンテンツに対するリクエストをキャッシュし、その上でS3へ振り分ける。

次回以降の静的コンテンツのリンクエストは、CloudFrontがレンスポンスを実行する。

AWSのクラウドデザイン一例


02. セットアップ

Distributions

▼ Distributions

設定項目 説明 補足
General
Origin and Origin Groups コンテンツを提供するAWSリソースを設定する。
Behavior オリジンにリクエストが行われた時のCloudFrontの挙動を設定する。
ErrorPage 指定したオリジンから、指定したファイルを含むレスポンスを返信する。
Restriction
Invalidation CloudFrontに保存されているキャッシュを削除できる。

▼ General

設定項目 説明 補足
Price Class 使用するエッジロケーションを設定する。 Asiaが含まれているものを選択。
WAF CloudFrontに紐付けるWAFを設定する。
CNAME CloudFrontのデフォルトドメイン名 (<発行されたランダム文字列>.cloudfront.net.) に紐付けるDNSレコード名を設定する。 ・Route53からルーティングする場合は必須。
・複数のレコード名を設定できる。
SSL Certificate HTTPSプロトコルでオリジンにルーティングする場合に設定する。 上述のCNAMEを設定した場合、SSL証明書が別途必要になる。また、Certificate Managerを使用する場合、この証明書は『バージニア北部』で申請する必要がある。
Security Policy リクエストの送信者が使用するSSL/TLSプロトコルや暗号化方式のバージョンに合わせて、CloudFrontが受信できるこれらのバージョンを設定する。 ・リクエストの送信者には、ブラウザ、APIにリクエストを送信する外部サービス、ルーティング元のAWSリソース、などを含む。
・- https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/secure-connections-supported-viewer-protocols-ciphers.html
Default Root Object オリジンのドキュメントルートを設定する。 ・何も設定しない場合、ドキュメントルートは指定されず、Behaviorで明示的にルーティングする必要がある。
・index.htmlを設定すると、『/』でリクエストした時に、オリジンのルートディレクトリ配下にあるindex,htmlファイルがドキュメントルートになる。
Standard Logging CloudFrontのアクセスログをS3に作成するか否かを設定する。

▼ Origin and Origin Groups

設定項目 説明 補足
Origin Domain Name CloudFrontをリバースプロキシサーバーとして、AWSリソースのエンドポイントやDNSにルーティングする。 ・例えば、S3のエンドポイント、ALBのDNS名を設定する。
・別アカウントのAWSリソースのDNS名であっても良い。
Origin Path オリジンのルートディレクトリを設定する。 ・何も設定しないと、デフォルトは『/』のなる。Behaviorでは、『/』の後にパスが追加される。
・『/var/www/foo』を設定すると、Behaviorで設定したパスが『/var/www/foo/foo』のように追加される。
Origin Access Identity リクエストのルーティング先となるAWSリソースで認可スコープの紐付けが必要な場合に設定する。ルーティング先のAWSリソースでは、アクセスポリシーを紐付ける。 CloudFrontがS3に対して読み出しを実行するために必要。
Origin Protocol Policy リクエストのルーティング先となるAWSリソースに対して、HTTPとHTTPSのいずれのプロトコルでルーティングするかを設定する。 ・ALBで必要。ALBのリスナーのプロトコルに合わせて設定する。
HTTP Only:HTTPプロトコルでルーティング
HTTPS Only:HTTPSプロトコルでルーティング
Match Viewer:両方でルーティング
HTTPポート ルーティング時に指定するオリジンのHTTPのポート番号
HTTPSポート ルーティング時に指定するオリジンのHTTPSのポート番号

▼ Behavior

設定項目 説明 補足
Precedence 処理の優先順位。 最初に作成したBehaviorが『Default (*)』となり、これは後から変更できないため、主要なBehaviorをまず最初に設定する。
Path pattern Behaviorを実行するパスを設定する。
Origin and Origin Group Behaviorを実行するオリジンを設定する。
Viewer Protocol Policy HTTP/HTTPSのどちらを受信するか、またどのように変換してルーティングするかを設定 HTTP and HTTPS:両方受信し、そのままルーティング
Redirect HTTP to HTTPS:両方受信し、HTTPSプロトコルでルーティング
HTTPS Only:HTTPSのみ受信し、HTTPSプロトコルでルーティング
Allowed HTTP Methods リクエストのHTTPメソッドのうち、オリジンへのルーティングを許可するものを設定 ・パスパターンが静的ファイルに対するリクエストの場合、GETのみ許可。
・パスパターンが動的ファイルに対するリクエストの場合、全てのメソッドを許可。
Object Caching CloudFrontにコンテンツのキャッシュを保存しておく秒数を設定する。 ・Origin Cacheヘッダーを選択した場合、アプリケーションからのレスポンスヘッダーのCache-Controlの値が適用される。
・カスタマイズを選択した場合、ブラウザのTTLとは別に設定できる。
TTL CloudFrontにキャッシュを保存しておく秒数を詳細に設定する。 ・Min、Max、Default、の全てを0秒とすると、キャッシュを無効化できる。
・『Headers = All』としている場合、キャッシュが実質無効となるため、最小TTLはゼロである必要がある。
・キャッシュの最終的な有効期間は、CloudFrontのTTL秒の設定、Cache-Controlヘッダー、Expiresヘッダー値の組み合わせによって決まる。
Whitelist Header Headers を参考にせよ。 Accept-*****:アプリケーションにレスポンスして欲しいデータの種類 (データ型など) を指定。
CloudFront-Is-*****-Viewer:デバイスタイプのboolean値が格納されている。
- https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html#ExpirationDownloadDist
Restrict Viewer Access リクエストの送信元を制限するか否かを設定できる。 セキュリティグループで制御できるため、ここでは設定しなくて良い。
Compress Objects Automatically レスポンス時に.gzipファイルとして圧縮するか否かを設定 ・クライアントからのリクエストヘッダーのAccept-Encodingにgzipが設定されている場合、レスポンス時に、gzip形式で圧縮して送信するか否かを設定する。設定しない場合、圧縮せずにレスポンスを返信する。
・クライアント側のダウンロード速度向上のため、基本的には有効化する。

▼ オリジンに対するリクエストの構造

CloudFrontからオリジンに送信されるリクエストの構造例を以下に示す。

GET /foo/
---
# リクエストされたドメイン名
Host: foo.example.com
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1
Authorization: Bearer <Bearerトークン>
X-Amz-Cf-Id: *****
Via: 2.0 <発行されたランダム文字列>.cloudfront.net (CloudFront)
# 各Cookieの値 (二回目のリクエスト時に設定される)
Cookie: sessionid=<セッションID>; __ulfpc=<GoogleAnalytics値>; _ga=<GoogleAnalytics値>; _gid=<GoogleAnalytics値>
# 送信元IPアドレス
# ※プロキシ (ALBやCloudFrontなども含む) を経由している場合、それら全てのIPアドレスが順に設定される
X-Forwarded-For: <client>, <proxy1>, <proxy2>
Accept-Language: ja,en;q=0.9
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
pragma: no-cache
cache-control: no-cache
upgrade-insecure-requests: 1
sec-fetch-site: none
sec-fetch-mode: navigate
sec-fetch-user: ?1
sec-fetch-dest: document
# デバイスタイプ
CloudFront-Is-Mobile-Viewer: "true"
CloudFront-Is-Tablet-Viewer: "false"
CloudFront-Is-SmartTV-Viewer: "false"
CloudFront-Is-Desktop-Viewer: "false"
# リクエストの送信元の国名
CloudFront-Viewer-Country: JP
# リクエストのプロトコル
CloudFront-Forwarded-Proto: https

▼ CloudFrontとオリジン間のHTTPSプロトコル

CloudFrontとオリジン間でHTTPSプロトコルを使用する場合、両方にSSL証明書を割り当てる必要がある。

割り当てたとしても、以下の条件を満たさないとHTTPSプロトコルを使用することはできない。

CLoudFrontからオリジンにHostヘッダーをルーティングしない設定の場合、オリジンが返却する証明書に『Origin Domain Name』と一致するドメイン名が含まれている必要がある。

一方で、Hostヘッダーをルーティングしない場合、オリジンが返却する証明書に『Origin Domain Name』と一致するドメイン名が含まれているか、またはオリジンが返却する証明書に、Hostヘッダー値と一致するドメイン名が含まれている必要がある。


Reports & analytics

▼ Cache statistics

リクエストに関連する様々なデータを、日付別に集計したものを確認できる。

リクエストに関連する様々なデータを、オブジェクト別に集計したものを確認できる。


03. CloudFrontの仕組み

Point Of Presence

CloudFrontは世界中に配置される『Point Of Presence (エッジロケーション+中間層キャッシュ) 』にデプロイされる。


CloudFront DNS

CloudFrontのドメイン (<発行されたランダム文字列>.cloudfront.net) の正引きに応じて、エッジサーバーのIPアドレスを返却する。

CloudFrontのドメインは、AWS Route53のDNSレコードとして登録する。

cloudfront_architecture.png


エッジサーバー

▼ エッジサーバーとは

地理的にクライアントから最も近い場所にあるキャッシュサーバーである。

▼ 全エッジサーバーのIPアドレス

CloudFrontには、エッジロケーションの数だけエッジサーバーがあり、各サーバーにIPアドレスが割り当てられている。

以下のコマンドで、全てのエッジサーバーのIPアドレスを確認できる。

$ curl -X GET https://ip-ranges.amazonaws.com/ip-ranges.json \
    | jq ".prefixes[]| select(.service=="CLOUDFRONT") | .ip_prefix"

もしくは、以下のリンクを直接的に参考し、『"service": "CLOUDFRONT"』となっている部分を探す。

▼ 使用中サーバーのIPアドレス

CloudFrontには、エッジロケーションがあり、各ロケーションにサーバーがある。

以下のコマンドで、エッジロケーションにある使用中サーバーのIPアドレスを確認できる。

$ nslookup <発行されたランダム文字列>.cloudfront.net


04. キャッシュ

オリジンリクエストの可否、キャッシュ作成の有無

▼ オリジンリクエストの可否、キャッシュ作成の有無、の決まり方

オリジンにルーティングする必要があるリクエストを、各種パラメーターのAll (全許可) /一部許可/None (全拒否) で設定できる。

また、キャッシュ作成の有無にも関係している。

CloudFrontではリクエストがJSONとして扱われており、JSONの値が過去のリクエストに合致した時のみ、そのリクエストと過去のものが同一であると見なす仕組みになっている。

キャッシュ判定時のパターンを減らし、ヒット率を向上させるために、全ての項目で『None (全拒否) 』を選択した方が良い。

最終的に、対象のファイルがCloudFrontのキャッシュ作成の対象となっているかは、レスポンスのヘッダーに含まれる『X-Cache:』が『Hit from cloudfront』または『Miss from cloudfront』のどちらで判断できる。

▼ ヘッダー値に基づくキャッシュ作成

リクエストヘッダーのうち、オリジンへのルーティングを許可し、加えてキャッシュキーと見なすパラメーターを設定する。

Cookieとクエリストリングと比べて、同じ設定でもキャッシュ作成の有無が異なることに注意する。

機能名 オリジンリクエストの可否 キャッシュ作成の有無
全許可 全てのヘッダーのルーティングを許可する。 キャッシュを作成しない。
一部ルーティング 一部のヘッダーのルーティングを拒否し、ヘッダーの無いリクエストをルーティングする。 指定したヘッダーのみをキャッシュキーとみなす。日付に関するヘッダー (例:Accept-Datetime) などの動的な値をキャッシュキーとしてしまうと。同一と見なすリクエストがほとんどなくなり、ヒットしなくなる。そのため、ヘッダーをオリジンにルーティングしつつ、動的になりやすい値を持つヘッダーをキャッシュキーにしないようにする必要がある。ヒット率の向上のため、クエリストリングやCookieの静的な値をキャッシュキーに設定すると良い。
全拒否 全てのヘッダーのルーティングを拒否し、ヘッダーの無いリクエストをルーティングする。 キャッシュを作成しない。

Cookie情報のキー名のうち、オリジンへのルーティングを許可し、加えてキャッシュキーと見なすパラメーターを設定する。

リクエストのヘッダーに含まれるCookie情報 (キー名/値) が変動していると、CloudFrontに保存されたキャッシュがヒットしない。

CloudFrontはキー名/値を保持するため、変化しやすいキー名/値は、オリジンにルーティングしないように設定する。

例えば、GoogleAnalyticsのキー名 (_ga) の値は、ブラウザによって異なるため、1ユーザーがブラウザを変えるたびに、異なるキャッシュが作成されることになる。

そのため、ユーザーを一意に判定することが難しくなってしまう。

GoogleAnalyticsのキーはブラウザからAjaxでGoogleに送信されるもので、オリジンにとっても基本的に不要である。

セッションIDはCookieヘッダーに設定されているため、フォーム送信に関わるパスパターンでは、セッションIDのキー名を許可する必要がある。

機能名 オリジンリクエストの可否 キャッシュ作成の有無
全許可 全てのCookieのルーティングを許可する。 全てのCookieをキャッシュキーとみなす。
一部ルーティング 一部のCookieのルーティングを拒否し、Cookieの無いリクエストをルーティングする。 指定したCookieのみキャッシュキーとみなす。Cookieはユーザーごとに一意になることが多く、動的であるが、それ以外のヘッダーやクエリ文字でキャッシュを判定するようになるため、同一と見なすリクエストが増え、ヒット率の向上につながる。
全拒否 全てのCookieのルーティングを拒否し、Cookieの無いリクエストをルーティングする。 キャッシュを作成しない。

▼ クエリストリングに基づくキャッシュ作成

クエリストリングのうち、オリジンへのルーティングを許可し、加えてキャッシュキーと見なすパラメーターを設定する。

異なるクエリパラメーターのキャッシュを別々に作成するか否かを設定できる。

機能名 オリジンリクエストの可否 キャッシュ作成の有無
全許可 全てのクエリストリングのルーティングを許可する。 全てのクエリストリングをキャッシュキーとみなす。
一部拒否 一部のクエリストリングのルーティングを拒否し、クエリストリングの無いリクエストをオリジンにルーティングする。 指定したクエリストリングのみをキャッシュキーとみなす。
全拒否 全てのクエリストリングのルーティングを拒否し、クエリストリングの無いリクエストをルーティングする。 キャッシュを作成しない。

上記の設定では、Cookieやクエリストリングをオリジンにルーティングしつつ、キャッシュを作成しないようにできない。

そこで、キャッシュの最大最小デフォルトの有効期間を0秒とすることにより、結果的にキャッシュを動作しないようにさせ、キャッシュが作成されていないかのように見せかけられる。


ヘッダーキャッシュのヒット率向上

▼ ヒット率の向上について


▼ ヒット率の向上について


クエリストリングキャッシュのヒット率向上

▼ ヒット率の向上について

CloudFrontは、クエリストリングによってオリジンからレスポンスされるファイルのキャッシュを作成し、次回、同じクエリストリングであった場合、キャッシュをレスポンスとして返信する。

キャッシュ作成のルールを理解すれば、キャッシュのヒット率を向上させられる。

▼ クエリストリングの順番を固定する

リクエスト時のクエリストリングの順番が異なる場合、CloudFrontはそれぞれを異なるURLに対するリクエストと見なし、別々にキャッシュを作成する。

そのため、クエリストリングの順番を固定するようにURLを設計すれば、キャッシュのヒット率を向上させられる。

GET https://example.com?fooId=1&barId=2
GET https://example.com?barId=2&fooId=1

▼ クエリストリングの大文字小文字表記を固定する

リクエスト時のクエリストリングの大文字小文字表記が異なる場合、CloudFrontはそれぞれを異なるURLに対するリクエストと見なし、別々にキャッシュを作成する。

そのため、クエリストリングの大文字小文字表記を固定するようにURLを設計すれば、キャッシュのヒット率を向上させられる。

GET https://example.com?fooId=1&barId=2
GET https://example.com?FooId=1&BarId=2

▼ 署名付きURLと同じクエリストリングを使用しない

S3には、署名付きURLを発行する機能がある。

CloudFrontの仕様では、署名付きURLに含まれるExpiresKey-Pair-IdPolicySignatureといったクエリストリングを削除したうえで、オリジンにリクエストをルーティングする。

これらのパラメーターは、キャッシュヒットの判定要素として使用できない。

そのため、URLの設計時にこれらを使用しないようにする。


Invalidation (キャッシュの削除)

TTL秒によるキャッシュの自動削除を待たずに、手動でキャッシュを削除できる。

全てのファイルのキャッシュを削除したい場合は『/*』、特定のファイルのキャッシュを削除したい場合は『/<ファイルへのパス>』、を設定する。

CloudFrontに関するエラーページが表示された場合、不具合を修正した後でもキャッシュが残っていると、エラーページが表示されてしまうため、作業後には必ずキャッシュを削除する。


05. カスタムエラーページ

カスタムエラーページとは

オリジンに該当のファイルが存在しない場合、オリジンはCloudFrontに以下の403ステータスを含むレスポンスを返信する。

カスタムエラーページを設定しない場合、CloudFrontはこの403ステータスをそのままレスポンスしてしまう。

そのため、オリジンに配置したカスタムエラーページを404ステータスでレスポンスするように設定する。

This XML file does not appear to have any style information associated with it.
The document tree is shown below.
<Error>
  <code>AccessDenied</code>
  <Message>Access Denied</Message>
  <RequestId>*****</RequestId>
  <HostId>*****</HostId>
</Error>


設定方法

オリジンからカスタムエラーページをレスポンスするパスパターンを定義する。

Lamnda@Edgeを使用したCloudFrontの場合は、Lambda@Edgeを経由して、カスタムエラーページをレスポンスする必要がある。