LetsEncryptワイルドカード証明書更新の自動化(route53限定)

# 課題・背景・概要

LetsEncryptのワイルドカード証明書の更新で`certbot renew`を実行すると以下のエラーが発生します。

ワイルドカード証明書の場合、そのドメインを所有していることを証明するために当該ホストに`_acme-challenge.nyango.com` というTXTレコードを追加する必要があるのですが、単純に`renew`するだけだとこの値を設定できないためです。（TXTレコードの値はcertbotからアドホックに指定されるので事前に設定することはできません）

自動化スクリプトを書くこともできるようですが、仕様を調べるのにどれだけの時間を要するのか想像もできず気がすすみません。LetsEncrypt証明書の有効期間は3ヶ月あるので2.5ヶ月に1回くらい手動でシコシコ更新すればいいのですが、それはそれで面倒。

自動化できないか調べてみたら方法があったのでまとめました

```bash
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/nyango.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert is due for renewal, auto-renewing...
Could not choose appropriate plugin: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.',)
Attempting to renew cert (nyango.com) from /etc/letsencrypt/renewal/nyango.com.conf produced an unexpected error: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.',). Skipping.
All renewal attempts failed. The following certs could not be renewed:
  /etc/letsencrypt/live/nyango.com/fullchain.pem (failure)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

All renewal attempts failed. The following certs could not be renewed:
  /etc/letsencrypt/live/nyango.com/fullchain.pem (failure)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 renew failure(s), 0 parse failure(s)

```


# 自動化方法

Route53限定を使用している場合、`certbot-dns-route53`というプラグインを使うことで自動化できます。

`certbot renew`時にオプションでこのプラグインを指定すると上述したTXTレコードを動的に作成してくれるようです。（実行後に確認したところTXTレコードが存在しなかったので最後に削除してくれているようです。親切！）

route53にアクセスする必要があるので、必要最小限の権限を持つIAMポリシーをIAMユーザに割り当てて、その認証情報を`certbot`を実行する端末（の実行ユーザ）に割り当てればOKです。

## プラグインインストール

```bash
# pip install certbot-dns-route53
```

## IAMポリシー定義

```json
{
    "Version": "2012-10-17",
    "Id": "certbot-dns-route53 policy",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "route53:ListHostedZones",
                "route53:GetChange"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "route53:ChangeResourceRecordSets"
            ],
            "Resource": [
                "arn:aws:route53:::hostedzone/★HOSTZONE ID★"
            ]
        }
    ]
}
```

**ホストゾーンID**はRoute53で確認します。

![](https://i.gyazo.com/3619f8590f37f956ba26bb500f086896.png)

## IAMユーザ作成

IAMユーザを作成して、上記のポリシーを割り当てます。認証情報（アクセスキーとシークレットキー）を控えます。

## IAMユーザの認証情報を端末に設定

`certbot renew`を実行する端末（の実行ユーザ）に認証情報を設定。この場合、rootユーザに設定しています。

```bash
# aws configure
```

上記を実行すると`~/.aws/credencials`に登録されます

```shell
[default]
aws_secret_access_key = dscyiPgxxxxxxxxxxxxxxxxxxxxxx
aws_access_key_id = AKIAxxxxxxxxxxxxxxxxxxxxxxxx
```

## テスト実行

```bash
certbot renew --force-renewal --no-self-upgrade --server https://acme-v02.api.letsencrypt.org/directory --agree-tos --dns-route53
```

成功した場合、コンソールの末尾に以下の情報が出力されます。

```bash
Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/nyango.com/fullchain.pem (success)
```

## スクリプトの作成

証明書の更新後にhttpサーバの再起動を実行するスクリプトを用意

```shell:/root/update_cert_wildcard.sh
#! /bin/bash

/bin/certbot renew --force-renewal --no-self-upgrade --server https://acme-v02.api.letsencrypt.org/directory --agree-tos --dns-route53

/bin/systemctl restart httpd.service

```

## （2019/09/04追記）
以下のインポートエラーが発生。
`ImportError: 'pyOpenSSL' module missing required functionality. Try upgrading to v0.14 or newer.`

対処

```
# pip install --upgrade pip
# pip install requests --ignore-installed
# pip install --upgrade --force-reinstall 'requests==2.6.0'
```

## cronへの割当

`0 4 * * 0 /root/update_cert_wildcard.sh`

# 参考URL

- [プラグインの公式ドキュメント](https://certbot-dns-route53.readthedocs.io/en/stable/#)
- [Route53 で Let’s Encrypt 証明書取得&更新を行う最低限の手順 - Qiita](https://qiita.com/komazarari/items/88c1ed18765fb7cab6c1)
- [Let's EncryptのワイルドカードSSL証明書の更新に苦労した話](http://thr3a.hatenablog.com/entry/20180917/1537171887)