Skip to content

Instantly share code, notes, and snippets.

@debiru
Created February 17, 2022 12:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save debiru/ba74e311b8dd6fc43fb8f451d3c60969 to your computer and use it in GitHub Desktop.
Save debiru/ba74e311b8dd6fc43fb8f451d3c60969 to your computer and use it in GitHub Desktop.
tinydns を使って Let's Encrypt で DNS-01 チャレンジを自動化する方法

Let's Encrypt 証明書と tinydns の導入

certbot

sudo apt install certbot
sudo apt install python3-certbot-apache

tinydns インストール

cd /etc
sudo mkdir _tinydns
cd _tinydns

sudo apt install daemontools

sudo wget http://cr.yp.to/djbdns/djbdns-1.05.tar.gz
sudo tar xzf djbdns-1.05.tar.gz
cd djbdns-1.05/

sudo sh -c "echo 'gcc -O2 -include /usr/include/errno.h' > conf-cc"
sudo make
// warning が表示されるがエラーでなければ問題ないので続ける

sudo make setup check

ls -la /usr/local/bin/ | grep tinydns

2回目以降の make setup check

$ sudo make setup check
./install
install: fatal: unable to write .../bin/tinydns: text busy
make: *** [Makefile:782: setup] Error 111
$ ls -la /usr/local/bin/ | grep tinydns
-rwxr-xr-x  1 root root 35096 Jan 31 01:18 tinydns
-rwxr-xr-x  1 root root 22776 Feb  2 19:00 tinydns-conf
-rwxr-xr-x  1 root root 30968 Jan 31 01:18 tinydns-data
-rwxr-xr-x  1 root root 26872 Jan 31 01:18 tinydns-edit
-rwxr-xr-x  1 root root 39232 Jan 31 01:18 tinydns-get

既に /usr/local/bin/tinydns プログラム群が存在する場合 make setup check が失敗する。

コマンド実行時の出力結果(メッセージ)を確認したいなど、何らかの理由でインストールをやり直したい場合はアンインストール手順を実行してからやり直せばよい。

tinydns アンインストール

コマンド群の削除

$ ls -la /usr/local/bin/ | grep tinydns
-rwxr-xr-x  1 root root 35096 Jan 31 01:18 tinydns
-rwxr-xr-x  1 root root 22776 Feb  2 19:00 tinydns-conf
-rwxr-xr-x  1 root root 30968 Jan 31 01:18 tinydns-data
-rwxr-xr-x  1 root root 26872 Jan 31 01:18 tinydns-edit
-rwxr-xr-x  1 root root 39232 Jan 31 01:18 tinydns-get

これらを退避させる。

sudo mkdir -p ~/tinydns_backup/bin

sudo mv /usr/local/bin/tinydns* ~/tinydns_backup/bin

/etc/tinydns の削除

sudo mv /etc/tinydns ~/tinydns_backup

再作成には次のコマンドを実行する。

sudo tinydns-conf tinydns dnslog /etc/tinydns $(hostname -I | ag -o '\d+\.\d+\.\d+\.\d+')

tinydns 起動

sudo apt install svtools daemontools-run
sudo reboot
sudo useradd tinydns
sudo useradd axfrdns
sudo useradd dnslog

sudo tinydns-conf tinydns dnslog /etc/tinydns $(hostname -I | ag -o '\d+\.\d+\.\d+\.\d+')

# if /etc/service/tinydns is exist
sudo rm -r /etc/service/tinydns

sudo ln -s /etc/tinydns /etc/service
sleep 5

# check
sudo svstat /etc/service/tinydns

# sample RRs
cd /etc/service/tinydns/root
sudo emacs data
---
._acme-challenge.lavoscore.org::ns.lavoscore.org:60
'_acme-challenge.lavoscore.org:tinydns-install-succeeded:60
---
sudo make

# dig check
dig _acme-challenge.lavoscore.org txt +norec @$(hostname -I | ag -o '\d+\.\d+\.\d+\.\d+')

dig は問い合わせドメイン名が間違っていると疎通がないかのような動作となるので、ドメイン名が間違っていないかよく確認する。

Let's Encrypt 自動更新

cd /etc/ssl

sudo touch will_update_letsencrypt.sh
sudo touch update_letsencrypt.sh
sudo touch restart_ssl_services.sh
sudo touch update_letsencrypt_and_postprocess.sh
sudo touch certbot-auth-hook.sh
sudo touch certbot-cleanup-hook.sh
sudo chmod +x *.sh
  • 2回目以降は certbot renew を使うことで、期限30日前の場合のみ更新処理が実行される
  • 更新処理は certbot renew を使うことが推奨されるが、cron で更新日を明示的に指定したい場合や意図的に強制更新をしたい場合は --force-renewal オプション付きのコマンドで再発行する

/etc/crontab

  • crontab に追記する。
  • ここでは毎月1日(6時10分)に強制的に証明書を再発行したいので certbot renew を使わずに強制発行している。
# Update sslcert (Let's Encrypt)
10 6	1 * *	root	/etc/ssl/update_letsencrypt_and_postprocess.sh

will_update_letsencrypt.sh

  • 必要なタイミングで自動更新する場合はこちらを使う。
#!/bin/sh -eu

certbot renew

update_letsencrypt.sh

  • 強制的に証明書を発行したい場合はこちらを使う。
  • DOMAIN_APEX と *.DOMAIN_APEX のドメイン名を対象にしている。必要があれば -d オプションを追加して任意のドメイン名を追加する。
#!/bin/sh -eu

DOMAIN_APEX="lavoscore.org"
MAIL_ADDRESS="main.coeurl@gmail.com"

SCRIPT_DIR="/etc/ssl"
AUTH_HOOK_PATH="${SCRIPT_DIR}/certbot-auth-hook.sh"
CLEANUP_HOOK_PATH="${SCRIPT_DIR}/certbot-cleanup-hook.sh"

certbot certonly --agree-tos --manual --preferred-challenges dns-01 \
        --manual-public-ip-logging-ok --force-renewal \
        -d "*.${DOMAIN_APEX}" -d "$DOMAIN_APEX" -m "$MAIL_ADDRESS" \
        --manual-auth-hook "$AUTH_HOOK_PATH" --manual-cleanup-hook "$CLEANUP_HOOK_PATH"

restart_ssl_services.sh

  • 証明書発行後に、証明書を参照しているサービスを再起動する。
#!/bin/sh

service apache2 restart
service vsftpd restart

update_letsencrypt_and_postprocess.sh

  • cron から実行するスクリプト。
#!/bin/sh

/etc/ssl/update_letsencrypt.sh
/etc/ssl/restart_ssl_services.sh

certbot-auth-hook.sh

  • DNS-01 チャレンジの際に実行するスクリプト。update_letsencrypt.sh で指定している。
#!/bin/sh

DATA_PARENT_DIR="/etc/service/tinydns/root"
DATA_PATH="${DATA_PARENT_DIR}/data"

DOMAIN="_acme-challenge.${CERTBOT_DOMAIN}"

TXT_RECORD="'${DOMAIN}:${CERTBOT_VALIDATION}:60"

echo "${TXT_RECORD}" >> ${DATA_PATH}
make -C ${DATA_PARENT_DIR}
sleep 1

certbot-cleanup-hook.sh

  • DNS-01 チャレンジの際に実行するクリーンアップスクリプト。update_letsencrypt.sh で指定している。
#!/bin/sh

DATA_PARENT_DIR="/etc/service/tinydns/root"
DATA_PATH="${DATA_PARENT_DIR}/data"

DOMAIN="_acme-challenge.${CERTBOT_DOMAIN}"

TARGET_RECORD="'${DOMAIN}:${CERTBOT_VALIDATION}:"

sed -i.bak -e "/${TARGET_RECORD}/d" ${DATA_PATH}
make -C ${DATA_PARENT_DIR}

証明書作成 DNS-01 チャレンジ

  • 証明書を発行してみる。
cd /etc/ssl/

sudo ./update_letsencrypt_and_postprocess.sh
  • apache.conf などに書きやすいようにシンボリックリンクを作成しておく。
sudo ln -nfs /etc/letsencrypt/live/lavoscore.org/cert.pem /etc/ssl/ssl-cert.pem
sudo ln -nfs /etc/letsencrypt/live/lavoscore.org/chain.pem /etc/ssl/ssl-chain.pem
sudo ln -nfs /etc/letsencrypt/live/lavoscore.org/fullchain.pem /etc/ssl/ssl-fullchain.pem
sudo ln -nfs /etc/letsencrypt/live/lavoscore.org/privkey.pem /etc/ssl/ssl-privkey.pem

証明書作成 HTTP-01 チャレンジ

  • FQDNを対象として証明書を発行する場合は、以下のコマンドで発行できる。
sudo certbot certonly --apache -d ocsp-stapling.lavoscore.org -d ocsp-stapling-off.lavoscore.org

証明書失効

  • 次のように証明書を予め複製しておけば、失効済み証明書を(研究目的で)利用できる。
sudo mkdir /etc/ssl/ocsp-stapling
sudo cp -r /etc/letsencrypt/archive/ocsp-stapling.lavoscore.org /etc/ssl/ocsp-stapling
  • 証明書を失効させたい場合は次のコマンドを実行する。
sudo certbot revoke --cert-path /etc/letsencrypt/live/ocsp-stapling.lavoscore.org/cert.pem
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment