さくらのクラウドでの Let's Encrypt 証明書の取得と自動更新について

## 概要
さくらのクラウドには、[スタートアップスクリプト](https://manual.sakura.ad.jp/cloud/startup-script/index.html)という機能があります。  
サーバ作成時に指定すると、サーバ内での構築作業を自動化することが可能です。  
このパブリックスクリプトは GitHub にて[公開](https://github.com/sakura-internet/cloud-startupscripts)されているようです。  
今回「[Let's Encrypt](https://github.com/sakura-internet/cloud-startupscripts/blob/master/publicscript/letsencrypt/letsencrypt.sh)」を使いたかったのですが、残念ながら「※CentOS7系のみで動作します。」とのことでした。  
そこで MiracleLinux/CentOS Stream/AlmaLinux/RockyLinux の 8.X系で動作するように変更してみたので、ご紹介します。

## 前提条件
元の仕様と変わりませんので、事前作業として以下の2つが必要となります。

* さくらのクラウドDNSにゾーン登録を完了していること
* さくらのクラウドAPIのアクセストークンを取得していること

## 変更点
修正した部分については、こちらを参照ください。

```diff
3c3
< # @sacloud-name "Let's Encrypt for 8 series OS"
---
> # @sacloud-name "Let's Encrypt"
8c8
< # (MiracleLinux/CentOS Stream/AlmaLinux/RockyLinux の 8.X系でのみ動作します)
---
> # (CentOS7.X でのみ動作します)
14,17c14
< # @sacloud-require-archive distro-miracle distro-ver-8*
< # @sacloud-require-archive distro-centos distro-ver-8*
< # @sacloud-require-archive distro-alma distro-ver-8*
< # @sacloud-require-archive distro-rocky distro-ver-8*
---
> # @sacloud-require-archive distro-centos distro-ver-7
45,51d41
< #-- 8系の OS は通信が可能になるまで少し時間がかかる
< if [ $(grep -c "release 8" /etc/redhat-release) -eq 1 ] ;then
<       sleep 30
< else
<       exit 0
< fi
<
53c43
< curl -fsSL https://github.com/sacloud/usacloud/releases/latest/download/install.sh | bash
---
> curl -fsSL http://releases.usacloud.jp/usacloud/repos/setup-yum.sh | sh
76c66
< #cat > domain.list @@@ADDR@@@
---
> cat > domain.list @@@ADDR@@@
83c73
< yum install -y certbot python3-certbot-dns-sakuracloud expect
---
> yum install -y certbot certbot-dns-sakuracloud expect
```

* 最初に sleep を入れているのは、そうしないと名前解決ができずに処理が止まるためです。

* usacloud の[インストール方法](https://docs.usacloud.jp/usacloud/installation/start_guide/)が変更になっています。

* `domain.list` 部分は何か処理をしているように見えなかったのでコメントアウトしました。

* `certbot-dns-sakuracloud` というパッケージは無いため、 `python3-certbot-dns-sakuracloud` をインストールしています。
	* これが正しいかはわかっていません。certbot 含め、snapd利用やソースインストールなどの情報もあるようなので、それらと比較してご検討ください。
		* 私が試した MiracleLinux8.X の環境では、どうやっても snapd インストールがエラーになったので、あきらめました。

## スクリプト全体

```shell
#!/bin/bash
#
# @sacloud-name "Let's Encrypt for 8 series OS"
# @sacloud-once
# @sacloud-desc-begin
# このスクリプトは usacloud, certbot-auto をインストールし、Let's Encryptで "指定ドメイン" と "*.指定ドメイン" のTLS証明書を取得します
# CAA レコードを登録する場合は、 issue と issuewild タグを登録します。
# (MiracleLinux/CentOS Stream/AlmaLinux/RockyLinux の 8.X系でのみ動作します)
#
# 事前作業として以下の2つが必要となります
# ・さくらのクラウドDNSにゾーン登録を完了していること
# ・さくらのクラウドAPIのアクセストークンを取得していること
# @sacloud-desc-end
# @sacloud-require-archive distro-miracle distro-ver-8*
# @sacloud-require-archive distro-centos distro-ver-8*
# @sacloud-require-archive distro-alma distro-ver-8*
# @sacloud-require-archive distro-rocky distro-ver-8*
# @sacloud-text required DOMAIN "さくらのクラウドDNSで管理しているDNSゾーン" ex="example.com"
# @sacloud-text required MAILADDR "Let's Encryptから連絡を受信するメールアドレス" ex="sakura@example.com"
# @sacloud-checkbox default= CAA "CAAレコードを登録する"
# @sacloud-apikey required permission=create AK "APIキー"

_motd() {
	LOG=$(ls /root/.sacloud-api/notes/*log)
	case $1 in
		start)
			echo -e "\n#-- Startup-script is \\033[0;32mrunning\\033[0;39m. --#\n\nPlease check the log file: ${LOG}\n" > /etc/motd
		;;
		fail)
			echo -e "\n#-- Startup-script \\033[0;31mfailed\\033[0;39m. --#\n\nPlease check the log file: ${LOG}\n" > /etc/motd
			exit 1
		;;
		end)
			cp -f /dev/null /etc/motd
		;;
	esac
}

set -ex

#-- スタートアップスクリプト開始
_motd start
trap '_motd fail' ERR

#-- 8系の OS は通信が可能になるまで少し時間がかかる
if [ $(grep -c "release 8" /etc/redhat-release) -eq 1 ] ;then
	sleep 30
else
	exit 0
fi

#-- usacloud のインストール
curl -fsSL https://github.com/sacloud/usacloud/releases/latest/download/install.sh | bash
zone=$(dmidecode -t system | awk '/Family/{print $NF}')

set +x

#-- usacloud の設定
usacloud config --token ${SACLOUD_APIKEY_ACCESS_TOKEN}
usacloud config --secret ${SACLOUD_APIKEY_ACCESS_TOKEN_SECRET}
usacloud config --zone ${zone}

#-- certbot で使用する token と secret の設定
cat <<_EOL_> ~/.sakura
dns_sakuracloud_api_token = "${SACLOUD_APIKEY_ACCESS_TOKEN}"
dns_sakuracloud_api_secret = "${SACLOUD_APIKEY_ACCESS_TOKEN_SECRET}"
_EOL_
chmod 600 ~/.sakura

set -x

#-- 変数のセット
domain="@@@DOMAIN@@@"
mail_addr="@@@MAILADDR@@@"
caa_flag=@@@CAA@@@
#cat > domain.list @@@ADDR@@@

if [ -z ${caa_flag} ]; then
	caa_flag="0"
fi

#-- certbot のインストール
yum install -y certbot python3-certbot-dns-sakuracloud expect

#-- 証明書のインストール
expect -c "
set timeout 180
spawn certbot certonly --dns-sakuracloud --dns-sakuracloud-credentials /root/.sakura --dns-sakuracloud-propagation-seconds 90 -d *.${domain} -d ${domain} -m ${mail_addr} --manual-public-ip-logging-ok --agree-tos
expect \"(Y)es/(N)o:\"
send -- \"Y\n\"
expect \"Congratulations\"
"

#-- 証明書が取得できたか確認
ls -l /etc/letsencrypt/live/${domain}/fullchain.pem

#-- cron に証明書の更新処理を設定
echo "$((${RANDOM}%60)) $((${RANDOM}%24)) * * $((${RANDOM}%7)) root certbot renew " >> /etc/cron.d/update-sacloud-certbot

#-- CAA レコードの登録
if [ ${caa_flag} -ne 0 ]
then
	usacloud dns record-add -y --name @ --type CAA --value '0 issue "letsencrypt.org"' ${domain}
	usacloud dns record-add -y --name @ --type CAA --value '0 issuewild "letsencrypt.org"' ${domain}
fi

_motd end

exit 0
```

## その後の流れのサンプル
スクリプト利用後は、証明書が自動的に更新される状態にはなっていますが、それだけです。  
実際の利用時は、その用途に合わせて反映などの作業も必要です。  
参考程度ですが、WEBサーバ(apache)での利用を想定した場合は以下あたりの作業が必要になると思います。

```Console
## apacheインストール
# dnf install -y httpd mod_ssl

## 作成した証明書、鍵ファイルを指定
# cat /etc/httpd/conf.d/ssl.conf | grep ドメイン名
SSLCertificateFile /etc/letsencrypt/live/ドメイン名/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/ドメイン名/privkey.pem

## httpd 有効化と起動
# systemctl enable httpd
# systemctl start httpd

## 必要に応じて firewalld 無効化
# systemctl disable firewalld
# systemctl stop firewalld

## 作成される cron設定に httpd への反映コマンドを追加
# cat /etc/cron.d/update-sacloud-certbot
XX XX * * XX root certbot renew --post-hook "systemctl reload httpd"
```

## 備考
* 動作は確認済みではありますが、修正内容が正しいことは保証しませんので、あくまでも一例とお考えください。
* DNS が route53 にあるといった場合は、 `python3-certbot-dns-route53` をインストールし、AWS の認証情報を用意するなど、手順を AWS用に修正すればよいものと思います。
* DNS認証では無く `.well-know/acme-challenge/` を利用する場合はそのように修正することもできるものと思います。
* 更新が問題無く行われるか気になる場合は、[証明書の有効期限監視](https://manual.sakura.ad.jp/cloud/appliance/simplemonitor/index.html#ssl)を実施するとよさそうです。
* 作成済みのサーバ内で実行する場合は、適宜変数や処理内容を修正するか、内容を参考にコマンドで実行してもよいと思われます。

## 最後に
[エンハンスドロードバランサ](https://manual.sakura.ad.jp/cloud/appliance/enhanced-lb/index.html)や[ウェブアクセラレータ](https://manual.sakura.ad.jp/cloud/manual-webaccel.html)といったサービスを利用する場合は、証明書の自動インストールや更新機能がついているようです。  
WEBサーバ用途なのであれば、その方が楽かもしれませんので、あわせてご検討ください。  
どうぞよいさくらのクラウドライフを！