Debian8 系に最新の certbot をインストールして Route53 で認証する

# TL;DR

我が家の Debian8 系のファイルサーバ([OpenMediaVault](https://www.openmediavault.org/))では、 [Nextcloud](https://nextcloud.com/) を利用して HTTPS 経由でファイルをやり取りできるようにセットアップしていますが、証明書が自己署名証明書であるために警告が出たりして何かと煩わしい状態です。

そこで、 Let's Encrypt(`certbot`) で証明書を発行して運用することに決めました。ちょうど先日、 AWS Route53 でドメインを管理するようにしたので、ここでは Route53 を用いて DNS-01 認証を利用し登録します。

# 前提条件

*   AWS Route53 を利用している事。
*   AWS の IAM ユーザーやポリシーを設定できる権限を持っている事。
*   `certbot` を動かすサーバがオンプレミスにあるか、 IAM Role が割り当てられていないこと。  
    (IAM Role が割り当てられている EC2 Instance の場合は、 IAM ユーザーの設定周りの記述を IAM Role に読み替え、 `.aws/credentials` の設定は行わないでください。)

# Let's Encrypt で証明書を発行する方法

## certbot 本体をセットアップ

### 利用ツールをインストール

```shell-session
# apt-get install git virtualenv
```

### 最新版の certbot をダウンロード

`apt-get` でも `certbot` をインストールできますが、それだとバージョンが古すぎる(`0.10.2`)ので、 GitHub から取得します。

```shell-session
# git clone https://github.com/certbot/certbot.git
# cd certbot
```

### virtualenv する

```shell-session
# virtualenv certbottest
# source certbottest/bin/activate
```

### certbot をインストール

```shell-session
# cd ./acme/
# python setup.py install
# cd ../
# python setup.py install
```

もし `python setup.py install` で失敗するようであれば、 `setuptools` を更新してみてください。

```shell-session
# pip install -U setuptools
```

### certbot 本体の動作を確認

実際にバージョン表示させてみます。

```shell-session
# certbot --version
certbot 0.26.0.dev0
```

上記のようにバージョンが表示されれば OK.

## certbot-dns-route53 プラグインをセットアップ

Route53 を用いて DNS-01 認証を実施するために、 `certbot-dns-route53` プラグインをセットアップします。

`certbot-dns-route53` は既に `git clone` した `certbot` リポジトリに含まれているので、それを利用します。

### certbot-dns-route53 プラグインをインストール

```shell-session
# cd certbot-dns-route53/
# python setup.py install
```

### certbot-dns-route53 プラグインの動作確認

`--dry-run` オプションを付与して Dry run させてみます。この時の `--email` は適当で良いでしょう。

```shell-session
# certbot certonly -n --agree-tos --email test@example.com --dns-route53 --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Starting new HTTP connection (1): 169.254.169.254
Plugins selected: Authenticator dns-route53, Installer None
Missing command line flag or config entry for this setting:
Please enter in your domain name(s) (comma and/or space separated)

(You can set this with the --domains flag)
```

特にエラーを吐く様子もなく動作すれば OK.

## AWS 周りの設定

`certbot-dns-route53` を使って証明書を発行するためには、 `certbot` コマンドが DNS-01 認証に必要な操作を行えるように、 Route53 に対していくつかのアクションを行えるようになっている必要があります。
ここでは、そのための準備を行います。

### IAM ポリシーの作成

[sample-aws-policy.json](https://github.com/certbot/certbot/blob/master/certbot-dns-route53/examples/sample-aws-policy.json) を参考に、ポリシーを作成してください。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "route53:ListHostedZones",
                "route53:GetChange"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect" : "Allow",
            "Action" : [
                "route53:ChangeResourceRecordSets"
            ],
            "Resource" : [
                "arn:aws:route53:::hostedzone/YOURHOSTEDZONEID"
            ]
        }
    ]
}
```

`YOURHOSTEDZONEID` は、証明書を発行するドメインの `Hosted Zone Id` を [Route53 のコンソール](https://console.aws.amazon.com/route53/home?region=us-east-1#hosted-zones:) から確認してください。

### IAM ユーザーの作成

上記ポリシーを適用した IAM ユーザーを作成してください。

ユーザー名は `certbot` 等でよいでしょう。 `アクセスキー ID` と `シークレットアクセスキー` はメモしてください。

### .aws/credentials を作成

作成した IAM ユーザーの情報を、 `certbot` を実行するサーバに登録します。
`.aws/credentials` に上記で作成した IAM ユーザの `アクセスキー ID` と `シークレットアクセスキー` を保存します。

```shell-session
# mkdir ~/.aws
# vim ~/.aws/credentials
```

```~/.aws/credentials
[default]
aws_access_key_id = your_access_key_id
aws_secret_access_key = your_secret_access_key
```

`your_access_key_id` を IAM ユーザの `アクセスキー ID` に、 `your_secret_access_key` を IAM ユーザの `シークレットアクセスキー` に置き換えて保存してください。 `"` でくくる必要はありません。

### 証明書を発行する

証明書を発行します。下記の `your_mail_addr@example.com` は自身のメールアドレスを、 `your.domain.example.com` は証明書を発行するドメインの名前を指定してください。

```shell-session
# certbot certonly -n --agree-tos --email your_mail_addr@example.com --dns-route53 -d your.domain.example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Found credentials in shared credentials file: ~/.aws/credentials
Plugins selected: Authenticator dns-route53, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for your.domain.example.com
Starting new HTTPS connection (1): route53.amazonaws.com
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/your.domain.example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/your.domain.example.com/privkey.pem
   Your cert will expire on 2018-10-01. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
```

これで証明書の発行ができました。

証明書は `/etc/letsencrypt/live/<ドメイン名>` の配下にありますが、こちらはシンボリックリンクとなっています。これは定期的に証明書を取得しなおすように設定した際に、常に新しい証明書を参照できるようにする為です。実体は `/etc/letsencrypt/archive/<ドメイン名>` の配下にあり、古いものから順に `cert1.pem` のようにナンバリングされます。

```shell-session
# ls -l /etc/letsencrypt/live/your.domain.example.com/
total 4
lrwxrwxrwx 1 root root  43 Jul  3 18:35 cert.pem -> ../../archive/your.domain.example.com/cert1.pem
lrwxrwxrwx 1 root root  44 Jul  3 18:35 chain.pem -> ../../archive/your.domain.example.com/chain1.pem
lrwxrwxrwx 1 root root  48 Jul  3 18:35 fullchain.pem -> ../../archive/your.domain.example.com/fullchain1.pem
lrwxrwxrwx 1 root root  46 Jul  3 18:35 privkey.pem -> ../../archive/your.domain.example.com/privkey1.pem
-rw-r--r-- 1 root root 682 Jul  3 18:35 README
```

あとは、これらの生成されたファイルを必要な場所に置いたり、サーバ側の設定を変更して `certbot` が生成した証明書のパスを参照するようにしたりすれば OK です。

# FYI

## NG 集

試行錯誤する中でハマったというか、気付いた事。

### apt-get でインストールした certbot では動かない

`apt-get` でも `certbot` をインストールすることはできますが、バージョンが古すぎてプラグインが動作しませんでした。

```shell-session
$ sudo apt-get install certbot -t jessie-backports
$ certbot --version
certbot 0.10.2
```

`certbot 0.10.2` だと、 `certbot-dns-route53` をインストールした後に `certbot` 自体が動作しなくなってしまいます。

```shell-session
$ sudo pip install certbot-dns-route53
$ certbot --version
An unexpected error occurred:
VersionConflict: (certbot 0.10.2 (/usr/lib/python2.7/dist-packages), Requirement.parse('certbot>=0.21.1'))
Please see the logfile 'certbot.log' for more details.
```

## 参考文献

*   [Let's Encrypt (certbot) を使ってワイルドカード証明書する！(あとちょっと)](https://qiita.com/chamaharun/items/9b8c00d14c05c025febd)