S3+CloudFront+ACM(AWS Certificate Manager)でHTTPS静的サイトを作ってみた

ドメイン取得からS3での静的サイト及びHTTPS化(CloudFront,ACS)までやってみた時の作業メモ。

# やること

+ ドメインの登録を行う(今回、お名前.comでやったみたが、Route53の登録でもOK)
+ 本例では **example.com** というドメインを購入したと想定(この作業メモを書いた時は別のドメインで検証しています)
+ S3のStaticWebsiteHostingとCloudFronとACMを利用して、 **https://blog.example.com** でアクセス出来るようにする

# ドメインを探す

自分の利用したいドメインを探して購入します。
せっかくなのでRoute53で購入してみたかったのですが、欲しいのが丁度なかったのでお名前.comで購入しました。

登録が完了すれば登録したメールアドレスに登録完了通知が来ているかと思います。

# Route53にドメインを登録する

次に取得したドメインをRoute53に登録します。
今回は **example.com** というドメインを取得したので、こちらの登録を行っていきます。

Route53の画面を表示し、 **DNS management** の下のGet started now を選択します。

次にCreate Hosted Zoneを選択し、ゾーンを作成します。

+ Domain Name->example.com
+ Comment->(任意)
+ Type->Public Hosted

登録後、レコード情報を確認するとNameSeversというので複数のネームサーバーが確認できるので、こちらをコピペしておきます。

# お名前.comでネームサーバーを登録する

先ほどRoute53で表示されたネームサーバーをお名前.comに登録します。

取得したドメインの **ネームサーバー変更** というリンクから変更できました。

ネームサーバーの登録により、登録したドメインが登録できるようになるまで多少時間がかかることもあるようです。

# S3でサイトを作成する

まずは静的サイト用のバケットを作成します。
バケット名はアクセスする際のドメイン名と同じ設定としてください。

+ BucketName->blog.example.com
+ Region->Tokyo

次にテスト表示用のindex.htmlを作成し、上記バケット直下にアップロードします。

```index.html
hello world
```

次にこのバケットに誰でもアクセスできるように権限の設定を行います。
バケットを選択後、Properties->Permissions->Add bucket policを選択し、以下を入力します。

 **blog.example.com** となっている部分は適宜、作成したバケット名に置き換えてください。


```
{
  "Version":"2012-10-17",
  "Statement":[{
	"Sid":"AddPerm",
        "Effect":"Allow",
	  "Principal": "*",
      "Action":["s3:GetObject"],
      "Resource":["arn:aws:s3:::blog.example.com/*"
      ]
    }
  ]
}
```

次に作成したバケットを選択し、Static Web Site Hostingを有効にします。

これで準備は完了で、この後表示されている Endpoint　にアクセスすることで先ほどアップロードしたindex.htmlの内容が確認できます。

# Route53でalias設定により登録したドメインでアクセスできるようにする

StaticWebSiteHostingによって払い出されるドメイン名は長いもので分かりにくいので、取得したドメインを利用するようにします。

Route53の画面を表示し、Hosted zonesの中から **example.com** を選択します。

次にCreate Record Setを選択し、Aレコード(alias)を登録します。

+ Name->blog.example.com
+ Type->A - IPv4 address
+ Alias->Yes
+ Alias Target->作成したバケット
+ Routing Policy->Simple
+ Evaluate Target Health->No

これで **blog.example.com** というexample.comのサブドメインの名前解決の際にはS3のblog.example.comバケットのIPアドレスを返却するようになります。

準備ができたらまずは名前解決ができるか確認します。

```bash
# 名前解決出来るか確認.IPアドレスが返却されれば、名前解決できている
$nslookup blog.example.com
Server:		192.168.11.1
Address:	192.168.11.1#53

Non-authoritative answer:
Name:	blog.example.com
Address: 54.231.226.51

```

名前解決ができているので次にcurlを使ってアクセスしてみます。

```bash
$curl http://blog.example.com
hello world!
```

index.htmlの内容が表示されれば、成功です!

# CloudFrontを使ってアクセスできるようにする

S3をOrignにしたCloudFrontを設定します
上記によってClinet->CloudFront->S3というアクセス方法になります。
CloufFront経由でないS3の直接アクセスは拒否するようにします。(Origin Access Identiyの利用）
以下を参考に作業をしました。

[[CloudFront + S3]特定バケットに特定ディストリビューションのみからアクセスできるよう設定する](http://dev.classmethod.jp/cloud/aws/cloudfront-s3-origin-access-identity/)

まずは先ほどまでの準備で必要だった以下を一旦削除します。

+ Route53に登録したS3へ向いているaliasの削除
+ S3のバケットのバケットポリシーの削除

次にCloudFrontの設定をしていきます。

以下を設定（デフォルトとは違うものだけ抜粋）

+ Original Domain Name->blog.example.com.s3.amazonaws.com
+ Restrict Bucket Access->Yes
+ Origin Access Identity->Create a New Identity
+ Grant Read Permissions on Bucket->Yes,Update Bucket Policy
+ Price Class->Use Only US and Europe
+ Default Root Object->index.html

設定後、確認します。

```bash
# CloudFrontのドメインにアクセス
$curl http://xxxxx.cloudfront.net
hello world!

# S3への直接接続はNG
$curl http://blog.example.com.s3-website-ap-northeast-1.amazonaws.com/
<html>
<head><title>403 Forbidden</title></head>
<body>
<h1>403 Forbidden</h1>
<ul>
<li>Code: AccessDenied</li>
<li>Message: Access Denied</li>
<li>RequestId: 7CB5D6DEF9900DAF</li>
<li>HostId: eZXWOY0c/trV8q9+erYXt8mVl2qeJ12MoIkQSHxH4j3bijpsktiG/w+EQ3aaN2h7hfIOSL+K0p0=</li>
</ul>
<hr/>
</body>
</html>
```

# CloudFrontへ独自ドメインでアクセスする

Route53を利用して独自ドメインのblog.example.comでCloudFront経由のアクセスができるようにします。

CloudFrontでの変更

+ Alternate Domain Names(CNAMEs)->blog.example.com

Route53でAレコードを追加

+ Name->blog.example.com
+ Alias->Yes
+ Alias Target->xxx.cloudfront.net(CloudFrontのalias)

```bash
#　DNSで引けるか確認.CDNなのでエッジロケーションのIP群が返却
$dig blog.example.com

; <<>> DiG 9.9.5-3-Ubuntu <<>> blog.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30296
;; flags: qr rd ra; QUERY: 1, ANSWER: 8, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4000
;; QUESTION SECTION:
;blog.example.com.          IN      A

;; ANSWER SECTION:
blog.example.com.   60      IN      A       54.192.117.185
blog.example.com.   60      IN      A       54.192.117.84
blog.example.com.   60      IN      A       54.192.117.88
blog.example.com.   60      IN      A       54.192.117.136
blog.example.com.   60      IN      A       54.192.117.190
blog.example.com.   60      IN      A       54.192.117.18
blog.example.com.   60      IN      A       54.192.117.116
blog.example.com.   60      IN      A       54.192.117.241

;; Query time: 24 msec
;; SERVER: 10.0.2.3#53(10.0.2.3)
;; WHEN: Tue Jan 26 xx:xx:xx JST 2016
;; MSG SIZE  rcvd: 177

# curlで取得。CloudFrontのStatusがDeployedになっている事を確認すること
$curl http://blog.example.com
hello world!
```

# ACM(AWS Certificate Manager)を使ってSSL化する

現在の状態でもHTTPSアクセスは可能ですが、CloudFrontのデフォルトドメインに対しての証明書なので現在の独自ドメインの証明書とは違います。
ACMを使ってSSL証明書を発行し、CloudFrontと連携するとことで正しいSSL証明書でアクセスできるようにします。

ACMでSSL証明書を申請後、申請ドメイン宛にメールが送信されてくるため、まず、独自ドメインでメールが受信できるようにします。
ちなみにメール受信設定をしっかりしていないとはまります。。。

[AWS Certificate Manager (ACM)で申請前に事前に確認しておくべき大切なこと](http://qiita.com/toshihirock/items/cf4e6d8afa08beaa728c)

今回はAWSのSESを使ってメール受信を行い、S3に保存するようにします。
以下を参考に設定してみました。

[[新機能]Amazon SES でメール受信が出来るようになりました！](http://dev.classmethod.jp/cloud/receiving-email-with-amazon-ses/)

+ SESの画面を表示->Domains->Verify a New Domain
+ Domainの欄に「blog.example.com」と入力
+ DNSにTXTレコードとMXレコードを追加する必要がある記述が表示。Route53を使っているので「Use Route53」を選択
+ 「Domain Verification Record」、「Email Receiving Record」にチェックを入れ、「Create Record Sets」を選択（Email Receiving Recordはデフォルトはチェックされていないので注意）

と、MXレコードが追加されそうだと思ったのですが、されなかったので自分で登録します。。。

+ Name->blog.example.com
+ Type->MX
+ Value->10  inbound-smtp.us-east-1.amazonaws.com

何はともあれ追加できたので次にSESで受信ルールを設定します。

+ 画面右のRule Setsを選択し、「Create a New Rule set」を選択し、Rule Setを作成する
+ 「View Active Rule Set」を選択後、「Crete Rule」を選択
+ Recipientで「blog.example.com」と設定し、このドメインでのアクションを設定する
+ Add actionで「S3」を設定し、メール受信時に情報を取得するバケットを設定する

これでACM申請時に送信されるadmin@blog.example.comなどへのメールがSESで受信できるはずなので、一度Gmailなどからメールを送信し、確認します。
受信がうまくできればS3にメール内容が保存されているはずです。

ここまでうまくいけば受信の設定ができているのでいよいよACMの設定を行います。

+ ACMの画面を開いてGet startedを選択
+ Domainに「blog.example.com」と記述

申請後、SESの受信時のアクションで設定したバケットを確認し、メールが入っていることを確認します。メールには承認用のリンクがあるのでそれをブラウザで開いて、承認します。

承認が無事終われば、ACMの画面でStatusがIssuedとなっていることが確認できます
CloudFrontの画面からACMで設定したSSL証明書を有効にします。


+ SSL Certificateで「Custom SSL Certifiacte」を選択し、先ほど作成したblog.example.com用の証明書を選択します。

これでブラウザから https://blog.example.com でアクセスすると正式な証明書が！！

<img width="88" alt="Screen Shot 2016-01-26 at 8.59.03 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/20193/b1e0ee3f-808c-a5f9-0f1a-d05d748fccca.png">


お疲れ様でした。