API で TXT レコードを変更できない DNS を利用しているドメインの証明書を dns-01 で更新できないかと思ってやってたのでメモ
Let's Encryptのフォーラムのコメントで acme-dns が紹介されていたので
この記事の1年ぐらい前に同じことをする別の方法の記事がQiitaにすでにあったのでリンクしておく
VALUE-DOMAIN でも DNS認証がしたい! (Let's Encryptの証明書の更新の自動化)
状況・条件
- DNS
- API で TXT レコードを変更できない
- NS レコードを設定できる
- ワイルドカード証明書を使う
- ネームサーバーを変えない
-
systemd-resolved
などのリゾルバを動かしたまま使う
この方法が適さない状況
acme-dns に使うドメインは NS レコードを設定できるのが前提。例えば無料で Dot TK とかのドメインが使える Freenom の DNS では NS レコードを設定できないので使うことができない。ネームサーバーの変更ができないようなレジストラはないと思うが諦めるしかない。
ネームサーバーを変更するならば Cloudflare DNS などの TXT レコードの API での変更がサポートされているようなところを最初から選べば良い。
サンプル環境
- ドメイン: example.org
- グローバル IP アドレス: 203.0.113.1
手順
- https://github.com/joohoi/acme-dns#installation に従ってインストール
-
config.cfg
の編集 -
certbot
の renewal pre/post hook と--manual-auth-hook
を用意する -
53/udp
を解放
用意
acme-dns は https化されていることが前提なので、あらかじめ証明書を取得しておく必要がある。これは TXT レコードの手動変更とかで取ればいいと思うのでこの辺とか参考にしてワイルドカード証明書を発行する
Let's Encrypt (certbot) でワイルドカード証明書できた!
systemd で管理する
$GOBIN/acme-dns
を /usr/local/bin/acme-dns
へ symlink しておくので $GOPATH/src/github.com/joohoi/acme-dns/acme-dns.service
を書き換える必要もなくなる。なので symlink で systemd の管理下へ置く
Installation では /etc/systemd/system/acme-dns.service
へ移せとあるけど、/usr/lib/systemd/system/acme-dns.service
にしておく
こうすると systemctl <enable|disable> acme-dns
をしても困らない[^systemd symlink]
config.cfg
- DNS のリゾルバと共存させるにはサーバーのグローバルIPを利用する [^dns global ip]
-
更新の時に Nginx を止めるようにしているので今回はリバースプロキシは利用しないが、止めなければリバースプロキシを使うことで acme-dns で証明書を設定する必要がなくなる [^reverse Nginx proxy]- ただ、常に acme-dns を動かしておかないといけない状況はあまりないと思うので好みで
- 更新の時に Nginx を止めているとかなり長い時間ダウンタイムがある事になるので 8080 番ポートで受ける形にしている
[general]
# DNS interface. Note that systemd-resolved may reserve port 53 on 127.0.0.53
# In this case acme-dns will error out and you will need to define the listening interface
# for example: listen = "127.0.0.1:53"
#listen = ":53"
listen = "203.0.113.1:53" # グローバルip 203.0.113.1 を設定する
[api]
# 0.0.0.0 を設定して直接公開
# Nginx などでリバースプロキシを使うなら 127.0.0.1 でもいい
ip = "0.0.0.0"
# 直接公開するので 443 番ポートを選択
# リバースプロキシを使うなら HTTP alternative の 8008 番とか 8080 番とか
#port = "443"
port = "8080" # Nginx を止めない形にしたので alternative で受ける
# すでに取得済みの証明書を使うので "cert"
# "letsencrypt" の挙動は確かめてない
# リバースプロキシ使うなら "none" で
tls = "cert"
# only used if tls = "cert"
# 既存の証明書を指定
tls_cert_privkey = "/etc/letsencrypt/live/auth.example.org/privkey.pem"
tls_cert_fullchain = "/etc/letsencrypt/live/auth.example.org/fullchain.pem"
フックの設定
renewal-hooks/{pre,post}
に acme-dns と nginx の起動停止の処理を書く
#!/bin/sh
#systemctl stop nginx
systemctl start acme-dns
#!/bin/sh
systemctl stop acme-dns
#systemctl start nginx
systemctl reload nginx # restart しなくても reload で証明書を読んでくれる
acme-dns に TXT レコードを設定するフックは --manual-auth-hook
で指定する。取得/更新する の項を参照
DNSサーバーの設定
acme-dns を置くサーバーを例えば auth.example.org
の NS レコードに設定する。 NS レコードは IP アドレスを受け付けないので適当に ns.example.org
などで acme-dns を置いたサーバーの IP アドレスを A/AAAA レコードに入れる
ns.example.org A 203.0.113.1
auth.example.org NS ns.example.org
こうすることで任意のドメインで _acme-challenge
に CNAME レコードで <uuid>.auth.example.org
とした時に acme-dns の TXT レコードを取りに来る
取得/更新する
acme-dns 用の認証スクリプトは joohoi/acme-dns-certbot-joohoi や koesie10/acme-dns-certbot-hook などがある。acme-dns-certbot-joohoi
は acme-dns に未登録のドメインだった時に自動でアカウントを作って _acme_challange.example.org. CNAME <uuid>.auth.example.org.
をプリントしてくれるので、事前に curl -sX POST https://auth.example.org/register
する手間が省ける
スクリプトを適当な場所にインストールして --manual-auth-hook
で指定する
#!/bin/bash
sudo systemctl start acme-dns
sudo certbot certonly --manual \
--manual-auth-hook /etc/letsencrypt/renewal-hooks/acme-dns-auth.py \
--manual-public-ip-logging-ok \
--agree-tos -m <メールアドレス> \
-d example.org -d \*.example.org \
--preferred-challenges dns-01 \
--server https://acme-v2.api.letsencrypt.org/directory
sudo systemctl stop acme-dns
sudo systemctl reload nginx
--force-renewal
オプションをつけて全てのドメインの更新するときのオプションを変更させる
#!/bin/bash
sudo certbot renew --force-renewal --manual \
--manual-auth-hook /etc/letsencrypt/renewal-hooks/acme-dns-auth.py \
--manual-public-ip-logging-ok
終わり
Cloudflare に DNS のためだけにネームサーバーを向けていたので、是非はともかくこれで Google Domains DNS に戻せる
もし不明なところ等あればコメントどうぞ
[^dns global ip]: joohoi/acme-dns Issue #118
[^reverse Nginx proxy]: example use a reverse Nginx proxy and set up basic authentication https://community.letsencrypt.org/t/help-me-understand-acme-dns/58892/22
[^systemd symlink]: symlink を /etc/systemd/system
に作ると systemctl disable acme-dns
した時に消えてしまうので /lib/systemd/system
や /usr/lib/systemd/system
で管理するのが望ましいと思う