起こったこと
Let's Encryptの証明書をcertbot-autoを使って自動更新をかけているが、2019年7月13日の深夜の更新で、一部のサイトでERR_SSL_PROTOCOL_ERRORが表示されるようになった(Chrome)。IEやEdgeでも同様にエラー表示。
※certbot-autoは証明書の残期間が1ヶ月を切らないと証明書の更新を行わないので、上記の更新の日付はあまり意味がありません。これまでにも発生しているかもしれませんし、今後も発生するかもしれません。たまたまこちらの環境で、この日に発生したというだけの情報です。
忙しい人のための結論
HTTPSのデフォルトサイトに下記の記述を入れれば良い。
ssl_session_tickets off;
もう少し詳しい説明
etckeeperを入れているので、当該の更新で何が変わったのかを確認する。どうやら、このあたりが怪しい。ssl_session_tickets off; をコメントアウトすると案の定復帰。
diff --git a/letsencrypt/options-ssl-nginx.conf b/letsencrypt/options-ssl-nginx.conf
index 292d429..3cc2b9b 100644
--- a/letsencrypt/options-ssl-nginx.conf
+++ b/letsencrypt/options-ssl-nginx.conf
@@ -4,8 +4,9 @@
# the up-to-date file that you will need to refer to when manually updating
# this file.
-ssl_session_cache shared:le_nginx_SSL:1m;
+ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
+ssl_session_tickets off;
options-ssl-nginx.conf というのは何かというと、certbotでnginxの設定を自動修正した場合に、virtualhostの設定にこんな感じでincludeされるデフォルトの設定。
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/info-lounge.jp/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/info-lounge.jp/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
問題のssl_session_ticketsはこういうものらしい。
TLSセッションチケットは簡単に言うとTLSのセッション情報を暗号化してクライアント側に保存することで HTTPS通信時に行われるTLSハンドシェイクの手順を省略してネットワークレイテンシを削減するための仕組みです。
https://tech.mercari.com/entry/2015/11/16/170037
options-ssl-nginx.conf でこの行だけコメントアウトすれば問題なく稼働するが、このファイルを書き換えた場合には、今後Let's Encrypt側の推奨値が変わっても、このファイルの自動アップデートがかからなくなるとの記載がある。
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file.
そこで、問題の本質を解決するために調査をすると、こんなチケットが見つかった。
https://github.com/jwilder/nginx-proxy/issues/580
あとは、忙しい人のための結論のとおり。
server {
listen 443 ssl default;
server_name _;
ssl_session_tickets off;
ssl_certificate /etc/pki/tls/certs/xxx.xxx.xxx.xxx.crt;
ssl_certificate_key /etc/pki/tls/private/xxx.xxx.xxx.xxx.key;
return 444;
}