Let's Encryptで複数のサブドメインに対応したワイルドカード証明書の発行
無料でSSL証明書を取得できるLet's Encryptですが、いつの間にか複数のサブドメインに対応したワイルドカードでのSSL証明書を発行できるようになっていたので、実際に取得して試してみました。
環境は CentOS 7 です。
目次
- 証明書発行の流れ
- certbotのインストール、バージョン確認
- ワイルドカード証明書発行のコマンド実行
- DNSにTXTレコード追加、DNS設定変更の反映確認
- ワイルドカード証明書発行のコマンド処理再開
- Webサーバーの設定、再起動(nginx)
- 証明書の更新
- 最後に
証明書発行の流れ
Let's Encryptでワイルドカード証明書を発行する流れは以下の通り。
- certbotのインストール
- certbotのバージョン確認
- 証明書発行のコマンド実行(キーが表示され、処理が途中で止まる)
- DNSのTXTレコードにコマンドで生成されたキーをセット
- DNSにセットしたTXTレコードが設定に反映されていることを確認
- コマンドの処理再開
- 作成されたSSL証明書をWebサーバの設定に追加
- Webサーバの再起動
- httpsでサイトにアクセス
以下、詳しい手順になります。
certbotのインストール、バージョン確認
まずは、CentOS7にEPELリポジトリを追加。
yum install epel-release
EPELリポジトリを追加したら、certbotをインストールします。
yum install certbot --enablerepo=epel
インストールが終わったらバージョンの確認。
yum list installed | grep certbot
※バージョン0.23以降がワイルドカードに対応しているようです。
ワイルドカード証明書発行のコマンド実行
以下のコマンドで複数のサブドメインに対応したワイルドカード証明書を発行します。
certbot certonly \
--manual \
-d xxx-yyy-zzz.com \
-d *.xxx-yyy-zzz.com \
-m xxx-yyy-zzz@gmail.com \
--agree-tos \
--manual-public-ip-logging-ok \
--preferred-challenges dns-01 \
--server https://acme-v02.api.letsencrypt.org/directory
-d)ルートドメインと複数のサブドメインの指定。(ワイルドカード「*」での指定だけではルートドメインが対象外になるので注意)
-m)メールアドレスの指定。(期限切れが近くなった時にメールが送られてくる)
上記のコマンドを実行する場合、ドメイン(xxx-yyy-zzz.com)を自分のものに置き換えてください。
その他のオプションについては、こちら(User Guide — Certbot)を参照。
コマンドを実行すると、ターミナルに以下の内容が出力されます。
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
Starting new HTTPS connection (1): supporters.eff.org
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for xxx-yyy-zzz.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.xxx-yyy-zzz.com with the following value:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
途中の確認では「Yes」を選択しないと先に進めませんでした。
コマンドは最後のPress Enter to Continue出力後、ずっと待機したままになるので、この状態のまま、今度は手動でDNSのTXTレコードに上記のキーをセットします。
DNSにTXTレコード追加、DNS設定変更の反映確認
DNSの管理画面にアクセスして、TXTレコードのホスト名に「_acme-challenge.xxx-yyy-zzz.com」、値に上記で出力されたキー「XXXXX...」をセットして登録します。
これについては、利用しているDNSサーバーによって方法が違うと思うので、詳しくはそちらを参照してください。
DNSの設定が終わったら、設定が反映されるまで時間がかかる場合があるようなので、実際に反映されているかどうか確認します。(開いていたターミナルはコマンド実行中なので、別のターミナルを立ち上げて実行)
まずは、bind-utilsをインストール。
yum install bind-utils
インストール後、以下のコマンドで確認。
dig -t TXT _acme-challenge.xxx-yyy-zzz.com
設定が正常に反映されていれば、DNSに設定した内容が以下のように出力されます。
;; ANSWER SECTION:
_acme-challenge.xxx-yyy-zzz.com. 3600 IN TXT "XXXXX..."
何度か試しましたが、設定が反映されるまでの時間がまちまちだったので、実際に試して確認してみてください。
ちなみに反映される前にコマンドの処理を再開すると、失敗して、最初から(コマンドの実行)やらないといけないので、確認してからの方がいいと思います。
[2019年7月1日 追記]
上記のコマンドで設定したキーがなかなか取得できない原因が分かりました。DNSのレコードを設定する際にキャッシュの時間を3600(秒指定なので1時間)で指定していたのが問題だったようです。(とくに気にせずデフォルトの値を使っていました)
ただし、Let's Encryptの証明書発行コマンドでは、最新の設定内容を参照してくれるので、DNSレコードさえきちんと設定していれば、問題なく、認証されます。
キャッシュが更新されてからでないと認証に失敗する可能性があるので、DNSレコードのキャッシュ時間は短めに設定しておくのがいいと思います。(私の場合、デフォルトは3600(秒)でしたが、60(秒)に変更しました。)
[2020年3月27日 追記]
digコマンドに「+short」を付加して実行すると、目的のレコードの内容のみ出力することが可能です。
dig -t TXT _acme-challenge.xxx-yyy-zzz.com +short
何度か証明書の更新でDNSのTXTレコードを設定してみて分かりましたが、digコマンドで取得できたレコードの内容が更新されていても、認証時に古いレコードの内容が取得されて、認証に失敗することがありました。これといった解決策はありませんが、レコードの変更確認後、数分待った後に認証処理を再開すると上手くいきます。
キャッシュではなく最新?のレコード値を確認したい場合は、以下のコマンドで確認することができます。
dig -t TXT _acme-challenge.xxx-yyy-zzz.com +trace
ワイルドカード証明書発行のコマンド処理再開
DNSの設定後、止まっていた証明書発行コマンドを再開します。(なにかしらのキーを押せば処理が再開する)
無事に認証できた場合、以下の内容が画面に出力されます。
Waiting for verification...
Resetting dropped connection: acme-v02.api.letsencrypt.org
Resetting dropped connection: acme-v02.api.letsencrypt.org
Cleaning up challenges
Resetting dropped connection: acme-v02.api.letsencrypt.org
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/xxx-yyy-zzz.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/xxx-yyy-zzz.com/privkey.pem
Your cert will expire on 2019-06-18. 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
パっと見は分かり難いですが、「IMPORTANT NOTES」にCongratulations!と出力されているので、証明書の発行に成功したことが分かります。
また、上記の中で重要なのは、期限が掲載されている点です。Let's Encryptの証明書の有効期間は90日間なので、上の場合、「2019-06-18」までが証明書が有効な日付になります。
Webサーバーの設定、再起動(nginx)
続いて、Webサーバーに作成された証明書をセットします。
今回はnginxの場合の例。
server {
listen 443 ssl
ssl_certificate /etc/letsencrypt/live/xxx-yyy-zzz.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/xxx-yyy-zzz.com/privkey.pem;
}
設定したらWebサーバーを再起動します。
nginx -s reload
最後にhttpsでURLにアクセスしてサイトが表示されれば完了です。
証明書の更新
さて、証明書の更新についてですが、できれば自動更新で証明書を更新したいところ。
ですが、どうやらワイルドカード証明書の場合、DNSの設定をいじって認証しなければいけないため、DNSの変更が可能なAPIが提供されているサービスでしか自動更新ができないようです。
そういったAPIが提供されていることの方が少ないようなので、普通は手動で更新する感じになると思います。
なお、手動で更新する場合、以下のコマンドを実行するだけでいいみたいです。 ⇒ 追記参照
certbot renew
一度、更新の機会があったので上記のコマンドを試してみたかったのですが、その時はすっかり忘れていて、最初の証明書作成時と同じコマンドで証明書を更新したため未確認です。
ちなみに期限切れが近づくと以下のような内容のメールが、証明書作成時に指定したメールアドレスに届きます。
Your certificate (or certificates) for the names listed below will expire in 19 days (on 03 Apr 18 02:00 +0000). Please make sure to renew your certificate before then, or visitors to your website will encounter errors.
We recommend renewing certificates automatically when they have a third of their
total lifetime left. For Let's Encrypt's current 90-day certificates, that means
renewing 30 days before expiration. See
https://letsencrypt.org/docs/integration-guide/ for details.
30日前から更新可能なので、忘れずに更新しておきましょう。
[2019年7月1日 追記]
コマンド「certbot renew」ですが、どうやらDNSのAPIを利用した自動更新用の実行用コマンドだったようで、その設定をしていない私の環境で実行したらエラーが出て証明書の更新ができませんでした。
この場合、証明書を更新するには、ここで示したワイルドカード証明書の発行コマンドをもう一度実行する必要があります。(手順はまったく同じなので、慣れてしまえばそこまで苦ではありません)
ちなみに私の環境で証明書を更新したにも関わらず、サイトにアクセスすると証明書の期限が切れてページが表示されない、といった事象に遭遇しましたが、これはWebサーバのNginxの設定がまずかったらしく、証明書を更新したにも関わらず、キャッシュの方に残っていた古い方の証明書が参照されてしまっていたことが原因でした。Webサーバを再起動すると正常にページが表示されるようになったので、SSL証明書を更新する時は、念のため、Webサーバを再起動するか、定期的に再起動をするように設定しておいた方がいいかもしれないですね。
[2020年3月27日 追記]
何度か証明書の更新を行って分かりましたが、時々、DNSのTXTレコードを使った確認が複数回行われることがあります。
その時は、1回目のTXTレコード確認後、続けてもう一度、同じレコード名(_acme-challenge.xxx-yyy-zzz.com)で異なる値をTXTレコードとして追加しないといけません。
2度目は以下のようなメッセージが追加で表示されます。
(This must be set up in addition to the previous challenges; do not remove, replace, or undo the previous challenge tasks yet. Note that you might beasked to create multiple distinct TXT records with the same name. This ispermitted by DNS standards.)
1度目の確認で設定したTXTレコードは削除や上書きせずにそのまま残しておき、同じレコード名で追加して認証を行うようです。
[2020年6月5日 追記]
再度、証明書を更新すると、DNSレコードの確認がまた2回必要だったので、もしかたら、コマンドに記述したドメインの個数分、認証用のTXTレコードを登録しないといけないのかもしれません。
最後に
非常に便利なワイルドカード証明書ですが、サブドメイン一つ一つの証明書を取得して自動更新するか、ワイルドカード証明書でまとめて取得して手動で更新するか、どちらがいいかはちょっと悩ましいところなので、できればワイルドカード証明書でもっと簡単に自動更新できたら嬉しいですね。