こんにちは、サービスシステム運用課の上曽山です。
Let's Encryptのサーバー証明書は、無料であることの他に発行/更新のプロセスが自動化されていることで知られています。ワイルドカード証明書も用意されており便利に使えます。
このワイルドカード証明書ですが、Let's Encryptではドメイン所有権認証をDNSで行う方法でしか発行出来ません。
そして、DNS認証で証明書を発行するためには、DNSサーバーに指定されたTXTレコードを設定する必要があり、完全自動化するにはひと工夫必要です。
今回はcertbotのプラグインを使ってDNS認証を自動化する方法を確認してみます。
検証環境
今回の検証は以下の環境で行っています。
DNSサーバーとWEBサーバーは最低限の設定が終わっている前提で話を進めますのでご了承ください。
| 用途 | 名前 | バージョン |
|---|---|---|
| OS | Rocky Linux | 9.6 |
| DNSサーバー | Bind | 9.16.23 |
| WEBサーバー | Httpd | 2.4.62 |
| ACMEクライアント | Certbot | 3.1.0 |
DNS認証を自動化するために
最初に書いた通りLet's EncryptのDNS認証は、DNSサーバーに指定されたTXTレコードを設定して認証を行います。
DNSプロバイダーによっては設定用のAPIが用意されている場合もありますし、がんばれば自作スクリプトで処理することも出来ますが、今回利用するACMEクライアントのcertbotには便利なプラグインが用意されているので、これを使って自動化します。
利用するプラグインはdns-rfc2136。
RFC2136に準拠したダイナミックDNSと連携させるためのプラグインになります。
certbot-dns-rfc2136.readthedocs.io
ダイナミックDNSの設定
certbotに触れる前にダイナミックDNSの設定を行います。
本記事内ではexample.jpドメインを使った例を記載します。
- 認証用サブドメインの委任
ACMEでDNS認証に使うサブドメインは_acme-challenge.<ドメイン名>です。
ダイナミックDNS(ddns.example.jp)と権威DNS(ns.example.jp)は別々のサーバーであるとします。
ACMEからの認証リクエストをダイナミックDNSに委任するため、ゾーンファイルにNSレコードを追加します。
また、example.jpのすべてのサブドメインが同じIPアドレスにアクセスするよう設定します。
example.jpのゾーンファイル
$ORIGIN example.jp.
$TTL 3600 ; 1 hour
@ IN SOA ns.example.jp. admin.example.jp. (
1970010101 ; serial
3600 ; refresh (1 hour)
900 ; retry (15 minutes)
3600000 ; expire (5 weeks 6 days 16 hours)
3600 ; minimum (1 hour)
)
IN NS ns.example.jp.
IN A AAA.BBB.CCC.DDD
ns IN A AAA.BBB.CCC.EEE
_acme-challenge IN NS ddns.example.jp.
ddns IN A WWW.XXX.YYY.ZZZ
* IN A AAA.BBB.CCC.DDD
- TSIG鍵作成
ダイナミックDNSで使うTSIG鍵を作成します。
共通鍵作成に使用するのはbind-utilsに含まれているddns-confgenというツールです。
使い勝手が良くなるので実行結果はファイルに書き込んでしまいましょう。
# ddns-confgen -q -k certbot. -a sha512 | tee /var/named/dynamic/certbot.key
key "certbot." {
algorithm hmac-sha512;
secret "dummydummydummydummydummydummydummy==";
};
| コマンドオプション補足 | |
|---|---|
| -q | 余計なコメントを省き鍵情報だけを出力する |
| -k | keynameの指定 |
| -a | 暗号化アルゴリズムの指定 |
| HMACしか使えないのでハッシュ関数の指定だけで良い | |
ファイルを作成したらnamedが読み取れるようファイルオーナーを変更します。
# chown named. /var/named/dynamic/certbot.key
- BIND(named.conf)の設定
named.confに先ほど作成した共通鍵をBINDに読み込ませる設定を追加します。
include "/var/named/dynamic/certbot.key";
続いて_acme-challenge.example.jpのゾーン設定です。
認証リクエスト時のTXTレコードだけ更新出来るよう、update-policyを設定します。
zone "_acme-challenge.example.jp" {
type master;
file "dynamic/_acme-challenge.example.jp.zone";
update-policy {
grant certbot. name _acme-challenge.example.jp. TXT;
};
};
- ゾーンファイル作成
最後に_acme-challenge.example.jpのゾーンファイルを作成します。
_acme-challenge.example.jpのゾーンファイル
$ORIGIN _acme-challenge.example.jp.
$TTL 3600 ; 1 hour
@ IN SOA ns.example.jp. admin.example.jp. (
1970010101 ; serial
3600 ; refresh (1 hour)
900 ; retry (15 minutes)
3600000 ; expire (5 weeks 6 days 16 hours)
3600 ; minimum (1 hour)
)
IN NS ddns.example.jp.
ゾーンファイルも忘れずにファイルオーナーを変更してください。
# chown named. /var/named/dynamic/_acme-challenge.example.jp.zone
一通り設定が終わったらnamedを再起動します。
# systemctl restart named-chroot.service
certbotのインストール
それでは証明書発行の準備に取り掛かります。
WEBサーバーに移動して、certbotをインストールするためEPELリポジトリを追加します。
# dnf config-manager --enable crb # dnf install -y epel-release
リポジトリを追加したらcertbot、ダイナミックDNSと連携するためのプラグインcertbot-dns-rfc2136をインストールします。
# dnf install -y certbot python3-certbot-dns-rfc2136
certbot-dns-rfc2136の使い方
- TSIG鍵情報の確認
設定のためにTSIG鍵の情報が必要になるため改めて内容を確認しましょう。
TSIG鍵の内容
key "certbot." {
algorithm hmac-sha512;
secret "dummydummydummydummydummydummydummy==";
};
- 資格情報作成
TSIG鍵の内容を元にダイナミックDNSの資格情報を作成します。
マニュアルページにテンプレートがあるのでコピペして使いましょう。
ファイルは共通鍵の情報を含むため、念を入れて隠しディレクトリに保存するようにします。
# mkdir /etc/letsencrypt/.secrets/ # vi /etc/letsencrypt/.secrets/rfc2136.ini
rfc2136.iniの内容
# Target DNS server (IPv4 or IPv6 address, not a hostname) dns_rfc2136_server = WWW.XXX.YYY.ZZZ # Target DNS port dns_rfc2136_port = 53 # TSIG key name dns_rfc2136_name = certbot. # TSIG key secret dns_rfc2136_secret = dummydummydummydummydummydummydummy== # TSIG key algorithm dns_rfc2136_algorithm = HMAC-SHA512 # TSIG sign SOA query (optional, default: false) dns_rfc2136_sign_query = false
| 設定内容補足 | |
|---|---|
| dns_rfc2136_server | ホスト名は使えないのでIPアドレスを設定する必要がある |
| dns_rfc2136_name | ダブルクォーテーションは不要 |
| dns_rfc2136_secret | |
| dns_rfc2136_algorithm | アルファベットは大文字にする必要がある |
| dns_rfc2136_sign_query | オプション設定なので無くても良い |
ファイルを作成したら、またまた念を入れてrootユーザーだけが読み取れるようにしましょう。
# chown -R root. /etc/letsencrypt/.secrets/ # chmod -R 400 /etc/letsencrypt/.secrets/
サーバー証明書の発行
- 証明書発行
準備が整ったのでワイルドカード証明書を発行します。
最初は--dry-runを付けて、プラグイン、ダイナミックDNSの設定に間違いが無いか確認しましょう。
今回は検証目的なので--register-unsafely-without-emailで管理者メールアドレスの登録を省略しています。
# certbot certonly \ --dry-run \ --dns-rfc2136 \ --dns-rfc2136-credentials /etc/letsencrypt/.secrets/rfc2136.ini \ --server https://acme-v02.api.letsencrypt.org/directory \ -d example.jp \ -d *.example.jp \ --agree-tos \ --register-unsafely-without-email
| コマンドオプション補足 | |
|---|---|
| --dry-run | 証明書を発行せず実行テストを行う |
| --dns-rfc2136 | 証明書発行に使うプラグインの指定 |
| --dns-rfc2136-credentials | TSIGの資格情報ファイル名 |
| --server | ACMEサーバーのURL |
| -d | サーバー証明書を取得するドメイン |
| --agree-tos | 利用規約に同意する |
| --register-unsafely-without-email | Let's Encryptにメールアドレスを登録しない |
以下、コマンド実行後に表示されるメッセージです。
Saving debug log to /var/log/letsencrypt/letsencrypt.log Simulating a certificate request for example.jp and *.example.jp Waiting 60 seconds for DNS changes to propagate (ここで60秒の待機時間が発生する) The dry run was successful.
初回発行時にはDNS情報が伝播するのを待つ時間(propagate time)が発生します。
dry runで問題が無ければ--dry-runを外してサーバー証明書を発行しましょう。
- 証明書確認
無事に証明書が発行されれば/etc/letsencrypt/live/<ドメイン名>/の下にシンボリックリンクが作成されるので確認してみましょう。
# ls -l /etc/letsencrypt/live/example.jp/ total 4 lrwxrwxrwx 1 root root 42 Nov 21 11:21 cert.pem -> ../../archive/example.jp/cert1.pem lrwxrwxrwx 1 root root 43 Nov 21 11:21 chain.pem -> ../../archive/example.jp/chain1.pem lrwxrwxrwx 1 root root 47 Nov 21 11:21 fullchain.pem -> ../../archive/example.jp/fullchain1.pem lrwxrwxrwx 1 root root 45 Nov 21 11:21 privkey.pem -> ../../archive/example.jp/privkey1.pem -rw-r--r-- 1 root root 692 Nov 21 11:21 README
- WEBサーバー設定
上記のファイル名を設定ファイルに書いてサービスを再起動すれば設定完了です。
設定ファイルの内容
<VirtualHost *:443>
ServerName example.jp
ServerAlias www1.example.jp www2.example.jp
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.jp/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.jp/privkey.pem
</VirtualHost>
httpdサービス再起動
# systemctl restart httpd.service
最後に
ダイナミックDNSさえ用意出来れば、Let's EncryptのDNS認証は難しくないことが分かりました。
サーバー証明書の有効期限短縮が予定されていることですし、ボチボチ自動更新出来る環境を整えていこうと思います。