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


課題・背景・概要

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

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

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

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

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です。

プラグインインストール

# pip install certbot-dns-route53

IAMポリシー定義

{
    "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で確認します。

IAMユーザ作成

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

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

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

# aws configure

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

[default]
aws_secret_access_key = dscyiPgxxxxxxxxxxxxxxxxxxxxxx
aws_access_key_id = AKIAxxxxxxxxxxxxxxxxxxxxxxxx

テスト実行

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

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

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

スクリプトの作成

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

/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