「Let’s Encrypt Slack」でググると、更新から通知までの一連の処理が一つのシェルスクリプトになっているゴリ押し法が出てくるので、もう少し管理を楽にする方法を模索した。
検証環境
- Ubuntu 18.04.4 LTS (Bionic Beaver)
- certbot 0.27.0-1~ubuntu18.04.1
- MatterMost 5.20.1(Slack互換アプリとして検証)
apt の Certbot
apt の certbot
パッケージには標準で crontab
と systemd-timer
のファイルが同梱されている。
$ apt-file list certbot
certbot: /etc/cron.d/certbot
certbot: /etc/letsencrypt/cli.ini
certbot: /etc/logrotate.d/certbot
certbot: /lib/systemd/system/certbot.service
certbot: /lib/systemd/system/certbot.timer
certbot: /usr/bin/certbot
certbot: /usr/bin/letsencrypt
certbot: /usr/share/doc/certbot/README.rst.gz
certbot: /usr/share/doc/certbot/changelog.Debian.gz
certbot: /usr/share/doc/certbot/copyright
certbot: /usr/share/man/man1/certbot.1.gz
certbot: /usr/share/man/man1/letsencrypt.1.gz
$ cat /etc/cron.d/certbot
# /etc/cron.d/certbot: crontab entries for the certbot package
#
# Upstream recommends attempting renewal twice a day
#
# Eventually, this will be an opportunity to validate certificates
# haven't been revoked, etc. Renewal will only occur if expiration
# is within 30 days.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(43200))' && certbot -q renew
$ cat /lib/systemd/system/certbot.service
[Unit]
Description=Certbot
Documentation=file:///usr/share/doc/python-certbot-doc/html/index.html
Documentation=https://letsencrypt.readthedocs.io/en/latest/
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot -q renew
PrivateTmp=true
$ cat /lib/systemd/system/certbot.timer
[Unit]
Description=Run certbot twice daily
[Timer]
OnCalendar=*-*-* 00,12:00:00
RandomizedDelaySec=43200
Persistent=true
[Install]
WantedBy=timers.target
したがって個別にお手製の crontab を書いたり、パッケージ同梱のスクリプトを上書きして Slack 連携させるのは管理上あまり得策とは言えない。
解決法:Certbot の deploy hook を使う
certbot
コマンドには --deploy-hook
オプションがある。
--deploy-hook DEPLOY_HOOK
Command to be run in a shell once for each
successfully issued certificate. For this command, the
shell variable $RENEWED_LINEAGE will point to the
config live subdirectory (for example,
"/etc/letsencrypt/live/example.com") containing the
new certificates and keys; the shell variable
$RENEWED_DOMAINS will contain a space-delimited list
of renewed certificate domains (for example,
"example.com www.example.com" (default: None)
要は証明書ファイルが正しく更新できた時にコマンド DEPLOY_HOOK
を実行するというもの。
ここに Slack webhook を叩く curl
コマンドや、それを記述したシェルスクリプトのパスをおけば良い。
更新されたドメイン名は環境変数 $RENEWED_DOMAINS
で与えられる(同一証明書で複数のドメインを認証した場合はスペース区切りで与えられるが、証明書が異なる場合は証明書ごとにコマンドが実行される)。
#!/bin/bash
SLACK_MESSAGE="New certificate created successfully: \`$RENEWED_DOMAINS\`"
SLACK_WEBHOOK_URL='<your_webhook_url>'
SLACK_CHANNEL='<your_slack_channel_id>'
SLACK_USERNAME="Let's Encrypt"
SLACK_ICON_URL='https://letsencrypt.org/images/le-logo-lockonly.png'
curl -s -o /dev/null -X POST --data-urlencode 'payload={"channel": "'"$SLACK_CHANNEL"'", "username": "'"$SLACK_USERNAME"'", "text": "'"$SLACK_MESSAGE"'", "icon_url": "'"$SLACK_ICON_URL"'"}' $SLACK_WEBHOOK_URL
この hook ファイルの保存先として、 /etc/letsencrypt/renewal-hooks/
というディレクトリが用意されている。
中にはそれぞれ deploy/
post/
pre/
というディレクトリがある(post
と pre
については割愛する)ため、 /etc/letsencrypt/renewal-hooks/deploy/notify_slack
として保存する。
/etc/letsencrypt/renewal-hooks/deploy/notify_slack
最後に、 certbot
パッケージには /etc/letsencrypt/cli.ini
という設定ファイルが存在する。
このファイルには certbot
コマンドのオプション名と同じ属性名を与えることで、自動的にオプションが渡せるようになるものである。
このおかげで、 パッケージ標準の crontab
や systemd-timer
ファイルに手を加えずに済む。/etc/letsencrypt/cli.ini
末尾に以下の一行を追加する(引用符で囲むと引用符もコマンドの一部として認識されてしまうので注意する)。
deploy-hook = /etc/letsencrypt/renewal-hooks/deploy/notify_slack
これで完成。
機能テスト
例えば nginx を使っている場合は以下のコマンドで強制的に証明書を更新できる。
ただし証明書更新の Rate Limit (同一ドメインは1週間に5回まで)には注意すること。
sudo certbot certonly -d <your_domain> --force-renewal --nginx
通知スクリプトだけ試したい場合は以下のコマンドで良い。
RENEWED_DOMAINS=<your_domain> /etc/letsencrypt/renewal-hooks/deploy/notify_slack