AWSで独自ドメインかつHTTPSの静的Webサイト配信を行う

# はじめに
AWSのSAPを勉強中に、上記構成の問題が多く出題されているように感じ、理解を深めるために実際に構築してみることにしました。

# 利用するサービス
- Amazon Route 53​(以下Route53)
    - 全世界のエッジロケーションの一部を使用して、高可用性を持ったDNSサービスを提供します。
- Amazon CloudFront​​(以下CloudFront)
    - 全世界のエッジロケーションを使用してキャッシュを配信できるCDN(Content Delivery Network)サービスです。
    - S3だけではHTTPS通信を行うことができず、HTTPS通信を行うために利用します。
- Amazon Simple Storage Service (Amazon S3)​​​(以下S3)
    - インターネットからアクセスできるストレージサービスです。
    - 静的なファイル(HTMLなど)を格納するために利用します。
- AWS Certificate​ Manager​(以下ACM)
    - ドメイン認証の証明書の発行、自動更新管理が可能です。
    - CloudFrontと連携して、所有ドメインのHTTPSアクセスを提供するために利用します。

# 料金
Route53以外はAWS無料枠内で可能で、Route53も月100円以下ですので、気軽に試してみることができます。

# 実施方法
今回は以下の流れで進めていきます。
1. Route53でドメイン名を取得
2. S3バケットの作成
3. S3の静的ホスティングを有効化し、コンテンツをアップロード
4. ACMを利用してSSL/TLS証明書を取得
5. CloudFrontとACMのSSL/TLS証明書を紐づけ

## Route53でドメイン名を取得
まずはRoute53でドメイン名を取得します。
![route53_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/1e0c76fb-f2c1-045b-0fc6-522e7b703153.png)

ただ、Route53でドメインを取得しようとすると高いので、私は[お名前.com](https://www.onamae.com/)から取得しました。1円から取得できます。
![route53_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/b5025c3a-cd38-134c-836b-04b811d13655.png)

↓こんな感じで登録できました。
![domain.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/87a7ee5d-163b-b281-1744-f7227a04dfd7.png)

次にRoute53へ登録します。
![route53_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/eb30fa1e-340f-c8fd-b3af-d7fec9e770d7.png)

先ほど取得したドメインをドメイン名に指定して、ホストゾーンを作成します。
![route53_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/32b91c40-d59d-c7ba-b716-1173ad8dd984.png)

ホストゾーンが作成されます。
![route53_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/f5f31f3e-eb13-c02a-3164-cedbd6bbf38c.png)

続いて、上記で作成されたNSレコードの情報をもとに、お名前.comのDNSに設定を行います。お名前.comのドメイン設定画面の「ネームサーバーの変更」をクリックします。
その後、その他のサービスタブにRoute53のNSレコードの4レコードを入力して、更新します。
![route53_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/9a4be488-1d69-7eb4-35fc-1a6a0112388c.png)


次の画面で、ドメインにチェック、「その他」タブから「その他のネームサーバーを使う」を選択し、前述のRoute53で作成された4つのNSレコードを入力して「確認」をクリック。

## S3バケットの作成
それではS3バケットを作成していきます。「バケットを作成」ボタンをクリックします。
![s3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/bb7c637c-fd41-ce88-54d0-0714504b860c.png)

一意なバケット名とリージョンを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/4774c0bb-e8c4-6823-34cd-a8d580e06407.png)

アクセス設定について、デフォルトのままで問題ありません。それ以外の項目(バケットのバージョニングなど)についてもデフォルトで問題ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/acf551d6-322e-e60a-df10-fec5ac0be438.png)

S3バケットが作成されたことを確認します。
![s3_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/6426d178-b88e-6a54-a067-36eeecbf977f.png)

## S3の静的ホスティングを有効化し、コンテンツをアップロード
次にS3の静的ホスティングを有効化し、コンテンツをアップロードしていきます。
対象のバケットを選択し、バケットのプロパティタブの静的ウェブサイトホスティングを編集します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/91eb1f3d-9110-20cd-1a82-d9865093d75c.png)
![s3_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/9e77bb52-9292-c2ae-f2ab-6fd83ddb6bc2.png)

静的ウェブサイトホスティングを有効にし、インデックスドキュメントを指定します。その後、変更を保存します。
![s3_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/143e1049-cd34-c9ea-8d88-fbe159aae6dd.png)

静的ウェブホスティングが有効になったことを確認します。
![s3_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/4eea4dcc-a99f-82e5-7042-31c629e09bc5.png)

次に、index.htmlをアップロードします。私は適当に作成したHTMLをアップロードします。
![s3_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/310d6efb-beb0-0d86-1297-3b9eb7b36309.png)

アップロードが完了できたらこのように表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/afc1e964-99c3-f637-b82b-5cbac5128271.png)

その後、私はアップロードできたHTMLを確認しようと、パブリックアクセスのブロックを解除したのですが、403(AccessDenied)エラーが出てしまいました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/686c1dbc-79e8-1b97-f6d7-9158a1678663.png)
初期状態のバケットポリシー、ACLは未設定のため、バケットポリシーから参照できるように修正が必要です。バケットポリシーを修正したら、無事S3にアップロードしたHTMLを確認できました。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::[S3バケット名]/*"
        }
    ]
}
```
バケットポリシーとACLの関係性は以下が参考になりました。
https://dev.classmethod.jp/articles/s3-acl-wakewakame/

## ACMを利用してSSL/TLS証明書を取得
次にACMを利用してSSL/TLS証明書を取得します。
注意点として、CloudFrontでACM証明書を利用するためには、米国東部 (バージニア北部) リージョンでリクエストを行う必要があります。
https://docs.aws.amazon.com/ja_jp/acm/latest/userguide/acm-regions.html

証明書をリクエストします。

![acm_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/395b8679-217e-3f05-2cbb-bc5ce0d28bb5.png)


パブリック証明書をリクエストします。
![acm_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/596d9111-a778-c6d3-30e0-96b424c48f8c.png)

取得したドメイン名を入力し、リクエストを行います。
![acm_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/1875c58f-af70-d617-96fe-8830e328e475.png)

リクエスト後、リロードします。
![acm_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/d24ea7f4-8044-b597-47e4-bd2c399cfd69.png)

保留中のステータスとなっています。
![acm_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/58900ebe-7068-cf0f-845f-9874e12a6a3f.png)


証明書の発行にRoute53でCNAMEレコードの登録が必要です。「Route53でのレコードの作成」をクリックするとRoute53へ自動的にCNAMEレコードを登録してくれます。
![acm_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/0e832981-1fbb-330d-71f5-69977409f88e.png)

![acm_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/67e79161-e1bd-6d46-1be9-72e9ae14b164.png)

Route53にCNAMEレコードが作成されたことを確認できました。
![route53_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/25aef962-c9be-2cbc-5726-3ba814c56cf4.png)

この作業を行ってから1日経っても証明書のステータスが保留中の検証のままだったのですが、お名前.comのドメイン利用制限解除の手続きを実施したところ、10分後にステータスが発行済みに更新されました。
![acm_8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/86b7ab24-b80c-26fc-35f3-ef7359d2d89e.png)

## CloudFrontとACMのSSL/TLS証明書を紐づけ
次にCloudFrontで作業を行っていきます。ディストリビューションを作成ボタンをクリックします。

![cloudfront_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/37c050d2-1286-9083-183a-568f2de0a95f.png)

次にオリジンドメインを選択します。クリックすると、先ほど作成したS3バケットが出力されるので、選択します。
![cloudfront_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/32adb032-8acf-9386-8d2f-9df7c060f466.png)

次にS3バケットへのアクセスにOAIを使用するようにします。
OAIを設定することで、S3へはCloudFront以外からアクセスできなくなります。つまり、S3への直接アクセスができなくなるので、セキュリティが向上します。
![cloudfront_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/e57ed4f1-d909-d9f9-2eb5-ad590c5c8bd2.png)

新しいOAIを作成ボタンをクリックします。
![cloudfront_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/e843be44-ca52-ebf9-35cb-b82930912e2b.png)

OAIを作成します。
![cloudfront_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/34571941-2f1c-a4a4-ca62-32033b8133e8.png)

ここまででオリジンの設定を行いました。
![cloudfront_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/ba5eb289-a5b3-a2bf-809a-c7a456dae576.png)

次にデフォルトのキャッシュビヘイビアを設定します。
今回はビューワープロトコルポリシーをRedirect HTTP to HTTPSに変更します。
![cloudfront_8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/dcd752db-51a9-0433-2b16-3bb87b727b82.png)

次に設定項目のカスタムSSL証明書を設定します。
先ほどACMで取得した証明書を選択します。
![cloudfront_9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/f6004049-ca48-18ec-d7bd-e6a1e027e48b.png)

設定が完了したのでディストリビューションを作成し、ディストリビューションが作成できたことを確認できました。
![cloudfront_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/0e3e9181-cf93-88c8-a8dd-cf668d6a90cc.png)


また、私は既にS3のバケットポリシーを設定していたため、バケットポリシーの自動更新が実施できず、手動で更新しました。
以下のリンクに従ってバケットポリシーを更新しました。
```
{
    "Version": "2012-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EH1HDMB1FH2TC"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
        }
    ]
}
```
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html

S3バケットへの直接アクセスはエラーとなり、CloudFront経由のアクセスは正常に動作することを確認します。
<S3への直接アクセス>
![cloudfront_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/bff724de-7499-6cae-aad2-c937d13c7c63.png)

<CloudFront経由のアクセス>
![cloudfront_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/c3947c2e-d831-cc44-f705-51416a7fedd6.png)

ちなみに現在の設定状況ですと、http://<ドメイン名>/index.htmlまで指定しないとエラーとなります。
![cloudfront_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/af61a5da-0fb2-fbe5-5fe0-0ffac3a2692f.png)

変更するためには、設定のデフォルトルートオブジェクトを設定します。
![cloudfront_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/13ba8c66-bf7e-4b1a-29b7-0ea2f669fee0.png)

設定ができたので、index.htmlを指定せずアクセスできました。
![cloudfront_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/ae17730f-be26-ec47-df6a-195fe954955c.png)

最終的にhttps://<ドメイン名>でアクセスするとindex.htmlが表示されることが確認できました。
![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/437899be-22f6-b1e0-5c4b-b8af0bb2fac6.png)