2018/06/30(土)Certbotによるワイルドカード証明書と自動更新の設定
どこよりも簡単なワイルドカード証明書設定メモ。
2018年からLet's Encryptがワイルドカード証明書に対応しました。
これを利用するためにはdns-01という、DNSのTXTレコードを使った認証が必要で、このDNS認証手順を自動化する必要があります。
DNSレジストラサービスを使用している場合を想定して、dns-01認証の方法をまとめました。
構成
- Debian Stretch
- Apache
- BIND
- 設定対象DNS : example.jp
DNSは外部サービスを使用しているものとします。外部サービスでも、CloudfireやAWS、Google Cloud DNSといった有名サービスを使っている場合、DNSサーバは不要です。検索すれば、それらの設定方法が出てきます。
サブドメイン権限の移譲
example.jpを管理しているDNSサーバに対し、_acme-challenge というサブドメインを設定し、bindを動かしている(動かす)サーバに権限を移譲します。
_acme-challenge IN NS acme-ns.example.jp. acme-ns IN A 203.0.113.11
外部サービスの場合、書き方が異なる場合がありますが、IPを指定して権限を移譲してください。この設定により、別に用意したDNSサーバで、TXTレコードを適切に設定すれば、dns-01認証が通るようになります。
CNAMEで処理する方法もあるのですが、その場合、CNAMEしたドメインに対し _acme-challenge.alias.dom を認証するのでややこしくなります。*1
_acme-challenge IN CNAME acme-c.example.jp. --> *.example.jp の認証: _acme-challenge.acme-c.example.jp.
ネームサーバを設定
bindをnsupdateによるDDNS構成(RFC2136)に対応させるため、BINDを設定します。入れてない場合はインストール。
apt install bind9 dnsutils
※dnsutilsはnsupdateに必要です。
/etc/bind/name.conf.local
# /etc/bind/name.conf.local zone "_acme-challenge.example.jp" { type master; file "/etc/bind/master/_acme-challenge.example.jp"; allow-update { 127.0.0.1; ::1; }; check-names ignore; };
ドメイン名に"_"(アンダースコア)を含むため「check-names ignore」は必須です。
/etc/bind/master/_acme-challenge.example.jp
# /etc/bind/master/_acme-challenge.example.jp $TTL 60 @ IN SOA acme-ns.example.jp. root.example.jp. ( 1 ; serial 86400 ; refresh (1 day) 3600 ; retry (1 hour) 86400 ; expire (1 day) 60 ; minimum (1 minute) ) NS acme-ns.example.jp.
SOAレコードを以下のように書くと失敗します。
@ IN SOA ns._acme-challenge.example.jp. root.example.jp. (
アンダースコアを含む名前を master-name に書くことはbindではご法度のようで、例え「check-names ignore;」してログにエラーなく正常に読み込まれたと出てもテストするとこのゾーンが動作しません。ハマります、ご注意ください。
bindの再起動(起動)
設定にエラーがないか確認してから、bindを再起動します。
cd /etc/bind named-checkconf named-checkzone _acme-challenge.example.jp master/_acme-challenge.example.jp service bind9 restart
TXTレコードを更新できるか確認しておきます。「-l」を忘れずに。
nsupdate -l > add _acme-challenge.example.jp 60 TXT "test" > send > quit dig TXT _acme-challenge.example.jp
certbotの導入
apt install certbot
ワイルドカード証明書の自動アップデートを実現するため、2つほどスクリプトを導入します。内容をコピペしてください。
/etc/letsencrypt/renewal-hooks/dns-01-auth.sh
#!/bin/sh # dns-01 is VALIDATION set, TOKEN not set [ "$CERTBOT_VALIDATION" = "" ] && exit 0 [ "$CERTBOT_TOKEN" != "" ] && exit 0 echo "delete _acme-challenge.$CERTBOT_DOMAIN TXT\n"\ "add _acme-challenge.$CERTBOT_DOMAIN 10 IN TXT \"$CERTBOT_VALIDATION\"\n" | nsupdate -l
/etc/letsencrypt/renewal-hooks/dns-01-clean.sh
#!/bin/sh [ "$CERTBOT_VALIDATION" = "" ] && exit 0 [ "$CERTBOT_TOKEN" != "" ] && exit 0 echo "delete _acme-challenge.$CERTBOT_DOMAIN TXT\n" | nsupdate -l
2つとも実行属性を付けておきます。
cd /etc/letsencrypt/renewal-hooks chmod +x dns-01-auth.sh chmod +x dns-01-clean.sh
ワイルドカード証明書の取得
ここまでで、ワイルドカード証明書を取得する準備が整いました。あとは以下のコマンドを実行するだけです。
certbot certonly -d example.jp -d *.example.jp -m your@example.com \ --preferred-challenges dns-01 \ --server https://acme-v02.api.letsencrypt.org/directory \ --manual \ --manual-auth-hook /etc/letsencrypt/renewal-hooks/dns-01-auth.sh \ --manual-cleanup-hook /etc/letsencrypt/renewal-hooks/dns-01-clean.sh
少し長いですが確実に入力してください。
IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/example.jp/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/example.jp/privkey.pem Your cert will expire on 2018-00-00. 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"
こんな感じで表示されれば成功です。
今の設定は /etc/letsencrypt/renew/example.jp に保存されていますので、自動的に更新されます。
一応、更新のテストをしておきます。
certbot renew --force-renewal --dry-run
「--dry-run」を付けないと実際に更新されますので注意してください。
Apacheへの組み込み
証明書を設定します。nginxでも何でも構いませんが、Apacheの設定例。
<VirtualHost *:443> DocumentRoot /var/www/example.jp ServerName example.jp ServerAlias *.example.jp SSLEngine on SSLCertificateKeyFile /etc/letsencrypt/live/example.jp/privkey.pem SSLCertificateFile /etc/letsencrypt/live/example.jp/fullchain.pem </VirtualHost>
Apacheを自動再起動させる
/etc/letsencrypt/renewal-hooks/post 以下にスクリプトファイルを置くと、更新時に実行されます(非更新時には実行されません)。
deploy/ に置くと複数のドメインを更新した場合複数回実行されるので、post/ に置いてください。
/etc/letsencrypt/renewal-hooks/post/apache2
#!/bin/sh service apache2 reload
※実行属性を忘れずに付けてね。
動作確認。
certbot renew --dry-run
その他
起動タイミングの変更
オリジナルファイルは /lib/systemd/system/certbot.timer にあるので内容をコピーして書き換えます。
systemctl edit certbot.timer
OnCalenderの設定はsystemd.timeのマニュアル参照。
cronについて
/etc/cron.d/certbot にもリニューアル設定が残っていますが、systemd環境ではこのファイルは使われていません。よって修正は不要です。
cron.d/certbot:0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew
紛らわしていので削除しておきたいのですが、certbotを更新するたびにファイルを作成されるので、放置しておくのが良いでしょう……。