CloudFrontでS3のウェブサイトをSSL化する

「S3 + Route 53」の組み合わせで独自ドメイン運用しているサイトにhttpsでアクセスしたい！と思って調べたところ、CloudFrontを使用すればできることがわかった。

実は、「[AWSで静的ウェブサイトをホストする](http://docs.aws.amazon.com/ja_jp/gettingstarted/latest/swh/website-hosting-intro.html)」のステップ6で[CloudFront を使用してウェブサイトを高速化する](http://docs.aws.amazon.com/ja_jp/gettingstarted/latest/swh/getting-started-create-cfdist.html)方法が紹介されているが、自分がテストするだけなので高速化は不要だと思ってCloudFrontの設定をしていなかった。

ウェブサイトの高速化に興味がなくても、「S3 + CloudFront + Route 53」に変えるだけでSSL化できるし、なんとこの構成は「[AWSにおける静的コンテンツ配信パターンカタログ（アンチパターン含む）](http://dev.classmethod.jp/cloud/aws/static-contents-delivery-patterns/)」で紹介されている横綱＝最高の構成になるらしいので、検証してみる価値あり。

ちなみにCloudFrontはCDN（コンテンツ配信ネットワーク）サービスと紹介されているが、今回使ってみた感想はコンテンツキャッシュ機能付きのリバースプロキシのような感じ。

## S3のウェブサイトをCloudFrontに登録
1. CloudFrontのメニューから「Create Distribution」のボタンをクリック
1. 配信方法で「Web」を選択
![Clipboard08.jpg](https://qiita-image-store.s3.amazonaws.com/0/81380/5b1d3655-debf-5a07-c9b9-23ebf741283a.jpeg)

1. 「Origin Settings」でSSL化したいS3バケットを選択
「Origin Domain Name」でSSL化したいS3バケットを選択すると、「Origin ID」が自動で設定される（`www.example.com`の部分は実際に使用するドメイン名）
![Clipboard09.jpg](https://qiita-image-store.s3.amazonaws.com/0/81380/ef56e8fe-0b25-a97b-5a40-4610c2c362d7.jpeg)

1. 「Default Cache Behavior Settings」は何も変更しない
1. 「Distribution Setting」で「Alternate Domain Name」に使用するドメイン名を設定する（example.comとwww.example.comのように複数のドメイン名を使用する場合は、改行区切りで入力）
「Default Root Object」にはS3でウェブサイト用に使用しているバケットの「インデックスドキュメント」と同じファイル名を設定する
![Clipboard10.jpg](https://qiita-image-store.s3.amazonaws.com/0/81380/b93940c5-78a7-692f-23fa-9bb648d39f01.jpeg)
SSL証明書（SSL Certificate）の設定で独自SSLを使用するには事前にIAMに証明書をアップロードしておく必要があるので、とりあえずCloudFrontで用意されているデフォルトのSSL証明書を使う設定で先に進む

1. 設定内容を保存するとデプロイが始まり、「Status」の欄がDeployedになると使用できるようになる
1. デプロイが完了したらディストリビューションの詳細画面に表示されているDomain Nameにhttpsでアクセスでき（`https://xxxxx.cloudfront.net/`等）、S3のウェブサイトを閲覧できるようになる

## Route 53の設定をS3からCloudFrontに変更
1. Route 53のHosted Zonesから、CloudFrontに登録したS3を指しているAレコード`www.example.com`の編集画面を開く
1. 「Alias Target」をS3のエンドポイントから、CloudFrontのディストリビューションに変更し保存する
![Clipboard11.jpg](https://qiita-image-store.s3.amazonaws.com/0/81380/1f8486fc-7bab-f0ee-adaf-fc9ec57e6bd5.jpeg)
1. しばらくするとブラウザで`https://www.example.com`にアクセスできるようになり、S3のウェブコンテンツが表示される（ただし、CloudFrontのSSL証明書を使用しているのでURLと証明書でドメイン名が一致せず証明書エラーが出る）

## CloudFrontに独自SSL証明書を設定
AWS Certificate Manager(ACM)を使用してSSL証明書を設定することができる。ACMではサードパーティ製の証明書をインポートできるほか、SSL証明書をAWSにリクエスト(CloudFrontかELBで使用する場合)することもできる。
CloudFrontで証明書を使用する場合は、**必ず「米国東部（バージニア北部）」リージョンで証明書を登録**すること。CloudFrontにはリージョンがないので、東京リージョンとかで証明書を登録するとCloudFrontの画面で証明書が見つからなくてはまる。
今回は無料でSSL化を行いたいので、AWSにSSL証明書をリクエストする方法を書く。

### AWS Certificate Manager(ACM)で証明書作成
1. 「証明書のリクエスト」ボタンをクリックすると、ドメイン名を入力する画面が出てくる
![capture_006_11102017_225124.jpg](https://qiita-image-store.s3.amazonaws.com/0/81380/07702c2f-61c2-ccb6-50e9-0e2245e33d95.jpeg)   
ドメイン名は1つ入力すればいいが、「この証明書に別の名前を追加」するとドメインの別名を設定することができる
2. ドメイン名を入力し証明書のリクエストを完了すると、状態が「検証未完了」となり対象ドメインに登録されているメールアドレス宛に検証確認メールが送付される
3. 検証確認メールに記載されている`https://us-east-1.certificates.amazon.com/approvals...`のようなリンクをクリックする
4. 以下のような画面が表示され、「I Approve」のボタンをクリックすると証明書のリクエストが完了する
![capture_012_11102017_230641.jpg](https://qiita-image-store.s3.amazonaws.com/0/81380/4797aae9-ed97-586c-e586-313ac6e81973.jpeg)

### CloudFrontにACMの証明書を設定
1. CloudFrontでSSL証明書を設定したいDistributionを選択し、詳細画面の「General」タブで編集ボタンをクリック
2. 「SSL Certificate」の欄で「Custom SSL Certificate」を選択し、プルダウンから先ほどACMに登録した証明書を選ぶ
![capture_014_11102017_230729.jpg](https://qiita-image-store.s3.amazonaws.com/0/81380/189933fb-d653-c64a-b24e-2203c63a0aab.jpeg)
3. 「Custom SSL Client Support」はデフォルト(SNI)のままにしておく（※SNIじゃない場合は、$600/月かかる）
4. 変更内容を保存して完了

これでSSL証明書の設定ができたので、https://ドメイン名 でアクセスできるかどうか確認する。

## CloudFrontを使う場合の注意点
CloudFrontはコンテンツキャッシュを行い、「ウェブサイトの高速化」を実現している。デフォルトではオリジンサーバのコンテンツを 24 時間キャッシュする設定になっているため、検証中など頻繁にS3のオブジェクト内容を更新する際にはキャッシュがききすぎて辛い。[Cache-Controlヘッダーを設定してCloudFrontのキャッシュ時間を制御する](http://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/Expiration.html#expiration-individual-objects)等、キャッシュコントロールを適切に行う必要がある。
誤ってキャッシュしてしまった場合は、CloudFrontのDistribution詳細画面で「Invalidations」タブからファイル名のルールを登録すると対象コンテンツのキャッシュを失効させることができる。

## 参考
- [【CloudFront開発者ガイド】ウェブディストリビューションの使用](http://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/distribution-web.html)
- [CloudFrontのSSL/TLS対応 まとめ](http://dev.classmethod.jp/cloud/cloudfront-ssl-options-summary/)
- [AWSにおける静的コンテンツ配信パターンカタログ（アンチパターン含む）](http://dev.classmethod.jp/cloud/aws/static-contents-delivery-patterns/)