Ideal Reality

興味の赴くままに

MyDNSでLet’s Encryptのワイルドカード証明書を自動更新する

最近TLS(SSL)必須のAPIやライブラリが多いですよね。自宅サーバーにテスト環境を構築してサブドメインでアクセスするのにいちいち証明書作ってらんないので、ワイルドカード証明書にしたかったんです。

Contents
スポンサーリンク

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を提供してくれています。

disco-v8/DirectEdit

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スクリプトの用意

mydns_register.py

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が扱いやすく、また反映も速いため思った以上に簡単にできました。

これでテスト環境用にサブドメインを作りまくれます。

スポンサーリンク

参考

チャレンジのタイプ - Let's Encrypt - フリーな SSL/TLS 証明書

Let's Encrypt ワイルドカード自動更新(ConoHa) - eastforest

スポンサーリンク

コメント

投稿されたコメントはありません

名前

メールアドレス(任意)

コメント

関連する投稿

VagrantのWebサーバーをmDNSでLAN内からアクセスできるようにしてみた