AWS Certificate Manager (ACM) CLI メモ

ACM とは
======
AWSがELBかCloudFrontで使用する場合に限り使用できる無償のSSL証明書発行サービスです。
SSL証明書といえば賞味期限切れを大手サイトもやらかすなどトラブルが多いですが、なんとフルマネージドで自動更新までやってくれます。一度設定すればメンテナンス不要なのは嬉しいですね。
無償なのでいくつ作っても良いですが、ワイルドカード証明書も作成できます。
１つの証明書に複数のドメインを格納することも可能です。
みんな大好きAWSCLIで使ってみましょう。

2016/5/17追記: 東京リージョン(ap-northeast-1)に対応しました！
------
以前はバージニアだけでしたが、今回同時にカリフォルニア・オレゴン・アイルランド・フランクフルト・ソウル・シンガポール・シドニー・サンパウロと、大幅に対応リージョンが増えました。

前提条件
========
- デフォルトVPCが存在すること。無くても動きますが適宜パラメータを追加して作業してください。
- whoisに登録されている連絡先か、使用するドメインの webmaster, admin, postmaster, hostmaster, administrator 宛のいずれかの電子メイルを受信出来るようにしておくこと。
- AWSCLI バージョン 1.10.0 以上がインストールされていること。

準備しておくもの
--------------
- ap-northeast-1リージョン（東京）のデフォルトVPC内にWebサーバ(nginx,apache httpd等)が動作しているEC2インスタンスを1台稼働させておくこと。

実行権限
--------------
- ACMとELBを操作できること。

AWS CLIのバージョン
-------------------
以下のバージョンで動作確認済

* AWSCLI 1.10.0

```bash:コマンド:
aws --version
```
```text:結果(例):
      aws-cli/1.10.0 Python/2.6.6 Linux/2.6.32-573.8.1.el6.x86_64 botocore/1.3.22
```
注意：ACMはAWSCLI 1.10.0 で新規追加されたコマンドです。これより前のバージョンでは動作しませんのでご注意ください。


0. 事前作業
===========

0.1. リージョンの決定
---------------------

ap-northeast-1 (東京)リージョンにて作業します。
よってリージョンをそのように設定します。
(カレントユーザが利用するカレントリージョンも切り変わります。)

```bash:変数の設定:
export AWS_DEFAULT_REGION='ap-northeast-1'
```

0.2. 変数の確認
---------------

プロファイルとリージョンが想定のものになっていることを確認します。

```bash:コマンド
aws configure list
```
```text:結果(例):
            Name                    Value             Type    Location
            ----                    -----             ----    --------
         profile                <not set>             None    None
      access_key     ****************M73Q shared-credentials-file
      secret_key     ****************YWg/ shared-credentials-file
          region           ap-northeast-1              env    AWS_DEFAULT_REGION
```

0.3. EC2インスタンスのInstance ID取得
---------------

```bash:コマンド
INSTANCE_ID=`aws ec2 describe-instances \
 --query 'Reservations[].Instances[].InstanceId[]' \
 --output text` && echo ${INSTANCE_ID}
```
```text:結果(例):
      i-88888888
```

0.4. EC2インスタンスのAvailability Zone取得
---------------

```bash:コマンド
AVAILABILITY_ZONE=`aws ec2 describe-instances \
 --query 'Reservations[].Instances[].Placement[].AvailabilityZone[]' \
 --output text` && echo ${AVAILABILITY_ZONE}
```
```text:結果(例):
      ap-northeast-1a
```


1. SSL証明書の作成
===========

example.comのSSL証明書作成します。ドメイン名は適宜書き換えてください。
今回は example.com と www\.example.com 両方でアクセスできるよう追加ドメインを設定します。

1.1. SSL証明書作成リクエストの送信
---------------------

```bash:コマンド
CERT_ARN=`aws acm request-certificate \
 --domain-name example.com \
 --subject-alternative-names www.example.com \
 --domain-validation-options DomainName=www.example.com,ValidationDomain=example.com \
 --output text` && echo ${CERT_ARN}
```
```text:結果(例):
      arn:aws:acm:ap-northeast-1:444444444444:certificate/a7777777-7777-7777-7777-777777777777
```

入力したドメインについて次項のドメイン所有確認手続きが必要です。
今回は同一ドメインで２つのFQDN(example.comとwww.example.com)を設定しています。デフォルトだとドメイン所有確認が入力したドメイン全て @example.com @www\.example.com 宛に送られますが、同一ドメインなのにこれは面倒ですよね。
同一ドメインのFQDNに限りこれをまとめることができます。 @example.com だけに送るよう --domain-validation-option を追加してあります。（逆は不可です。サブドメインに集約することはできません）
複数のドメインを追加することもできますが、その場合は全てのドメインについて次項のドメイン所有確認手続きが完了するまでは証明書が有効になりません。

1.2. ドメイン所有確認手続き
---------------------

SSL証明書作成リクエストをするとドメイン所有確認の電子メイルが届きます。ただしAWSアカウント宛に届くわけではありません。
whoisに登録されている連絡先と、そのドメインの webmaster, admin, postmaster, hostmaster, administrator 宛に送られます。

届いた電子メイルの文中に書かれているURLをWebブラウザで開き "I Approve" ボタンを押します。
"Success!" という表示が出れば確認処理完了です。

ちなみにこの手続きを電子メイルサーバ側で届いたらcurlで自動処理することを試みるも玉砕。URLを開いた後に"I Approve"ボタンを押さないといけないからです。多分CURLのレベル高い人なら自動化できるのと思います。プルリクお待ちしています。

1.3. SSL証明書作成完了の確認
---------------------

再びCLI端末に戻り、証明書ができあがったか確認します。

```bash:コマンド
aws acm describe-certificate \
 --certificate-arn ${CERT_ARN} \
 --query 'Certificate.[Status]' --output text
```
```text:結果:
      ISSUED
```

ISSUEDと表示されれば発行完了しています。PENDINGと出たら電子メイル確認に失敗しているので前の手順をやり直し。


2. ELBの作成とSSL証明書の登録
===========

2.1. セキュリティグループの作成
-----------------------

セキュリティグループ acm-handson-sg を作成します。

```bash:コマンド:
SG_NAME="acm-handson-sg"
aws ec2 create-security-group \
 --group-name ${SG_NAME} --description ${SG_NAME}
SG_ID=`aws ec2 describe-security-groups \
 --filter Name=group-name,Values=${SG_NAME} \
 --query 'SecurityGroups[].GroupId' --output text` && echo ${SG_ID}
```
```text:結果(例):
      {
          "GroupId": "sg-59c3e63d"
      }

      sg-59c3e63d
```

外部からのHTTPS接続をセキュリティグループに追加。

```bash:コマンド:
aws ec2 authorize-security-group-ingress --group-id ${SG_ID} \
 --protocol 'tcp' --port 443 --cidr 0.0.0.0/0
```
```text:結果:
      (返り値なし)
```

2.2. ELBの作成
-----------------

作成したSSL証明書とセキュリティグループを用いてELB acm-handson-elb を作成します。
外部からHTTPS(tcp/443)を受け、SSL処理をしてEC2インスタンスへ平文HTTP(tcp/80)で転送するリスナを登録します。

```bash:コマンド:
ELB_NAME="acm-handson-elb"
aws elb create-load-balancer --load-balancer-name ${ELB_NAME} \
 --listeners '{"Protocol":"HTTPS","LoadBalancerPort":443,"InstanceProtocol":"HTTP","InstancePort":80,"SSLCertificateId":"'${CERT_ARN}'"}' \
 --availability-zones ${AVAILABILITY_ZONE} \
 --security-groups ${SG_ID}

```
```text:結果(例):
      {
          "DNSName": "acm-handson-elb-1099484941.ap-northeast-1.elb.amazonaws.com"
      }
```

- このDNSNameは後で使いますのでメモしておきます。

2.3. ELBへインスタンスを追加
-----------------

```bash:コマンド:
aws elb register-instances-with-load-balancer \
 --load-balancer-name ${ELB_NAME} --instances ${INSTANCE_ID}
```
```text:結果(例):
      {
          "Instances": [
              {
                  "InstanceId": "i-88888888"
              }
          ]
      }
```

2.4. ELB稼働状況の確認
-----------------

ELBにEC2インスタンスが登録されるまで少し時間がかかるので数分待ちます。

```bash:コマンド:
aws elb describe-instance-health --load-balancer-name ${ELB_NAME}
```
```text:結果(例):
      {
          "InstanceStates": [
              {
                  "InstanceId": "i-88888888",
                  "ReasonCode": "N/A",
                  "State": "InService",
                  "Description": "N/A"
              }
          ]
      }
```

State が InService になっていれば成功です。


3. DNSサーバの設定変更と動作確認
===========

AWS側の作業は全て完了しています。
後は 2.2. で作成されたELBのDNSNameをドメインのDNSサーバへCNAMEレコードとして設定し、ブラウザでアクセスできるか確認をします。
これは使用しているDNSサーバにより異なるので各自行ってください。


4. まとめ
===========

とても簡単にSSL証明書を作成して使うことができました。（ドメインの所有確認部分がAWSCLIで完結できないのが残念ですが）

気になるのはドメイン所有確認の電子メイル送信先です。
SSL証明書業者は一般に確認用の電子メイル送信先を（一定の規定内で）指定できますが、ACMではこれを選択できず5個以上のアドレスへ自動的に送られてしまいます。
日本の多くのレジストラ（お名前.comさん・さくらさん等ドメインの登録業者）はwhoisの連絡先にはレジストラの電子メイルアドレスを登録しており関係ない人たちにも送信されてしまうこと、受信不能なアドレスにも送信しようとしてバウンスが発生することなど、このやり方はちょっとどうかなと思いました。