noellabo's tech blog

@noellaboの技術ブログ

Let's Encrypt(certbot)で、TLS-SNI-01の削除により証明書の更新に失敗する問題への対応

さくらのクラウド Mastodonスタートアップスクリプトなどで2017年8月15日以前にサーバを立てた人は、2019年2月15日にTLS-SNI-01での証明書取得ができなくなったことを受け、更新に失敗して慌てているのではないかと思います。また、さくらのクラウドに限らず、certbot certonly --standalone --preferred-challenges tls-sni-01で認証していた場合、同様の問題が発生していることが予想されます。

ついては、とりあえずの応急処置の方法と、新しいやり方についてざっくり書いておきました。

応急処置する

やり方は、Let's encryptのフォーラムで中の人によりアナウンスされている通りの方法ですが、こちらであらためて紹介させていただきます。

How to stop using TLS-SNI-01 with Certbot

certbotのバージョンを確認して、0.28以上であればOK。古かったら更新が必要です。certbotは、certbot-autoかもしれません。

certbot --version

certbot renewの時に使う、前回の設定から、tls-sni-01を使用する記述をhttp-01にすり替えてしまう処理を走らせます。実に暗号じみていますが、sedを使って、該当箇所を正規表現で置換しています。ちょっと強引。

sudo sh -c "sed -i.bak -e 's/^\(pref_challs.*\)tls-sni-01\(.*\)/\1http-01\2/g' /etc/letsencrypt/renewal/*; rm -f /etc/letsencrypt/renewal/*.bak"

dry-runをつけてrenewを実行します。

sudo certbot renew --dry-run

これで成功するようになればOKです。

おそらくcron等を仕掛けてあると思いますので、あとは放置しておけば更新されるでしょう。 それでは不安でしたら、手動でrenewを実行してもいいかと思います。

何をしているか

TLS-SNI-01で更新するよう記憶している情報を書き換え、http-01を使ってチェックするように変更します。

これでひとまず更新できるようになりますので、当分は大丈夫です。ああ、よかった……。

これからはdns-01を使おう

さて、ここからが本命。本題です。

落ち着いた今こそ、証明書の取得方法を見直す良いタイミング。

どうせなら、これからのやり方、DNSを使った認証に切り替えましょう。 外からサーバにアクセスできるようにする必要がなくなりますし、ワイルドカード証明書が作れるようになります。

DNSプラグインを利用する

DNSを使って認証する方法を利用します。

マニュアル操作でもできるのですが、自動化できないですし、面倒なので、各種DNSに対応したプラグインが用意されています。

自分の使っているDNSサービスを探してください。(プラグインの対応していないDNSを利用している場合、引っ越した方がいいかもしれません)

さくらのクラウド用も、ちゃんと用意されています!

プラグイン名 DNS
certbot-dns-cloudflare Cloudflare
certbot-dns-cloudxns CloudXNS
certbot-dns-digitalocean DigitalOcean
certbot-dns-dnsimple DNSimple
certbot-dns-dnsmadeeasy DNS Made Easy
certbot-dns-gehirn Gehirn Infrastructure Service
certbot-dns-google Google Cloud
certbot-dns-linode Linode
certbot-dns-luadns LuaDNS
certbot-dns-nsone NS1
certbot-dns-ovh OVH
certbot-dns-rfc2136 RFC 2136(ダイナミックDNS用)
certbot-dns-route53 Route53(Amazon)
certbot-dns-sakuracloud Sakura Cloud(さくらのクラウド)

ここでは、certbot本体と、さくらのクラウド用のcertbot-dns-sakuracloudをインストールして設定する手順を説明します。certbot本体も最新のものにアップデートしておきましょう。

yum install certbot certbot-dns-sakuracloud

Ubuntu / Debianならapt、pythonとpipからもインストールできます。

DNSにアクセスする資格情報をファイルに保存する

さくらのクラウドの場合、さくらのクラウドのAPIキーを保存します。スタートアップスクリプトを利用した場合、既に作成済みです。他のDNSについては、上記の一覧表のリンク先に設定方法の記載があるので、そちらを参照してください。

vi ~/.sakuracloud_credentials

dns_sakuracloud_api_token = 'アクセストークン'
dns_sakuracloud_api_secret = 'アクセストークンシークレット'

このファイルはroot以外読めないようにしておきます。

chmod 600 ~/.sakuracloud_credentials

certbotで証明書を取得する

さて、では証明書を取得します。

下記のコマンドを、自分の実際のドメインにあわせてexample.comと記載した箇所を書き換えて実行してください。メールアドレスもダミーなので、ご自身の普段使っているアドレスに置き換えてください。

certbot certonly --dns-sakuracloud --dns-sakuracloud-credentials ~/.sakuracloud_credentials --expand -d example.com -d *.example.com -m admin@example.com --manual-public-ip-logging-ok --agree-tos --no-eff-email

新規の場合に必要なすべてのオプションを列記しましたが、既に利用中の場合は-mから後ろは不要です。

オプション 説明
certonly 証明書の取得・更新だけを行う指定
--dns-sakuracloud さくらのクラウド用のDNSプラグインを使用
--dns-sakuracloud-credentials ~/.sakuracloud_credentials 資格情報を保存してあるファイルを指定
--expand 既存の証明書に、新しいドメインの指定を追加して拡張する指定。新規の場合は不要
-d example.com 証明書を発行するドメインを指定
-d *.example.com 同じ証明書に含める二つ目のドメインを指定。*の指定により、任意のホスト名に使える証明書になる。必要なければ足さなくても良い
-m admin@example.com Let's Encryptからドメインの期限切れ警告などを送ってくるメールアドレス。既に登録済みなら不要
--manual-public-ip-logging-ok IPアドレスを記録することにあらかじめ同意する指定。既に登録済みなら不要
--agree-tos 利用規約にあらかじめ同意する指定。既に登録済みなら不要
--no-eff-email EFF財団からの連絡にメールアドレスの利用を許可しない指定。許可するなら--eff-email。既に登録済みなら不要

実行すると、

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator dns-sakuracloud, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for example.com
dns-01 challenge for example.com
Starting new HTTPS connection (1): secure.sakura.ad.jp
Starting new HTTPS connection (1): secure.sakura.ad.jp
Starting new HTTPS connection (1): secure.sakura.ad.jp
Starting new HTTPS connection (1): secure.sakura.ad.jp
Starting new HTTPS connection (1): secure.sakura.ad.jp
Starting new HTTPS connection (1): secure.sakura.ad.jp
Waiting 90 seconds for DNS changes to propagate
Waiting for verification...
Cleaning up challenges
Starting new HTTPS connection (1): secure.sakura.ad.jp
Starting new HTTPS connection (1): secure.sakura.ad.jp
Starting new HTTPS connection (1): secure.sakura.ad.jp
Starting new HTTPS connection (1): secure.sakura.ad.jp
Starting new HTTPS connection (1): secure.sakura.ad.jp
Starting new HTTPS connection (1): secure.sakura.ad.jp
Resetting dropped connection: acme-v02.api.letsencrypt.org

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.com/privkey.pem
   Your cert will expire on 2019-07-16. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

という感じで、すべて自動的に実行されて、証明書が作成されます。

資格情報を使ってDNSにワンタイムのトークンを書き込んで、それをチェックして認証する仕組みです。直後にDNSを読み出すと書き込んだ内容が取得できなかったりするので、書き込んでから90秒ほど待ち時間を挿入しています。うまく読めたらお掃除して、接続を切って終了です。

Congratulations!というメッセージが出ていれば成功です。

なお、ここで指定したオプション類は、次回更新する時の為に/etc/letsencrypt/renewal/example.com.confに保存されます。

その他にも色々と情報がでていて、fullchain.pemprivkey.pemをここに保存したからね! といってそれぞれのフルパスが記載されています。nginxの設定に書いたりするヤツです。証明書の期限も示されています。また、更新するときはcertbot renewだよ!とも書いてあります。気に入った? 寄付はこちらで受け付けてるよ!とも書いてあります。(日本人、英語なんもわからん、といって読み流しますねw)