2018/06/30(土)Certbotによるワイルドカード証明書と自動更新の設定

どこよりも簡単なワイルドカード証明書設定メモ。


2018年からLet's Encryptがワイルドカード証明書に対応しました。

しかし、これを利用するためにはdns-01という、DNSのTXTレコードを使った認証が必要で、有効期限3ヶ月を乗り越え他の証明書と同じように自動更新させるためにはこのDNS認証手順を自動化する必要があります

そもそもdns-01対応の自動設定が大変ですし、お名前.comやValue Domain等のレジストラサービスを使用していると色々と厄介です。

構成

  • 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.

*1 : 一度この方向で設定していたのですが、認証ドメインとTXTレコード設定ドメインが異なると後々わかりにくいので止めました。

ネームサーバを設定

bindをnsupdateによるDDNS構成(RFC2136)に対応させるため、BINDを設定します。入れてない場合はインストール。

apt install bind9

/etc/bind/name.conf.local

# /etc/bind/name.conf.local
zone "_acme-challenge.example.jp" {
	type master;
	file "master/_acme-challenge.example.jp";
	allow-update {
		127.0.0.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 -k ignore master/_acme-challenge.example.jp
service bind9 restart

TXTレコードを更新できるか確認しておきます。

nsupdate -l
> add _acme-challenge.example.jp 60 TXT "test"
> send
> quit
dig TXT _acme-challenge.example.jp

certbotの導入

Debian Stretchで新しい(0.22以降)のcertbotを導入するため、backports を設定します。/etc/apt/sources.list に以下の行を追加してください。

deb http://ftp.jp.debian.org/debian stretch-backports main

続いてcertbotを導入します。Stretchでは-tでターゲットを指定するのを忘れないでください(Stretchより後ならbackportsは不要になると思われます)。

apt -t stretch-backports 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>

参考

OK キャンセル 確認 その他