Let’s Encrypt で SSL error: Leaf certificate is expired が出てメールが受信できなくなった場合

突如、Gmailでメールの送受信でエラーが発生するようになりました。

詳細を見てみると、数日前から発生していたみたいですね。ぜんぜん使っていないメールアドレスなので気が付きませんでした^^

証明書は自動更新してあるのですが、どうも期限切れっぽいので確認していきます。

opensslで証明書を確認する

WEB(443ポート)

openssl s_client -connect localhost:443 -showcerts
………
………

    Start Time: 1622461737
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
    Max Early Data: 0
---

問題なさそう。

POP3S(995ポート)

openssl s_client -connect localhost:995 -showcerts
………
………

    Start Time: 1622461877
    Timeout   : 7200 (sec)
    Verify return code: 10 (certificate has expired)
    Extended master secret: no
    Max Early Data: 0
---

あら、certificate has expired エラーが出る。

設定の確認

Postfix、Dovecotの設定を見てみても、証明書のパスは問題無く、証明書も最新に更新されている。

Postfix

/etc/postfix/main.cf
# TLS parameters
#smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
#smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_tls_cert_file = /etc/letsencrypt/live/monmon.jp/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/monmon.jp/privkey.pem

Dovecot

/etc/dovecot/conf.d/10-ssl.conf
# root. Included doc/mkcert.sh can be used to easily generate self-signed
# certificate, just make sure to update the domains in dovecot-openssl.cnf
ssl_cert = </etc/letsencrypt/live/monmon.jp/fullchain.pem
ssl_key = </etc/letsencrypt/live/monmon.jp/privkey.pem

と同一ファイルを参照し、

ls -la /etc/letsencrypt/live/monmon.jp/
drwxr-xr-x 2 root root 4096 Apr 28 08:07 .
drwx------ 3 root root 4096 Feb 26 20:05 ..
-rw-r--r-- 1 root root  692 Feb 26 19:08 README
lrwxrwxrwx 1 root root   33 Apr 28 08:07 cert.pem -> ../../archive/monmon.jp/cert2.pem
lrwxrwxrwx 1 root root   34 Apr 28 08:07 chain.pem -> ../../archive/monmon.jp/chain2.pem
lrwxrwxrwx 1 root root   38 Apr 28 08:07 fullchain.pem -> ../../archive/monmon.jp/fullchain2.pem
lrwxrwxrwx 1 root root   36 Apr 28 08:07 privkey.pem -> ../../archive/monmon.jp/privkey2.pem

最新ファイルが参照されていました。

解決です

あれ、ひょっとしてこれは、最新の証明書が読み込めてないだけ?
Postfix、Dovecotをリロードしてみます。

sudo systemctl reload postfix dovecot

するとどうでしょう。

openssl s_client -connect localhost:995 -showcerts
………
………

    Start Time: 1622462738
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
    Max Early Data: 0
---

なおりました(笑)

どうやら、let’s encrypt の自動更新にあわせて、Postfix、Dovecotのリロードが必要なんですね。

再発防止

let’s encrypt の証明書更新後にhookされる機能があるみたい。

/etc/letsencrypt/renewal-hooks

このフォルダに以下の3つのフォルダがあり、そこに実行ファイルを置いておけば実行されるみたいです。

ディレクトリタイミング条件
deploy自動更新の処理証明書を更新した場合のみ実行
post自動更新の処理無条件に実行
pre自動更新の処理無条件に実行

こんな感じで分かれるみたいです。

よって今回は deploy を使います。

sudo vi /etc/letsencrypt/renewal-hooks/deploy/reload_postfix_dovecot.sh
#!/usr/bin/bash
systemctl reload postfix dovecot
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload_postfix_dovecot.sh

名称はなんでも。シェルを作りました。

シェル単体では動くので、次の更新時にリロードされるはず。

postfixのSNI運用中の場合は

2022/2/7 追記

証明書が更新されるたびに、tls_server_sni_maps の再構築が必要みたいです。

sudo vi /etc/letsencrypt/renewal-hooks/deploy/reload_postfix_dovecot.sh
#!/usr/bin/bash
postmap -F /etc/postfix/tls_server_sni_maps
systemctl reload postfix dovecot

こんな感じで、更新処理もシェルに追加しておきました。

うまく動きますように……