Route53+ACM+CloudFormation(S3+CloudFront)で、独自ドメインを利用したHTTPS環境の構築

Qiitaにもたくさん記事があるのですが、結構ハマったので個人的にメモ。

#やりたいこと(最終的な構成)
独自ドメインでアクセスし、S3に配置されたオブジェクトが表示されるようにする。
![AWS network diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272758/aaab9601-c022-3949-b60c-3897c466d540.png)

#前提
AWSアカウントを持っている
デプロイしたら実行できるアプリケーションのソースコードがあり、
自力でデプロイできる。

#手順
全体の流れはこんな感じ。
1.独自ドメインの取得
2.取得したドメイン情報をRoute53に設定
3.Route53の情報を、ドメイン取得元に設定
4.取得したドメインの証明書を取得
5.CloudFormationのスタックの作成
6.独自ドメインとCloudFrontの紐づけ
7.デプロイ

以下、詳細手順。
##1.独自ドメインの取得
私は[Freenom](https://www.freenom.com/ja/index.html?lang=ja)を利用して、無料ドメインを取得しました。
参考：[無料のドメインを取得する](https://qiita.com/teekay/items/135dc67e39f24997019e)

【ポイント】取得時は、"Forward URL"を選択して、適当なURLを入力。
デフォルトは3か月になっているので、無料枠の最大値である12か月をセット。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272758/82f27c55-a009-5928-767f-dc28cac5f042.png)
ちなみに、私はなぜかChoromeからだとGoogleアカウントを利用したログインができなくて、
IEから操作していました。
##2.取得したドメイン情報をRoute53に設定
AWSのコンソールから、Route53のサービス画面を開き、「ホストゾーンの作成」を行います。
以下の2レコードは自動で作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272758/27a4a51b-435b-f17a-a251-2015c2a240dc.png)
##3.Route53の情報を、ドメイン取得元に設定
Freenomの場合、以下の手順になります。
・Services>My Domains>Management Domain>Management Toolsから、Name Serversを選択。
・Manage Freenom DNSを選択
・入力欄（Nameserver1～4)に、手順2で作成された、4つのNSレコードを登録する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272758/f8387fe8-8d83-8137-5d54-5aa801748d33.png)

##4.取得したドメインの証明書を取得する。
ACM(Amazon Certificate Manager)を利用してSSL証明書を取得します。
手順は、下記記事の「3. SSL証明書の発行」参照
[無料の独自ドメインとAWS Certificate Managerを使ったお手軽SSL対応](https://labs.mobingi.com/aws-certificate-manager-and-freenom/)

状況が"発行済み"になれば、証明書の取得完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272758/a8e7edf0-95f2-84f2-cad9-81924a394d51.png)
私の場合、メインのドメインの証明書の取得は1分くらいで完了しましたが、サブドメインの方は数時間かかりました。。なぜだ。。

【ポイント】
汎用的な証明書が欲しいと思って、「\*.originaldomain.com」の証明書のみをリクエストするのは誤りです。「originaldomain.com」「\*.originaldomain.com」の2つをリクエストする必要がありますし、サブドメインは別途リクエストが必要です。

その理由は、サブドメインやアスタリスク (*) を利用した証明書取得を行う場合、ACMは1 つのサブドメインレベルのみを保護するためです。詳細は下記がわかりやすく説明されていました。
[AWS Certificate Manager(ACM)でワイルドカード証明書を発行する際の注意事項](http://blog.serverworks.co.jp/tech/2018/05/31/acm-wildcard-certificate/)

####4-1. サブドメインも証明書を取得したい場合
Route53の設定を以下のようにします。
1.サブドメインについて、ホストゾーンの作成を行う。
2.**メインの**ドメインのホストゾーンに、レコードを1つ追加する。
　名前：サブドメインの名前
　レコードタイプ：NS
　値：1で作成された、**サブドメインの**NSの値

##5.CloudFormationのスタックの作成
CloudFormationを利用して、S3とCloudFrontを作成します。

【注意】証明書のリージョンとスタックを作成するリージョンは同一の必要があります。

私はテンプレートを用いてスタックを作成しました。
CloudFront、CloudFrontDistirbution、S3Backet、S3BacketPolicyについて、以下のようにテンプレート設定を行います。(下記は抜粋です)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272758/3cb20eaf-a323-5000-b8fa-449ac5eaadc6.png" width=50%>

```templateSample.yaml
Parameters: //ドメインと証明書情報をパラメータにしてあります
  Domain:
    Type: String
    Default: [独自ドメイン情報]
  SSLId:
    Type: String
    Default: [証明書の識別子]
Resources:
  [Bucket]: //S3に作成するBucketの設定
    Type: AWS::S3::Bucket
    Properties: 
      AccessControl: PublicRead
      BucketName: [任意の名前]
      WebsiteConfiguration:
        IndexDocument: index.html //ここではDefaultをindex.htmlに設定
  CloudFrontOriginAccessIdentity: //CloudFrontのオリジンサーバーの設定
    Type: "AWS::CloudFront::CloudFrontOriginAccessIdentity"
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: !Sub "access-identity-${Bucket}"
  [Bucket]Policy:　//S3BacketPolicyの設定
    Type: "AWS::S3::BucketPolicy"
    Properties:
      Bucket: !Ref Bucket //ここで上記の[Bucket]とリンク
      PolicyDocument:
        Statement:
          [必要なポリシー情報を記載]
          Resource: !Sub "arn:aws:s3:::${Bucket}/*"
  CloudFrontDistribution:
    Type: "AWS::CloudFront::Distribution"
    Properties:
      DistributionConfig:
       [必要なDistribution情報を記載]
        Origins:
        - DomainName: !GetAtt Bucket.DomainName　//CloudFrontのオリジンサーバーを[Bucket]にリンク 
          Id: !Sub S3origin-${Bucket}
          S3OriginConfig:
            OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}"
        ViewerCertificate:  
         SslSupportMethod: sni-only
          AcmCertificateArn: !Sub arn:aws:acm:us-east-1:${AWS::AccountId}:certificate/${SSLId} //ここにSSL情報を設定
        Enabled: true
```

SSLIdには以下の情報を記載します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272758/08961213-05a7-c171-bd74-e7cf22a05e69.png)


##6.独自ドメインとCloudFrontの紐づけ
無事S3とCloudFrontが作成できたら、最後にRoute53にタイプAとAAAAのレコードを1つずつ作成します。
エイリアスを利用し、作成したCloudFrontのディストリビューションIDと紐づけを行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272758/2c2e4c7c-b234-1779-6aff-3eaedbb1b197.png)

##7.デプロイ
デプロイ方法は割愛します。
私はこんな感じのコマンドでデプロイできました。
```aws s3 cp ./dist/ s3://develop.xxxx.xx --recursive
```
##8.アクセス確認
自分の設定した独自ドメインからアクセスを確認します。

##9.以上！！！
無事アクセスできたら完了です。

私は今回初めてCloudFormationに触ったド素人なので、
超超超時間かかりました…><
たくさんエラーも出たので、エラー別の原因切り分けなどは別途書けたらと思います。