MyDNSでLet’s Encryptのワイルドカード証明書を自動更新する
最近TLS(SSL)必須のAPIやライブラリが多いですよね。自宅サーバーにテスト環境を構築してサブドメインでアクセスするのにいちいち証明書作ってらんないので、ワイルドカード証明書にしたかったんです。
HTTP-01とDNS-01
まず、TLS証明書を取得するにはドメインの所有権を確認する必要があります。
HTTP-01とは、HTTPサーバーのにACMEクライアントが発行したトークンを設置、それをLet's Encryptが外部からアクセスしてトークンを検証することで、ドメインの所有者を確認する方法です。
Let's Encryptの設定方法を調べたら出てくる記事のほとんどはこの方法を利用しており、僕が当ブログで公開しているWordpress設定方法の記事でもこのやり方を書いてます。
HTTP-01はHTTPサーバーに所定のファイルを設置する(もしくはcerbotの検証用サーバーを使用する)だけで検証可能であり、つまりは手元のサーバーをいじるだけで設定できるのでとても簡単です。
ですが、この方法ではサブドメインの所有権までは確認できないので、ワイルドカード証明書は発行できません。
そこで使用するのがDNS-01です。
DNS-01ではACMEクライアントが発行したトークンをDNSのTXTレコードに設置します。
DNSはドメインツリーと呼ばれる階層構造になっているため、1つのドメインの所有権が確認できればそのサブドメインの所有権も同じく確認できるわけです。
ただし、DNSのTXTレコードが存在するのは手元のサーバーではなく、名前解決を行っているネームサーバーなので、certbotで証明書を取得する度にネームサーバーにトークンを設定する必要があります。
MyDNSのLet's Encrypt用API
DNSのTXTレコードをマニュアルでしか設定できないネームサーバーだと、証明書更新を毎回マニュアルで行わなければいけなくてとっても面倒なのですが、MyDNSではDNS-01での証明書取得を自動化できるようにAPIを提供してくれています。
These are scripts for users of MyDNS.JP and are necessary to obtain server certificates with Let's Encrypt's DNS-01. - disco-v8/DirectEdit
これを使えば簡単にワイルドカード証明書の取得を自動化できる・・・のですが複数のMyDNSアカウントを扱えないのと、PHPってのがどうも気に入らなかったのでPythonで書き換えました。
import urllib.parse
import urllib.request
import base64
import sys
import os
def mydns_register_validation(master_id, password, domain, validation, cmd = "REGIST"):
url = "https://www.mydns.jp/directedit.html"
authorization = master_id + ":" + password
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Basic " + base64.b64encode(authorization.encode()).decode("utf-8")
}
data = {
"EDIT_CMD": cmd,
"CERTBOT_DOMAIN": domain,
"CERTBOT_VALIDATION": validation
}
request = urllib.request.Request(url, headers=headers, data=urllib.parse.urlencode(data).encode(), method="POST")
try: urllib.request.urlopen(request)
except urllib.error.HTTPError as e:
print(e.code)
print(e.read())
使い方
Pythonスクリプトの用意
GitHub Gist: instantly share code, notes, and snippets.
ここからmydns_register.py
をダウンロードして、ファイルの末尾にあるmydns_register_validation
関数呼び出しのMyDNS Master IDとパスワードを書き換えてください。
Pythonスクリプトの配置
スクリプトを配置する場所はrootアカウントから実行できればどこでもいいです。
僕はMyDNSのLet's Encript用APIの使い方に従って、証明書が保管されているドメインのディレクトリに配置しました。/etc/letsencrypt/live/example.com
のような場所です。
所有者とグループはroot、パーミッションは700がいいです。
証明書の取得
まずはちゃんと動作するか--dry-runで確認します。
sudo certbot certonly \
--dry-run \
--manual \
--agree-tos \
--no-eff-email \
--manual-public-ip-logging-ok \
--preferred-challenges dns-01 \
--server https://acme-v02.api.letsencrypt.org/directory \
--domain example.com \
--domain *.example.com \
--email [email protected] \
--manual-auth-hook "/etc/letsencrypt/live/example.com/mydns_register.py" \
--manual-cleanup-hook "/etc/letsencrypt/live/example.com/mydns_register.py DELETE"
ドメインとメールアドレス、pythonスクリプトのパスは自分のものに書き換えてくださいね。
成功したら本番で、--dry-runを抜いて実行してください。
自動更新
環境にもよりますが、大体は証明書を取得するのにcertbotを実行した時にsystemdのcertbot-renew.timerが有効化されているはず。
systemctl list-timers
上記のコマンドでsystemdのタイマー一覧を確認できるので、certbot-renew.timerがスケジューリングされているか確認してください。
もし有効化されていないなら
sudo systemctl enable --now certbot-renew.timer
で有効化できます。
あとは更新時にhttpサーバーが証明書を再読み込みするように、/etc/letsencrypt/renewal-hooks/deploy
以下にNginxやApacheをreloadするスクリプトを用意しておくといいでしょう。
#!/bin/bash
systemctl reload nginx
#!/bin/bash
systemctl reload httpd
実行権限をつけるのを忘れないでくださいね。
まとめ
MyDNSのAPIが扱いやすく、また反映も速いため思った以上に簡単にできました。
これでテスト環境用にサブドメインを作りまくれます。
コメント