Edited at

acme-dnsを使ってLet's Encryptのワイルドカード証明書を更新する

API で TXT レコードを変更できない DNS を利用しているドメインの証明書を dns-01 で更新できないかと思ってやってたのでメモ

Let's Encryptのフォーラムのコメントで acme-dns が紹介されていたので

この記事の1年ぐらい前に同じことをする別の方法の記事がQiitaにすでにあったのでリンクしておく

VALUE-DOMAIN でも DNS認証がしたい! (Let's Encryptの証明書の更新の自動化)


状況とか


  • API などを用いても自動で TXT レコードを変更することができない&手動で NS レコードを設定できる DNS を利用している (eg. Google Domains DNS)

  • ワイルドカード証明書を使う

  • ネームサーバーを変えない


  • systemd-resolved などのリゾルバを動かしたまま使う


環境


  • ConoHa VPS 1GBプラン

  • Ubuntu 18.04.2 LTS


やること



  1. https://github.com/joohoi/acme-dns#installation に従ってインストール


  2. config.cfg の編集


  3. certbot の renewal pre/post hook と --manual-auth-hook を用意する


  4. 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 をしても困らない1


config.cfg


  • DNS のリゾルバと共存させるにはサーバーのグローバルIPを利用する 2


  • 更新の時に Nginx を止めるようにしているので今回はリバースプロキシは利用しないが、止めなければリバースプロキシを使うことで acme-dns で証明書を設定する必要がなくなる 3


    • ただ、常に acme-dns を動かしておかないといけない状況はあまりないと思うので好みで

    • 更新の時に Nginx を止めているとかなり長い時間ダウンタイムがある事になるので 8080 番ポートで受ける形にしている




config.cfg

[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 = "198.51.100.1:53" # グローバルip 198.51.100.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"



フックの設定

joohoi/acme-dns-certbot-joohoi とか koesie10/acme-dns-certbot-hook があるのでそれらを使えばいい

適当に /etc/letsencrypt/renewal-hooks/ にでも置いて --manual-auth-hook で指定する

renewal-hooks の pre/ post/ に acme-dns と nginx の起動停止の処理を書く


/etc/letsencrypt/renewal-hooks/pre/acme-dns-start.sh

#!/bin/sh

#systemctl stop nginx
systemctl start acme-dns


/etc/letsencrypt/renewal-hooks/post/acme-dns-finish.sh

#!/bin/sh

systemctl stop acme-dns
#systemctl start nginx
systemctl restart nginx

--pre-hook とかのオプションでも大丈夫だと思うけど、ファイルおくだけでいいのでコマンドのオプションを使う必要はないと思う


DNSサーバーの設定

acme-dns に使うドメインは NS レコードを設定できるのが前提。例えば無料で Dot TK とかのドメインが使える Freenom の DNS では NS レコードを設定できないので選択肢から外れる

それがないところは Cloudflare DNS とかに移ればいいし、移る時に TXT レコードを設定する API があるところを選べばいいので、acme-dns を使わなければいけない状況は考えにくい

Google Domains DNS のように TXT レコード変更用の API が用意されていないが手動で NS レコードや TXT レコードは設定可能という DNS を使ってることを想定する

まずは今回使うドメイン、例として auth.example.org の ネームサーバー で以下のレコードを追加する。 example.org には acme-dns のサーバーの IP を A レコードを設定

example.org A 198.51.100.1

auth.example.org NS example.org

こうすることで他のドメインで _acme-challenge.example.net CNAME <uuid>.auth.example.org としていると acme-dns のサーバーへ TXT レコードを取りに来る


取得/更新する

joohoi/acme-dns-certbot-joohoi のフックを利用すると未登録のドメインだった時に acme-dns に /register でユーザーを追加してくれるので「 curl -s -X POST https://auth.example.org/register でそれを保存して〜」といった手順を飛ばせる

koesie10/acme-dns-certbot-hook はそんな風になってはいなさそうなのでこだわりとかなければ前者を使うといい


取得

#!/bin/bash

/etc/letsencrypt/renewal-hooks/pre/acme-dns-start.sh

sudo certbot certonly --manual \
--manual-auth-hook /etc/letsencrypt/renewal-hooks/acme-dns-auth.py \
--manual-public-ip-logging-ok \
--agree-tos -m <メールアドレス> \
-d exmaple.net -d \*.example.net \
--preferred-challenges dns-01 \
--server https://acme-v2.api.letsencrypt.org/directory

/etc/letsencrypt/renewal-hooks/post/acme-dns-finish.sh


--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 に戻せる

もし不明なところ等あればコメントどうぞ





  1. symlink を /etc/systemd/system に作ると systemctl disable acme-dns した時に消えてしまうので /lib/systemd/system/usr/lib/systemd/system で管理するのが望ましいと思う 



  2. joohoi/acme-dns Issue #118 



  3. example use a reverse Nginx proxy and set up basic authentication https://community.letsencrypt.org/t/help-me-understand-acme-dns/58892/22