VALUE-DOMAIN と Certbot で DNS認証 （更新も自動化したい）

　既存環境を変えずに、Let's Encrypt のワイルドカード証明書の更新を自動化したい。

　上記目的に沿った有用な情報はほぼ先人たちが書かれてますが、自分用の情報がばらけているので
簡単にまとめておく。（疑問が残るが目的は果たせたっぽい）
　自分的には80番ポートを閉じておきたい、、、というあたりが本音。

 当方の環境は以下の通りです。
　　　ネームサーバー　　VALUE-DOMAIN
　　　ウェブサーバー　　CentOS7（WebARENAのVPSクラウド）

## VALUE-DOMAINでやること
- ＤＮＳの設定しても反映に時間がかかる
- ＡＰＩがない

　以上の理由で、VALUE-DOMAINでは、必要なTXTレコードをサーバーに渡すようにしておく。
具体的にはこんな感じ。

```
www IN A XXX.XXX.XXX.XXX　（自分のサーバーアドレス）
ns _acme-challenge www.sample.jp.
```
　VALUE-DOMAIN側でやることはここまで。。

## WebARENAでやること
- ＤＮＳ用のポートを開ける

　セキュリティグループにＤＮＳ用のポート（５３番）を追加して開放。
具体的にはこんな感じ。
　アクセス元のＩＰ固定されていれば絞って置く方が良いのだけれど
[随時変更される](https://free-ssl.jp/faq/#IP)ようなので全ＩＰ向けに開放。

```
udp:53,53,ip4:0.0.0.0/0
```

　使っているインスタンスの設定も忘れずに。ちなみに８０番ポートはここで閉じてある。

## CentOS7でやること（証明書取得まで）

　必要なものを yum でインストール。結果、現時点のversionは以下の通り。

[root@ ~]# cat /etc/centos-release
CentOS Linux release 7.6.1810 (Core) 

[root@ ~]# apachectl -v
Server version: Apache/2.4.6 (CentOS)
Server built:   Apr 24 2019 13:45:48

[root@ ~]# certbot --version
certbot 0.35.1

[root@ ~]# dnsmasq -version
Dnsmasq version 2.76  Copyright (c) 2000-2016 Simon Kelley

- ネームサーバーを立てる

/etc/dnsmasq.conf を /etc/dnsmasq.conf.org にリネームしておいて
vim /etc/dnsmasq.conf

```/etc/dnsmasq.conf
port=53
no-hosts
domain-needed
bogus-priv
txt-record=_acme-challenge.sample.jp,"（ここに認証用の乱数を入れる）"
```
systemctl restart dnsmasq　で再起動したのち、外部からtxtフィールドが参照出来るか確認しておく。（例：nslookup -q=txt _acme-challenge.sample.jp ）

- certbotで証明書の作成する。

```
[root@ ~]# certbot certonly --manual -d sample.jp -d *.sample.jp \
-m webmaster@sample.jp --agree-tos --manual-public-ip-logging-ok \
--preferred-challenges dns-01

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for sample.jp

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.sample.jp with the following value:

（　ここに認証用の「使い捨ての乱数」が表示される　）

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
Waiting for verification...
Cleaning up challenges
```

　乱数が表示されたら、もう一個ターミナルを開いて（事前に開けておいた方がなお良い）使い捨ての乱数を /etc/dnsmasq.conf を所定の場所にコピペして保存したのち systemctl restart dnsmasq してからターミナルを閉じる。

　元のターミナルに戻って [enter] キーを押してあげると、、

```
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/sample.jp/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/sample.jp/privkey.pem
   Your cert will expire on 20XX-XX-XX. 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

[root@ ~]# 
```
　無事証明書が作成されました。ここまできたら各々の設定ファイルに証明書のパスを通すなどして設定を終える。（この辺の説明は、人によっていろいろ違うと思うので割愛）
私の場合、証明書を必要とするのは以下の３つなので、
　　　　systemctl restart httpd
　　　　systemctl restart postfix
　　　　systemctl restart dovecot
としたのち、ちゃんと証明書が活用されているか確認して、ひとまず終了。

## CentOS7でやること（証明書の自動更新の設定）

- certbotのスクリプトを作っておく

どのVarsionからなのか分からないが、/etc/letsencrypt/renewal-hooks/ 配下の（pre, post, deploy）のそれぞれのディレクトリに実行ファイルを保存しておくと勝手に実行されるようです。
なので、以下の３つのスクリプトを作成して実行権限を与えておく。

```/etc/letsencrypt/renewal-hooks/pre/dns01-auth.sh
#!/bin/bash
#echo $CERTBOT_VALIDATION > /tmp/CERTBOT_VALIDATION.txt ##確認用
#echo $CERTBOT_DOMAIN > /tmp/CERTBOT_DOMAIN.txt ##確認用
[ "$CERTBOT_VALIDATION" = "" ] && exit 0
[ "$CERTBOT_TOKEN"     != "" ] && exit 0
echo -e " port=53\n" \
        "no-hosts\n" \
        "domain-needed\n" \
        "bogus-priv\n" \
        "txt-record=_acme-challenge.$CERTBOT_DOMAIN,\"$CERTBOT_VALIDATION\"" \
        > /etc/dnsmasq.conf
systemctl restart dnsmasq
sleep 20s　　　# この時間は環境により要調整
```

```/etc/letsencrypt/renewal-hooks/post/dns01-clean.sh
#!/bin/bash
systemctl stop dnsmasq
```

```/etc/letsencrypt/renewal-hooks/deploy/deploy-hook.sh
#!/bin/bash
systemctl reload httpd
systemctl reload postfix
systemctl reload dovecot
```

- 　--DRY-RUN してみる

/etc/letsencrypt/renewal/sample.jp.conf の最下行に以下の２行を追加する

```
manual_cleanup_hook = /etc/letsencrypt/renewal-hooks/post/dns01-clean.sh
manual_auth_hook = /etc/letsencrypt/renewal-hooks/pre/dns01-auth.sh
```
```
[root@ ~]# certbot renew --force-renewal --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/sample.jp.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Plugins selected: Authenticator manual, Installer None
Starting new HTTPS connection (1): acme-staging-v02.api.letsencrypt.org
Running pre-hook command: /etc/letsencrypt/renewal-hooks/pre/dns01-auth.sh
Renewing an existing certificate
Dry run: skipping deploy hook command: /etc/letsencrypt/renewal-hooks/deploy/deploy-hook.sh

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/sample.jp/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/sample.jp/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Running post-hook command: /etc/letsencrypt/renewal-hooks/post/dns01-clean.sh
```
　どうやら大丈夫っぽいので、、、

- 　--force-renewal してみる

```
[root@ ~]# certbot renew --force-renewal
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/sample.jp.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Plugins selected: Authenticator manual, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Running pre-hook command: /etc/letsencrypt/renewal-hooks/pre/dns01-auth.sh
Renewing an existing certificate
Running deploy-hook command: /etc/letsencrypt/renewal-hooks/deploy/deploy-hook.sh

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/sample.jp/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

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

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/sample.jp/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Running post-hook command: /etc/letsencrypt/renewal-hooks/post/dns01-clean.sh
```

　うまく更新されました。

- 　cron に登録しておく


```
[root@ ~]# crontab -e
00 05 * * 1 certbot renew
```

　毎週月曜、朝５時に実行する例

## 残課題（というか疑問が残る）

　とりあえず目的は果たせてるようなのだが、なぜ？？という感じのままです。

疑問1. dns01-auth.sh に環境変数が渡されてない。（なぜだろう？）
疑問2. 疑問1だと乱数が渡らないはずなのに、--force-renewal すると、
　　　証明書が更新されている。（なんでだろう？）
　
　というよく分からない状態で現在運用中。
気持ち悪いけど、問題が起きるまでしばらく様子見しておくつもり。