6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

acme-dns で Let's Encrypt のワイルドカード証明書を発行・更新する

Last updated at Posted at 2020-06-17

はじめに

無料で SSL 証明書を発行してくれる Let's Encrypt では、証明書の発行・更新の際にドメインの所有者であることを証明する必要があるが、その方法として次の2つがよく使用される。

  • HTTP-01 チャレンジ
  • DNS-01 チャレンジ

(参考: チャレンジのタイプ - Let's Encrypt)

ワイルドカード証明書 (「*.example.com」のようなすべてのサブドメインで有効な証明書) を発行してもらう場合は、DNS-01 チャレンジを使用する必要がある。

DNS-01 チャレンジとは

自身が所有するドメインの権威 DNS サーバにおいて、Let's Encrypt から指定された特定の値を TXT レコードに設定することにより、ドメインの所有権を証明する。

_acme-challenge.example.com. IN TXT 82QiAOKu66D70Jm-Q3nAijh29d2587F3HiuhEgWGFf8

Let's Encrypt の証明書の有効期限は90日なので、約3ヶ月ごとに DNS サーバのレコードを変更する必要があり、手間がかかる。そこで acme-dns という仕組みを利用する。

acme-dns とは

acme-dns とは、DNS-01 チャレンジ認証を実施するための

  • 簡易 DNS サーバ
  • Web API サーバ

がセットになった、Go 言語で書かれたオープンソースのソフトウェアである。

用意するもの

acme-dns 用サーバ

今回は Ubuntu Server 18.04 をインストールした適当な VPS を使う。グローバル IP アドレスが必要。

Let's Encrypt 用クライアント

適当な Linux 環境。今回は発行した SSL 証明書を使用する Web サーバを想定。

文中のパラメータ

文中の下記の値は、環境に応じて適宜読み替えること。

key value
acme-dns サーバのホスト名 acme-dns.example.net
acme-dns 用のゾーン acme-dns.example.net
acme-dns サーバの IP アドレス 203.0.113.10
SSL 証明書を発行するドメイン example.com

構築手順

acme-dns サーバ用の DNS レコードの登録

acme-dns で使用するドメイン (例: example.net) の権威 DNS に、次のレコードを登録する (SSL 証明書の発行は、このドメインに限られないのでご安心を)。

  • acme-dns サーバの A レコード
  • DNS-01 チャレンジで使用する NS レコード
acme-dns.example.net. IN A 203.0.113.10
acme-dns.example.net. IN NS acme-dns.example.net. 

なお今回は前記「文中のパラメータ」の通り、「acme-dns サーバのホスト名」と「acme-dns 用のゾーン」で同じ名前を使うので、A レコードはグルーレコードの役割も果たす。このゾーンの権威サーバも acme-dns が担う。

acme-dns サーバ

今回は Docker で acme-dns サーバを動かすことにする。

まず用意した Ubuntu Server 18.04 に

  • Docker 環境
  • docker-compose コマンド

をインストールしておく。

Ubuntu で systemd-resolved が動いている場合、acme-dns が Port 53 を listen するのに邪魔になるので無効化する (下記「1.1.1.1」等の部分は、適当な DNS リゾルバを指定)。

$ sudo systemctl stop systemd-resolved
$ sudo systemctl disable systemd-resolved
$ cat << EOM | sudo tee /etc/resolv.conf
nameserver 1.1.1.1
nameserver 1.0.0.1
EOM

acme-dns のソースを GitHub から持ってくる。

$ git clone https://github.com/joohoi/acme-dns

設定ファイルやデータベース用のディレクトリを作成する。

$ cd acme-dns
$ mkdir data db

設定ファイルを作成する。

$ cp config.cfg config/
config/config.cfg
[general]
listen = "0.0.0.0:53"
protocol = "both"
domain = "acme-dns.example.net"
nsname = "acme-dns.example.net"
nsadmin = "admin.example.net"
records = [
    "acme-dns.example.net. A 203.0.113.10",
    "acme-dns.example.net. NS acme-dns.example.net.",
]
debug = true

[database]
engine = "sqlite3"
connection = "/var/lib/acme-dns/acme-dns.db"

[api]
ip = "0.0.0.0"
disable_registration = false
port = "443"
tls = "letsencrypt"
acme_cache_dir = "api-certs"
corsorigins = [
    "*"
]
use_header = false
header_name = "X-Forwarded-For"

[logconfig]
loglevel = "debug"
logtype = "stdout"
logformat = "text"

なお acme-dns の API は HTTPS なので、自身にも SSL 証明書が必要になるが、上記の tls オプションで letsencrypt を指定することで、自動的に Let's Encrypt で証明書を発行して適用してくれる。

設定ができたので、docker-compose コマンドで acme-dns を起動する (-d はバックグラウンドで起動するオプション)。

$ docker-compose build
$ docker-compose up -d

以上で acme-dns サーバが構築できた。

SSL 証明書の発行

以後は、適当な Linux 環境 (例: 証明書を使用する Web サーバ) で作業する。

あらかじめ以下のコマンドをインストールしておく。

  • curl
  • jq

acme-dns のユーザ登録 (初回のみ)

構築した acme-dns に対して、証明書を発行するドメイン (ゾーン) ごとにユーザ登録が必要になる。

ユーザ登録は Web API で行える。なお下記の 203.0.113.0/24 の部分は、このユーザが acme-dns を使用できる IP アドレス (つまり Web サーバ等) の範囲を指定する。必須パラメータではないが、セキュリティ上指定しておいた方が良い。

$ curl \
  -s \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "allowfrom": [
        "203.0.113.0/24"
    ]
}' https://acme-dns.example.com/register | jq .

すると以下のような結果が返ってくるので、これをメモしておく。

{
  "username": "zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz",
  "password": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
  "fulldomain": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.acme-dns.example.net",
  "subdomain": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "allowfrom": [
    "203.0.113.0/24"
  ]
}

DNS レコードの登録 (初回のみ)

SSL 証明書を発行するドメイン (例: example.com) の権威 DNS サーバに、acme-dns を使用するための CNAME レコードを登録する。下記の xxx... の部分は、上記結果の fulldomain の値に置き換えること。

_acme-challenge.example.com. IN CNAME xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.acme-dns.example.net.

SSL 証明書の発行

いよいよ acme-dns を使って Let's Encrypt の SSL 証明書を発行する。

acme-dns に対応したクライアントの実装はいくつかある。また、よく Let's Encrypt で使われる certbot コマンドの hook スクリプト機能を使用する方法もあるが、今回は acme.sh というとても便利なクライアントを見つけたので、これを使用する。

まず acme.sh をインストールする。

$ curl https://get.acme.sh | sh
$ . ~/.bashrc

インストールできたら、-h オプションでヘルプを見てみる。

$ acme.sh -h | head -20
https://github.com/acmesh-official/acme.sh
v2.8.6
Usage: acme.sh  command ...[parameters]....
Commands:
  --help, -h               Show this help message.
  --version, -v            Show version info.
  --install                Install acme.sh to your system.
  --uninstall              Uninstall acme.sh, and uninstall the cron job.
  --upgrade                Upgrade acme.sh to the latest code from https://github.com/acmesh-official/acme.sh.
  --issue                  Issue a cert.
  --signcsr                Issue a cert from an existing csr.
  --deploy                 Deploy the cert to your server.
  --install-cert           Install the issued cert to apache/nginx or any other server.
  --renew, -r              Renew a cert.
  --renew-all              Renew all the certs.
  --revoke                 Revoke a cert.
  --remove                 Remove the cert from list of certs known to acme.sh.
  --list                   List all the certs.
  --showcsr                Show the content of a csr.
  --install-cronjob        Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.

証明書を発行する用のシェルスクリプト (例: letsencrypt.sh) を作成する。

letsencrypt.sh
#!/usr/bin/env bash

OPT=$1

DOMAIN="example.com"
export ACMEDNS_BASE_URL="https://acme-dns.example.net"
export ACMEDNS_USERNAME="zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz"
export ACMEDNS_PASSWORD="yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
export ACMEDNS_SUBDOMAIN="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

~/.acme.sh/acme.sh \
  $OPT \
  --debug \
  --dns dns_acmedns \
  -d "$DOMAIN" \
  -d "*.$DOMAIN"

シェルスクリプトを実行する。

$ chmod +x letsencrypt.sh
$ ./letsencrypt.sh --issue

うまくいくと、$HOME/.acme.sh/example.com/ ディレクトリ以下に、SSL 証明書や秘密鍵が発行されるので、これらのファイルを Web サーバ等から参照する。

$ ls -1 $HOME/.acme.sh/example.com
ca.cer
fullchain.cer
example.com.cer
example.com.conf
example.com.csr
example.com.csr.conf
example.com.key

dig コマンドを使用すると、acme-dns が TXT レコードを応答していることが確認できる。

$ dig _acme-challenge.example.com. txt +short
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.acme-dns.example.net.
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"

なお acme.sh の --list オプションで、発行済証明書の一覧が確認できる。

$ acme.sh --list
Main_Domain     KeyLength  SAN_Domains       Created                       Renew
example.com  ""         *.example.com  Wed Jun 17 11:02:23 UTC 2020  Sun Aug 16 11:02:23 UTC 2020

発行した証明書を更新するには、以下のコマンドを実行すれば良い。

$ ./letsencrypt.sh --renew

acme.sh には、cron による証明書の自動更新など便利な機能がいろいろあるので、研究してみよう。

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?