CloudFrontのHTTPS通信を必須にしてみた

# 背景・目的
以前、[Amazon CloudFrontを試してみた](https://qiita.com/zumax/items/14582d1dff091fe2838c)という記事で、CloudFrontの基本的な整理と、簡単なハンズオンを行いました。

今回は、コンテンツへのセキュアなアクセスとアクセス制限の設定を試してみます。


# まとめ
下記に特徴を整理します。

|特徴 |説明 |
|:--|:--|
|CloudFrontのセキュリティのオプション| ・HTTPS接続<BR><BR>・特定の地理的いるユーザがコンテンツに、アクセスできないようにする<BR><BR>・CloudFrontの署名付きURLまたは、Cookieを使用してコンテンツにアクセスするようにユーザに要求<BR><BR>・特定のコンテンツフィールドのフィールドレベルの暗号化を設定<BR><BR>・AWS WAFを使用してコンテンツへのアクセスを管理する|
|HTTPSの使用|・ビューワーによるHTTPS<BR>・オリジンへのHTTPS|
|ビューワー↔CloudFront↔オリジン間のHTTPS通信|それぞれで暗号化と復号を行う|
|ビューワーとCloudFront間HTTPS通信のセキュリティポリシー|CloduFrontでビューワーとの通信に使用する最小の SSL/TLSプロトコル<BR><BR>ビューワーとの通信を暗号化するために、CloudFrontが使用できる暗号|
|CloudFrontとオリジン間HTTPS通信|CloudFrontが、オリジンに対するHTTPS接続を確立するには、オリジンがサポートしている必要ある|
|ビューワーと CloudFront 間の通信で HTTPS を必須にする場合|１）CloudFrontがディストリビューションに割り当てたドメイン名を使用している場合は、ビューワープロトコルポリシーの設定を変更する<BR><BR>２）独自ドメインなどを使用している場合は、下記のいずれかになる<BR>・ACMが提供するSSL/TLS証明書を使用する<BR>・サードパーティ認証機関からの証明書をACMまたは、IAM証明書ストアにインポートする|
|CloudFront と Amazon S3 オリジン間の通信で HTTPS を必須にする場合|バケットの使用方法により異なる<BR><BR>・S3バケットがウェブサイトのエンドポイントの場合、オリジンとの通信にHTTPSを使用するように設定できない<BR><BR>・オリジンがHTTPS通信をサポートするS3バケットの場合、CloudFrontは、ビューワーがリクエストを送信するために使ったプロトコルを必ず使用してS3にリクエストを転送する<BR><BR>・必須にする場合、ビューワープロコトルを下記のいずれかに設定する必要がある|
|CloudFrontの料金|日本の場合、0.0120 USD / 1万件あたり ※1※2|

※1 2024/6/13時点の情報です
※2 専用 IP カスタム SSLは考慮されていません。詳細は、[ドキュメント](https://aws.amazon.com/jp/cloudfront/pricing/)をご確認ください。


# 概要
[コンテンツへのセキュアなアクセスとアクセス制限の設定](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/SecurityAndPrivateContent.html)を基に整理します。

> CloudFront には、コンテンツをセキュリティで保護するためのオプションが用意されています。CloudFront を使用してコンテンツへのアクセスを保護および制限する方法を次に示します。
> - HTTPS 接続を設定する
> - 特定の地理的な場所にいるユーザーがコンテンツにアクセスできないようにする
> - CloudFront の署名付き URL または署名付き Cookie を使用してコンテンツにアクセスするようにユーザーに要求する
> - 特定のコンテンツフィールドのフィールドレベルの暗号化を設定する
> - AWS WAF を使用してコンテンツへのアクセスを管理する

- セキュリティのオプション
    - HTTPS接続
    - 特定の地理的いるユーザがコンテンツに、アクセスできないようにする
    - CloudFrontの署名付きURLまたは、Cookieを使用してコンテンツにアクセスするようにユーザに要求
    - 特定のコンテンツフィールドのフィールドレベルの暗号化を設定
    - AWS WAFを使用してコンテンツへのアクセスを管理する

## CloudFront で HTTPS を使用する
> ビューワーによる HTTPS の使用を必須とするように CloudFront を設定して、CloudFront がビューワーと通信するときの接続を暗号化することができます。また、オリジンに HTTPS を使用するように CloudFront を設定して、CloudFront がオリジンと通信するときの接続を暗号化することも可能です。

下記の設定が可能
- ビューワーによるHTTPSを必須とする
- オリジンにHTTPSを必須とする

> ビューワーとの通信とオリジンとの通信の両方で HTTPS を必須とするように CloudFront を設定する場合、CloudFront がオブジェクトのリクエストを受け取るときに以下が行われます。

> 1. ビューワーが HTTPS リクエストを CloudFront に送信します。ここで、ビューワーと CloudFront 間で何らかの SSL/TLS ネゴシエーションが実行されます。最終的に、ビューワーはリクエストを暗号化形式で送信します。
> 1. CloudFront のエッジロケーションにキャッシュされたレスポンスがある場合、CloudFront はレスポンスを暗号化してビューワーに返し、ビューワーがそれを復号化します。
> 1. CloudFront のエッジロケーションにキャッシュされたレスポンスがない場合、CloudFront はオリジンとの SSL/TLS ネゴシエーションを実行し、ネゴシエーションが完了すると、暗号化された形式でリクエストをオリジンに転送します。
> 1. オリジンは、リクエストを復号化して処理し (レスポンスを生成)、レスポンスを暗号化してから、そのレスポンスを CloudFront に返します。
> 1. CloudFront はレスポンスを復号化してから再度暗号化し、それをビューワーに転送します。また、CloudFront はエッジロケーションにレスポンスをキャッシュして、次回リクエストされたときに使用できるようにします。
> 1. ビューワーは応答の暗号化を解除します。

- ビュワーとの通信とオリジンとの通信の両方でHTTPSを必須とするように、CloudFrontを設定した場合、下記のような挙動になる
    1. ビューワーがHTTPSリクエストをCloudFrontに送信
        1. ビューワーとCloudFront間で SSL/TLS ネゴシエーションが行われる
    1. CloudFrontのエッジロケーションにキャッシュされたレスポンスの有無
        1. ある場合→ キャッシュから取得しレスポンスを暗号化してビューワーに返し、ビューワーは復号する
        1. ない場合→ 
            1. CloudFrontはオリジンとの SSL/TLS ネゴシエーションを行い、完了すると暗号化された形式でリクエストをオリジンに転送する
            1. オリジンは、リクエストを復号して処理し、レスポンスを暗号化後、CloudFrontに返す
            1. CloudFrontは、レスポンスを復号し、再び暗号化し、ビュワーに転送する
            1. CloudFrontはエッジロケーションにレスポンスをキャッシュして、次回リクエストされたときに、使用するようにする
            1. ビューワーはレスポンスを復号する

### ビューワーと CloudFront との間でサポートされているプロトコルと暗号
[ビューワーと CloudFront との間でサポートされているプロトコルと暗号](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/secure-connections-supported-viewer-protocols-ciphers.html)を基に整理します

::: note info
サポートされているセキュリティポリシー、およびサポートされている暗号名、署名スキームは、[ドキュメント](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/secure-connections-supported-viewer-protocols-ciphers.html)をご確認ください。
:::

> ビューワーと CloudFront ディストリビューションとの間で HTTPS が必要である場合は、セキュリティポリシーを選択する必要があります。これにより、次の設定が決定されます。
> - CloudFront でビューワーとの通信に使用する最小の SSL/TLS プロトコル。
> - ビューワーとの通信を暗号化するために CloudFront が使用できる暗号。
> セキュリティポリシーを選択するには、セキュリティポリシー に該当する値を指定します。以下の表は、各セキュリティポリシーで CloudFront が使用できるプロトコルと暗号化方式の一覧です。

- ビューワーと CloudFront ディストリビューションとの間で、HTTPSが必要なとき、セキュリティポリシーを選択する
- セキュリティポリシーでは、
    - CloduFrontでビューワーとの通信に使用する最小の SSL/TLSプロトコル
    - ビューワーとの通信を暗号化するために、CloudFrontが使用できる暗号

> ビューワーは、CloudFront との HTTPS 接続を確立するために、これらの暗号のうち少なくとも 1 つをサポートする必要があります。CloudFront は、ビューワーがサポートする暗号化方式から一覧順で暗号化方式を選択します。「OpenSSL、s2n、および RFC の暗号名」も参照してください。

- ビューワーとCloudFront とのHTTPS接続を確立するために、これらの暗号のうち、少なくとも1つをサポートする必要がある



### CloudFront とオリジンとの間でサポートされているプロトコルと暗号
[CloudFront とオリジンとの間でサポートされているプロトコルと暗号](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/secure-connections-supported-ciphers-cloudfront-to-origin.html)を基に整理します。

::: note info
サポートされている暗号化方式は、[ドキュメント](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/secure-connections-supported-viewer-protocols-ciphers.html)をご確認ください。
:::


> [CloudFront とオリジンとの間で HTTPS を必須にする] を選択する場合、安全な接続にどの SSL/TLS プロトコルを許可するかを決定し、次の表に示す ECDSA あるいは RSA 暗号のいずれかを使用して CloudFront からオリジンに接続できます。CloudFront がオリジンに対する HTTPS 接続を確立するには、オリジンがこれらの暗号のうち少なくとも 1 つをサポートしている必要があります。

- CloudFrontとオリジン間でHTTPS接続する場合、SSL／TLSプロトコルを許可するか決定する
- ECDSA、RSA暗号のいずれかを使用する
- CloudFrontが、オリジンに対するHTTPS接続を確立するには、オリジンがサポートしている必要ある


### HTTPS 接続料金
最新および、詳細な料金は、[データ送信（OUT）>HTTPSメソッドのリクエスト料金表(1万件あたり)](https://aws.amazon.com/jp/cloudfront/pricing/)をご確認ください

- 日本の場合、0.0120 USD / 1万件あたり

※1 2024/6/13時点の情報です
※2 専用 IP カスタム SSLは考慮されていません。詳細は、[ドキュメント](https://aws.amazon.com/jp/cloudfront/pricing/)をご確認ください。

## ビューワーと CloudFront 間の通信で HTTPS を必須にする
[ビューワーと CloudFront 間の通信で HTTPS を必須にする](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/using-https-viewers-to-cloudfront.html) を基に整理します。

> CloudFront ディストリビューション内で 1 つ以上のキャッシュ動作を設定して、ビューワーと CloudFront との通信で HTTPS を必須にできます。また、1 つ以上のキャッシュ動作で HTTP と HTTPS の両方を許可するように設定して、CloudFront における一部のオブジェクトで HTTPS を必須にすることもできます。設定手順はオブジェクト URL 内で使用しているドメイン名によって異なります。

- １つ以上のキャッシュ動作を設定し、ビューワーと CloudFront との通信でHTTPSを必須にできる
- 一部のオブジェクトのみHTTPSを必須にもできる

> - CloudFront がディストリビューションに割り当てたドメイン名を使用している場合 (d111111abcdef8.cloudfront.net など)、1 つ以上のキャッシュ動作の [ビューワープロトコルポリシー] 設定を変更して、HTTPS 通信を必須にします。この設定で、CloudFront は SSL/TLS 証明書を提供します。
CloudFront コンソールを使用して [ビューワープロトコルポリシー] の値を変更するには、このセクションで後述する手順を参照してください。
CloudFront API を使用して ViewerProtocolPolicy 要素の値を変更する方法については、Amazon CloudFront API リファレンスの「UpdateDistribution」を参照してください。

- CloudFrontがディストリビューションに割り当てたドメイン名を使用している場合は、ビューワープロトコルポリシーの設定を変更する

> - 独自のドメイン名 (example.com など) を使用している場合、CloudFront のいくつかの設定を変更する必要があります。また、AWS Certificate Manager (ACM) が提供する SSL/TLS 証明書を使用するか、サードパーティー認証機関からの証明書を ACM または IAM 証明書ストアにインポートする必要があります。詳細については、「代替ドメイン名と HTTPS の使用」を参照してください。


- 独自ドメインなどを使用している場合は、下記のいずれかになる
    - ACMが提供するSSL/TLS証明書を使用する
    - サードパーティ認証機関からの証明書をACMまたは、IAM証明書ストアにインポートする

## CloudFront と Amazon S3 オリジン間の通信で HTTPS を必須にする
[CloudFront と Amazon S3 オリジン間の通信で HTTPS を必須にする](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/using-https-cloudfront-to-s3-origin.html) を基に整理します。

> オリジンが Amazon S3 バケットの場合、CloudFront との通信に HTTPS を使用するためのオプションは、バケットの使用方法によって異なります。Amazon S3 バケットがウェブサイトエンドポイントとして設定されている場合、オリジンとの通信に HTTPS を使用するように CloudFront を設定することはできません。Amazon S3 はその設定で HTTPS 接続をサポートしていないためです。


> オリジンが HTTPS 通信をサポートする Amazon S3 バケットの場合、CloudFront はビューワーがリクエストを送信するのに使ったプロトコルを必ず使用して S3 にリクエストを転送します。プロトコル (カスタムオリジンのみ) 設定のデフォルト設定は [Match Viewer (ビューワーに合わせる)] で、変更できません。


> CloudFront と Amazon S3 との間の通信で HTTPS を必須にする場合、[ビューワープロトコルポリシー] の値を [Redirect HTTP to HTTPS (HTTP から HTTPS へのリダイレクト)] または [HTTPS Only (HTTPS のみ)] に変更する必要があります。このセクションで後述する手順では、CloudFront コンソールを使用して [ビューワープロトコルポリシー] を変更する方法について説明します。CloudFront API を使用してディストリビューションの ViewerProtocolPolicy 要素を更新する方法については、Amazon CloudFront API リファレンスの「UpdateDistribution」を参照してください。

> HTTPS 通信をサポートする Amazon S3 バケットで HTTPS を使用する場合、Amazon S3 では SSL/TLS 証明書を使用できるため、この通信を使用する必要はありません。

- オリジンがS3バケットの場合、CloudFrontとの通信に、HTTPSを使用するためのオプションは、バケットの使用方法により異なる
    - S3バケットがウェブサイトのエンドポイントの場合、オリジンとの通信にHTTPSを使用するように設定できない
        - S3がサポートしてない
    - オリジンがHTTPS通信をサポートするS3バケットの場合、CloudFrontは、ビューワーがリクエストを送信するために使ったプロトコルを必ず使用してS3にリクエストを転送する
        - 設定のデフォルト設定は、「Match viewer」から変更できない
    - 必須にする場合、ビューワープロコトルを下記のいずれかに設定する必要がある
        - HTTPS Only or Redirect HTTP to HTTPS


# 実践
## 前提
前回の[Amazon CloudFrontを試してみた](https://qiita.com/zumax/items/14582d1dff091fe2838c#%E5%AE%9F%E8%B7%B5)で作成した内容を基に、S3およびCloudFrontディストリビューションを作成します

## ビューワーと CloudFront 間の通信で HTTPS を必須にする
[ビューワーと CloudFront 間の通信で HTTPS を必須にする](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/using-https-viewers-to-cloudfront.html)を、基に試します。

1. CloudFrontに移動します
1. ナビゲーションペインで、「ディストリビューション」をクリックします
1. 対象のディストリビューションのIDをクリックします
1. ①「ビヘイビア」タブをクリック、 対象のビヘイビアを選択し、②「編集」をクリックします
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/1dc21130-28ad-82eb-00aa-bf1001f53844.png)
1. ビューワープロトコルで「HTTPS only」を選択します
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/310567db-4fc2-5bbb-2426-73d30d2cfe69.png)
1. 「変更を保存」をクリックします

1. HTTPSでリクエストします。表示されました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/593804d6-dc49-fd7b-270b-c5af39cd9c00.png)

1. HTTPでリクエストします。想定通りエラーになりました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/6b736ea3-00e7-b194-7eab-c1b06fd01367.png)


# 考察
今回は、CloudFrontのアクセスをHTTPS onlyに設定してみました。次回以降は、独自ドメインを使用した構築を試してみようと思います。

# 参考
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/SecurityAndPrivateContent.html

https://aws.amazon.com/jp/cloudfront/pricing/