Let's Encriptの証明書の更新時にフックを設定する

Let’s Encriptの証明書の更新時にフックを設定する方法について調べました。

複数のドメインをSNI運用しているメールサーバーがあり、それぞれのドメインごとにLet’s Encriptの証明書を利用しています。

それぞれのドメインとそのドメインの証明書を対応させるPostfixのSNIマッピングのデータベースファイルの更新を証明書の更新時に自動で行うためににフックを利用することにしました。

証明書更新時のフックの設定

例えばexample.comのドメインの証明書の更新時にフックを設定する場合、/etc/letsencript/renewal/にある設定ファイルexample.comrenewalparamsrenew_hookを追加して実行するコマンドを記載ます。

/etc/letsencript/renewal/example.com
[renewalparams]
account = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
authenticator = nginx
server = https://acme-v02.api.letsencrypt.org/directory
renew_hook = 実行したいコマンドを記載する

以下の設定のようにSNIマッピングのデータベースファイルでPostfixをSNI運用している場合、証明書が変更された時にSNIマッピングのデータベースファイルの更新もを行わないと証明書の変更が反映されません。

/etc/postfix/main.cf
tls_server_sni_maps = hash:${config_directory}/tls_server_sni_maps

SNIマッピングのデータベースファイルの更新はpostmapコマンドにSNIのマッピングを指定して行います。

postmap -F /etc/postfix/tls_server_sni_maps

このコマンドを対象のドメインのLet’s Encriptの設定ファイルのrenew_hookに設定します。

/etc/letsencript/renewal/example.com
[renewalparams]
account = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
authenticator = nginx
server = https://acme-v02.api.letsencrypt.org/directory
renew_hook = postmap -F /etc/postfix/tls_server_sni_maps

設定の動作確認

証明書の更新時にSNIマッピングのデータベースファイルを更新するフックを設定したので動作確認を行います。まずはrenew_hookに指定したコマンドが実行されるか--dry-runオプションを指定して確認してみます。

sudo certbot renew \
  --cert-name example.com \
  --force-renewal \
  --dry-run

certbotrenewサブコマンドに--dry-runオプションをつけて実行した場合、実際にrenew-hookは実行されませんが、Dry run:に続けて実行される予定のrenew_hookに指定したコマンドが以下のように表示されます。

Dry run: skipping deploy hook command: postmap -F /etc/postfix/tls_server_sni_maps

それでは実際の証明書の更新処理の確認を行うため--dry-runオプションをつけずに実行します。

sudo certbot renew \
  --cert-name example.com \
  --force-renewal

更新された証明書と実際にPostfixが利用している証明書が同じであるか比較して更新された証明書が使用されているかの確認を行います。

サーバーにある証明書のNot BeforeとPostfixが利用している証明書のNot Beforeの日付を比較して一致している場合は更新された証明書をPostfixが使用していることが確認できます。

まずは以下のコマンドをメールサーバーで実行して更新された証明書のNot Beforeの日付を確認します。

sudo openssl x509 -noout -text \
  -in /etc/letsencrypt/live/example.com/fullchain.pem |
  grep 'Not Before'

今度はメールサーバー以外の環境からPostfixに接続して証明書のNot Beforeの日付を出力してみて、メールサーバーで確認した証明書の日付と一致していることを確認します。

openssl s_client \
  -connect example.com:smtps\
  -showcerts | openssl x509 -text | grep 'Not Before'

メールサーバーで出力した日付とメールサーバー以外の環境からPostfixに接続して出力した日付が一致したことからPostfixが更新された証明書を利用していることが確認できました。

まとめ

Let’s Encriptでは設定ファイルに証明書の更新時に行うコマンドを記載することができ、証明書の自動更新時にそのコマンドを実行させるフックを設定することができます。この機能を利用することで定期作業を自動化することができ運用のコストを減らすことができます。