8月1日以降、Let’s Encrypt サービスに変更が生じたようです。私の証明書は今日まで有効だったため、この変更の影響は今日初めて受けました。Discourse が Let’s Encrypt サービスを管理するために使用するスクリプトは、デフォルトで Let’s Encrypt の代わりに新しいサービスである ZeroSSL を使用するよう更新されました。残念ながら、ZeroSSL は機能させるために事前にメールアドレスでの登録が必要のようで、今朝既存の証明書が失効した際、サイトが動作しなくなりました。
かなり調査した結果、問題の原因を特定できました。一時的な回避策は講じましたが、私が行った修正が必ずしも「正しい」解決策ではないと考えています。まず、ログに表示されていたエラーメッセージは以下の通りです。
[Wed 01 Sep 2021 05:33:58 PM UTC] Reload error for :
[Wed 01 Sep 2021 05:34:03 PM UTC] Using CA: https://acme.zerossl.com/v2/DV90
[Wed 01 Sep 2021 05:34:04 PM UTC] No EAB credentials found for ZeroSSL, let's get one
[Wed 01 Sep 2021 05:34:04 PM UTC] acme.sh is using ZeroSSL as default CA now.
[Wed 01 Sep 2021 05:34:04 PM UTC] Please update your account with an email address first.
[Wed 01 Sep 2021 05:34:04 PM UTC] acme.sh --register-account -m my@example.com
[Wed 01 Sep 2021 05:34:04 PM UTC] See: https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA
[Wed 01 Sep 2021 05:34:04 PM UTC] Please check log file for more details: /shared/letsencrypt/acme.sh.log
コンテナ内から手動でアカウント登録を試みましたが、登録完了のメッセージが表示された後、コンテナを再起動すると同じエラーが発生しました。そこでスクリプトを追跡したところ、この処理を行うスクリプトはコンテナ内の /etc/runit/1.d/letsencrypt に存在することがわかりました。元のスクリプトは以下の通りです。
#!/bin/bash
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf
issue_cert() {
LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh --issue $2 -d mudtoemanor.baronshire.org --keylength $1 -w /var/www/discourse/public
}
cert_exists() {
[[ "$(cd /shared/letsencrypt/mudtoemanor.baronshire.org$1 && openssl verify -CAfile ca.cer fullchain.cer | grep "OK")" ]]
}
########################################################
# RSA cert
########################################################
issue_cert "4096"
if ! cert_exists ""; then
# Try to issue the cert again if something goes wrong
issue_cert "4096" "--force"
fi
LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh \
--installcert \
-d mudtoemanor.baronshire.org \
--fullchainpath /shared/ssl/mudtoemanor.baronshire.org.cer \
--keypath /shared/ssl/mudtoemanor.baronshire.org.key \
--reloadcmd "sv reload nginx"
########################################################
# ECDSA cert
########################################################
issue_cert "ec-256"
if ! cert_exists "_ecc"; then
# Try to issue the cert again if something goes wrong
issue_cert "ec-256" "--force"
fi
LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh \
--installcert --ecc \
-d mudtoemanor.baronshire.org \
--fullchainpath /shared/ssl/mudtoemanor.baronshire.org_ecc.cer \
--keypath /shared/ssl/mudtoemanor.baronshire.org_ecc.key \
--reloadcmd "sv reload nginx"
if cert_exists "" || cert_exists "_ecc"; then
grep -q 'force_https' "/var/www/discourse/config/discourse.conf" || echo "force_https = 'true'" >> "/var/www/discourse/config/discourse.conf"
fi
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf -s stop
メール登録が機能しなかったため、acme.sh スクリプトがデフォルトで ZeroSSL の代わりに元の Let’s Encrypt を使用するようオプションを追加することにしました。その方法は以下のウェブサイトで説明されています:https://community.letsencrypt.org/t/the-acme-sh-will-change-default-ca-to-zerossl-on-august-1st-2021/144052
まず、スクリプトの3行目、/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf の直後に以下の行を追加してみました。
/shared/letsencrypt/acme.sh --set-default-ca --server letsencrypt
ログにはデフォルトが変更されたというメッセージが表示されましたが、その直後に ZeroSSL 用のメール未登録に関する同じエラーが発生しました。ログにはそのメッセージとエラーメッセージの間に約6秒の遅延があり、acme.sh スクリプトが環境変数を通じて状態情報を保持しており、その後のコマンド実行が異なるコンテキストで実行されたため変数が失われたのではないかと思われます。そのため、最終的に let’s encrypt スクリプト内の acme.sh のすべての呼び出しに --server letsencrypt という引数を追加するように変更しました。その上でコンテナを再起動すると、ZeroSSL ではなく Let’s Encrypt によって新しい証明書が生成され、サイトが復旧しました。
以下は私が使用した修正版の letsencrypt スクリプトです。
#!/bin/bash
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf
/shared/letsencrypt/acme.sh --set-default-ca --server letsencrypt
issue_cert() {
LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh --server letsencrypt --issue $2 -d mudtoemanor.baronshire.org --keylength $1 -w /var/www/discourse/public
}
cert_exists() {
[[ "$(cd /shared/letsencrypt/mudtoemanor.baronshire.org$1 && openssl verify -CAfile ca.cer fullchain.cer | grep "OK")" ]]
}
########################################################
# RSA cert
########################################################
issue_cert "4096"
if ! cert_exists ""; then
# Try to issue the cert again if something goes wrong
issue_cert "4096" "--force"
fi
LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh \
--installcert \
-d mudtoemanor.baronshire.org \
--fullchainpath /shared/ssl/mudtoemanor.baronshire.org.cer \
--keypath /shared/ssl/mudtoemanor.baronshire.org.key \
--server letsencrypt \
--reloadcmd "sv reload nginx"
########################################################
# ECDSA cert
########################################################
issue_cert "ec-256"
if ! cert_exists "_ecc"; then
# Try to issue the cert again if something goes wrong
issue_cert "ec-256" "--force"
fi
LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh \
--installcert --ecc \
-d mudtoemanor.baronshire.org \
--fullchainpath /shared/ssl/mudtoemanor.baronshire.org_ecc.cer \
--keypath /shared/ssl/mudtoemanor.baronshire.org_ecc.key \
--server letsencrypt \
--reloadcmd "sv reload nginx"
if cert_exists "" || cert_exists "_ecc"; then
grep -q 'force_https' "/var/www/discourse/config/discourse.conf" || echo "force_https = 'true'" >> "/var/www/discourse/config/discourse.conf"
fi
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf -s stop
デフォルトサービスを設定しようとして挿入した元のコマンドは、念のため残してありますが、必須ではないかもしれません。
したがって、このスクリプトを変更する必要があります。具体的には、acme.sh のすべての呼び出しで使用する Let’s Encrypt サービスを明示的に定義するか、acme.sh が状態情報をどのように保存しているかを特定してデフォルトコマンドの単一実行で機能するようにするか、最後に ZeroSSL のサポートとメールアドレスの収集・保存の必要性に対応する機能を追加する必要があります。
バージョンアップ時にこの変更が上書きされ、再度行う必要があると想定しています。もし何か見落としている点や、スクリプトの変更を必要としない別の対応策があれば、お知らせください。