MyDNSのLet’s Encryptのワイルドカード自動更新を導入した

前回(Let’s Encrypt でSSLワイルドカード証明書を導入する)の続き?
MyDNSが公開しているPHPのscriptを導入して、renewが行えるようにした。

背景

もともとLet’s Encryptでワイルドカード証明書を導入する前はcertbot renewをcronに登録していて放置していた。
そしてDNSのときのと同じくこちらも無料でアラートメールをもらって気づいた
前回(Let’s Encrypt でSSLワイルドカード証明書を導入する)重い腰を上げて導入したワイルドカード証明書関係が更新できていないようだ
そのあたりを調査して、MyDNSの自動更新スクリプトを導入した。というお話
ちなみにアラートメールはこんな感じ

Let’s Encryptからのアラートメールはこんな感じ

JTrimでコピペしたんだけど、jpg圧縮の品質悪いっすね
Affinityもってるんだから、面倒臭がらないで、そっちでするべきだったか

現状

アラートメールを受けて、まずはcronに登録しているコマンドを実施確認
(と、その前にまずはcron確認)

# crontab -l
* * * * * /bin/certbot renew && /bin/systemctl reload nginx
→certbotはrootで動かしているが、他のユーザ管理にしたいね
→cronの時間は念の為マスク

# type certbot
certbot is hashed (/usr/bin/certbot)
# which certbot
/usr/bin/certbot
# ls /bin/certbot -l
-rwxr-xr-x 1 root root 960 Apr  7 10:01 /bin/certbot
# ls /usr/bin/certbot -l
-rwxr-xr-x 1 root root 960 Apr  7 10:01 /usr/bin/certbot
→ cronに登録しているcertbotが/binにたいして、certbotは/usr/binにあった
→ シンボリックリンクでもハードリンクでもない
# sha256sum /bin/certbot
2e92fb3a6ca39f7de974ca3e4161197cc347139da68484398e575ec817600587  /bin/certbot
# sha256sum /usr/bin/certbot
2e92fb3a6ca39f7de974ca3e4161197cc347139da68484398e575ec817600587  /usr/bin/certbot
→どっちとも同じハッシュで問題もなく動くが、/usrに変更
# crontab -e
crontab: installing new crontab
# crontab -l
* * * * * /usr/bin/certbot renew && /bin/systemctl reload nginx
→cronの時間は念の為マスク

certbot確認

# certbot renew
(抜粋)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/meto4d.pgw.jp.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert is due for renewal, auto-renewing...
Could not choose appropriate plugin: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.')
Failed to renew certificate meto4d.pgw.jp with error: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.')

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

プラグインエラーが起きているから--manual-auth-hookを使えとのこと

certbot certonly --manual --manual-auth-hook /path/to/http/authenticator.sh --manual-cleanup-hook /path/to/http/cleanup.sh -d secure.example.com

This will run the authenticator.sh script, attempt the validation, and then run the cleanup.sh script. Additionally certbot will pass relevant environment variables to these scripts:

User Guide — Certbot 1.15.0.dev0 documentation https://certbot.eff.org/docs/using.html#pre-and-post-validation-hooks

certbotはshell変数を読み取って認証を取る
--manual-auth-hookを指定することで認証前にスクリプトを実行して、shell変数に代入→--manual-cleanupで変数を削除
ということらしい
そもそもcertbotはワンタイムパスワードを取得して、_acme-challengeのTXTレコードにそのワンタイムパスワードを入力、それを認証局が確認して認証という手順
そのワンタイムパスワード関係をshell変数周りで解決するということ

どうもワイルドカードの場合はAPI先を変更しないといけない関係で、certbot renewだけではだめっぽい
手動で認証を取らないといけないっぽい
うーん、めんどうくさい…

MyDNSのLet’s Encrypt更新スクリプトを導入

ということで、MyDNSが公開していたLet’s Encrypt自動更新スクリプトを導入
スクリプトにPHPはちょっとなあと思っていたが、宗教的な感覚なので、重い腰を上げて導入
MyDNSのDomainInfoにこうある

3-2) Let’s Encryptのワンタイムパスワードについて

Let’s Encryptのサーバー証明書を取得する際に、ワンタイムキーをDNS情報のTXTレコードに書くこと、という説明がありますが、MyDNS.JPでは専用APIと、そのAPIを使うためのスクリプトをGitHUBで公開しています。 ですので、Linuxでご利用の場合にはこちらのスクリプトを導入されることをお勧めいたします。

自宅サーバーやVPSに使える無料のダイナミックDNS (Dynamic DNS) https://www.mydns.jp/members/#domaininfo

GitHUBにて専用APIを叩くPHPスクリプトが置かれている
ご丁寧に導入方法も書いてある
が、導入通りのwgetではなく、git cloneでとってくる
PHP8対応が挟まると更新が必要になるかもしれないしね

専用ディレクトリ(/root/cron/mydns)を作って、そこで作業
上でちょろっと書いたけど、root以外で作業させたいね

# php -v
PHP 8.0.3 (cli) (built: Mar  4 2021 13:26:46) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.3, Copyright (c) Zend Technologies
→PHP8がすでにarchのパッケージに配布されていた

# git clone https://github.com/disco-v8/DirectEdit.git
# ls
DirectEdit
# cd DirectEdit
# ls
README.md  txtdelete.php  txtedit.conf  txtregist.php
# chmod 700 *.php
# chmod 600 *.conf
# vim txtedit.conf
→mydnsのIDやパスワードを入力
→yourdomainはワイルドカード手前のサブドメインまで
→ *.meto4d.pgw.jpであればmeto4d.pgw.jp
# certbot certonly --manual \
--preferred-challenges=dns \
--manual-auth-hook /your/domain/directory/DirectEdit-master/txtregist.php \
--manual-cleanup-hook /your/domain/directory/DirectEdit-master/txtdelete.php \
-d meto4d.pgw.jp -d *.meto4d.pgw.jp \
--server https://acme-v02.api.letsencrypt.org/directory \
--agree-tos -m hogehoge@hoge \
--manual-public-ip-logging-ok

Use of --manual-public-ip-logging-ok is deprecated.
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Use of --manual-public-ip-logging-ok is deprecated.
Cert not yet due for renewal

You have an existing certificate that has exactly the same domains or certificate name you requested and isn't close to expiry.
(ref: /etc/letsencrypt/renewal/meto4d.pgw.jp.conf)

What would you like to do?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Keep the existing certificate for now
2: Renew & replace the certificate (may be subject to CA rate limits)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Renewing an existing certificate for meto4d.pgw.jp and *.meto4d.pgw.jp

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/meto4d.pgw.jp/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/meto4d.pgw.jp/privkey.pem
   Your certificate will expire on 2021-08-01. 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

前回(Let’s Encrypt でSSLワイルドカード証明書を導入する)で登録していたが、certbot certonlyでもrenew動作と同じように更新上書きしてくれる
この記事を書きながら実施する前に、テストで前回と同様のcertbot certonlyでTXTレコードを更新して、云々を実施していたので、証明書が更新済み
それでも更新するかしないかを聞かれている
Use of --manual-public-ip-logging-ok is deprecated.と言われているので、それは後で修正しよう

これでOK
あとはsystemctl reload nginxで読み込んでいる証明書を更新

Cron登録用のshellscriptを作る

上の更新をスクリプトに落とし込んでcronに登録してやる
コード表示用プラグインのせいなんだが、上はshellscriptで下はそれを実施したときのコマンド

#!/bin/bash
if test $# -eq 0 ; then
  INPUT=1
else
  if test $1 -eq 1 || test $1 -eq 2; then
    INPUT=$1
  else
    INPUT=1
  fi
fi

echo $INPUT | /usr/bin/certbot certonly --manual --preferred-challenges=dns --manual-auth-hook /root/cron/mydns/DirectEdit/txtregist.php --manual-cleanup-hook /root/cron/mydns/DirectEdit/txtdelete.php -d meto4d.pgw.jp -d *.meto4d.pgw.jp --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -m hogehoge@hoge
# chmod 700 certbot.mydns.sh
# certbot.mydns.sh 1
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Cert not yet due for renewal

You have an existing certificate that has exactly the same domains or certificate name you requested and isn't close to expiry.
(ref: /etc/letsencrypt/renewal/meto4d.pgw.jp.conf)

What would you like to do?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Keep the existing certificate for now
2: Renew & replace the certificate (may be subject to CA rate limits)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): Keeping the existing certificate

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Certificate not yet due for renewal; no action taken.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Saving debug log to /var/log/letsencrypt/letsencrypt.log

ちゃんと動作しているみたいだ

# crontab -l
* * * * * /root/cron/mydns/DirectEdit/certbot.renew.mydns.sh 1; /usr/bin/certbot renew && /bin/systemctl reload nginx

定期更新の時間はmaskしてるせいで毎分実施されているように見えるが実際は違う
とはいえ、範囲で指定している
certbot renewは更新なくskippedでも正常終了で終わる(ということを今知った)
→systemctl reload nginxが勝手に挟まってしまう
これはなんとかしたいね
不用意にnginxが再ロードされてしまう。

まあ、これはv6.meto4d.pgw.jpが6/30に切れるらしいので、その更新を手動で行って、証明書更新があったときの文字列を見る→grepとかで探してあれば更新にしよう
cronはコメントアウトして、もう一度アラートメールを受け取るようにして今日は終了。

余談:更新するPHPの中身

DirectEdit/txtregist.php at master · disco-v8/DirectEdit · GitHub https://github.com/disco-v8/DirectEdit/blob/master/txtregist.php

単純にcertbotからやってくる可能性のある変数を配列に入れて、MyDNSへクエリを飛ばしているだけだった
PythonとかRubyとかもう少し管理しやすいスクリプトに書き換えて、そっちで管理してもいいかもね。

 69 total views,  2 views today

Archlinuxのnetctlやらresolvconfやらの設定小話

resolv.confではない
resolvconfの設定
知らなかったこんなの

背景

うちで使っているDNSサーバはMyDNS
MyDNSさんは非常に優秀で、IPアドレスの通知が一定期間ないとアラートメールが飛んでくる。
無料でアラートメールまでくれるのはすごく嬉しい
ちなみにアラートメールはこんな感じ

MyDNSからのメール画面

このDNS更新ができていないことと、resolvconfは何が関係あるんだってことだけど、
cronに登録したperl script(register_ip.pl)でDNS更新を行っている。
このregister_ip.plでは、DNSを解決して、登録IPと現IPを比較し、違ったら登録という処理を行っている。
特にIPv6というか、AとAAAAを登録しているauto.meto4dドメインを確認したいときは、DNS Resolvのあたりの処理をしっかり行わないとできない。
そこで、登録IPを確認するためにNet::DNS::Resolverを動かして得るのだが、もともとのresolvが動いていないと失敗する。
しかもこのエラー文がNet::DNSモジュールにどうとかこうとかというエラーで、DNS Resolveができなかったというエラーを出してくれないので、数ヶ月前に苦労したことがあった。
なんかネットワークがおかしいと想いつつ、sshで他のマシンにつなげようとしたときにresolv.confがどうもおかしいと、やっと判明した。

普通(?)は/etc/resolv.confを編集
nameserverが192.168.xx.18.8.8.8
192.168.xx.1と8.8.8.8が192.168.xx.18.8.8.8とtypo
これを直して終わり
だがそうじゃなかった、

% cat /etc/resolv.conf
# Generated by resolvconf
nameserver 192.168.xx.18.8.8.8

resolvconf?で管理されているらしい
確かに、/etc/resolv.confを編集した後に再起動すると、また間違ったresolv.confが流されている
resolvconfで変更を行う必要があるらしい
そもそもresolvconfとやらを見るのは始めてだし、ちょっと調べたという雑記


resolvconfとは

いつも大変お世話になっております。
Archlinux wikiから

openresolv には resolvconf ユーティリティが入っています。これは複数の DNS 設定を管理するためのフレームワークです。詳しくは man 8 resolvconf や man 5 resolvconf.conf を見て下さい。

https://wiki.archlinux.jp/index.php/%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E5%90%8D%E5%89%8D%E8%A7%A3%E6%B1%BA#openresolv_.E3.82.92.E4.BD.BF.E3.81.86

そもそも論として、自分が体験していた不具合のように、/etc/resolv.confは影響がでかいconfファイルである。
そのため、openresolvなどで安全に変更するフレームワークとなっている

安全に変更されてへんやんか

resolvconfのconfであるresolvconf.confは/etc/resolvconf.confにある

% cat /etc/resolvconf.conf 
# Configuration for resolvconf(8)
# See resolvconf.conf(5) for details

resolv_conf=/etc/resolv.conf
# If you run a local name server, you should uncomment the below line and
# configure your subscribers configuration files below.
#name_servers=127.0.0.1

なんも設定されてねえ
テストしてみる。
resolvconfの設定を読み込んで/etc/resolv.confに適用するには# resolvconf -u

% sudo vim /etc/resolv.conf
→適当に変える
% cat /etc/resolv.conf
# Generated by resolvconf
nameserver 192.168.xx.1
nameserver 8.8.4.4

% sudo resolvconf -u
→適用させる
% cat /etc/resolv.conf
# Generated by resolvconf
nameserver 192.168.xx.18.8.8.8
→元の間違った設定に戻っている

resolvconf自体は/run/resolvconf/interface/nic0を参照してresolv.confを生成しているらしい

% cat /run/resolvconf/interfaces/eth0


nameserver 192.168.xx.18.8.8.8
→なんかわからん改行が多いが、編集する
% sudo vim /run/resolvconf/interfaces/eth0
% cat /run/resolvconf/interfaces/eth0     
nameserver 192.168.xx.1
nameserver 8.8.8.8

% cat /etc/resolv.conf
# Generated by resolvconf
nameserver 192.168.xx.18.8.8.8

% sudo resolvconf -u
% cat /etc/resolv.conf
# Generated by resolvconf
nameserver 192.168.xx.1
nameserver 8.8.8.8
→とりあえずresolvconf経由では/run/resolvconfを見ているらしい

そもそも論として/run/を編集するのはおかしい
実際、再起動すると/run/resolvconf/がリセットされていた

% cat /run/resolvconf/interfaces/eth0
nameserver 192.168.xx.1
nameserver 8.8.8.8

% sudo reboot now

% cat /run/resolvconf/interfaces/eth0
nameserver 192.168.xx.18.8.8.8

resolvconfは/run/resolvconf/を参照して/etc/resolv.confを設定しているようだが、/run/resolvconf/はどこを参照して作られているかがわからない
interfacesで管理しているようなので、nic周りで管理されているようだが、、man見ても、調べてもよくわからない

nicからということは、もしかしたらnetctlで定義したnicのDNSを参照している可能性がある

% grep -i dns /etc/netctl/eth0
DNS=('192.168.xx.1''8.8.8.8')

すっごい怪しい
調べたら正しい設定は以下のようだ

DNS=('192.168.xx.1', '8.8.8.8')
→コンマがない

特に出てこなかったが、netctl→resolvconfで/etc/resolv.confを管理している可能性がある

試しに変更してrebootしてみる

% grep -i dns /etc/netctl/eth0
DNS=('192.168.xx.1','8.8.8.8')

% sudo reboot now

% cat /etc/resolv.conf
# Generated by resolvconf
nameserver 192.168.xx.1,8.8.8.8

どうもそうみたいだ
でもnameserver 192.168.xx.1,8.8.8.8はだめ
安全に変更してくれよ

どうも単純な構文解析しかしてないようだ

% grep -i dns /etc/netctl/eth0
DNS=('192.168.xx.1','8.8.8.8')
↓
% grep -i nameserver /etc/resolv.conf
nameserver 192.168.xx.1,8.8.8.8

% grep -i dns /etc/netctl/eth0
DNS=('192.168.xx.1' '8.8.8.8')
↓
% grep -i nameserver /etc/resolv.conf
nameserver 192.168.xx.1
nameserver 8.8.8.8

なるほどなあ

まとめ

netctl のDNSは’シングルクォート’で挟んで、間にスペースが必要
間にコロン,やらが入っているとそのまま代入される
スペースがあることで始めてnameserverが分割される
resolvconfは安全に変更するフレームワーク(疎通確認はちゃんと行わない)

これでやっと再起動してもネットワーク不通問題はなくなったでしょう
たぶん

 36 total views,  1 views today