東京大学情報基盤センターPKI

参考)UPKI-certbot-DNS-01チャレンジ対応(設定例)

動作関連図

DNS-01 チャレンジの構成図

サーバ概要

要点

  • example.u-tokyo.ac.jp のgitlabサーバで HTTPS 用証明書を取得します。
  • サーバは内部セグメントのみで、外部からHTTPで到達できません。
  • このため ACME は DNS-01 で行います。

DNS更新の前提

  • dns1.example / dns2.example / dns3.example は hidden master を持ちますが、セキュリティのため API で更新しません。
  • _acme-challenge.example.u-tokyo.ac.jp. を更新するための hidden master(acme-master)を新設します。

DNS構成

要点

  • 「_acme-challenge.example.u-tokyo.ac.jp.」は「example.u-tokyo.ac.jp.」の既存ゾーンから分離し、権威DNSサーバ上に専用ゾーンとして作成して別管理します。
  • 更新は acme-master のみで受け付け、権威DNSサーバ側は参照専用(ゾーン転送で受け取ります)。
  • 「example.u-tokyo.ac.jp.」の通常運用は dns-master が担当します。

役割

項目 説明
dns-master example.u-tokyo.ac.jp. の hidden master(既存)
acme-master _acme-challenge.example.u-tokyo.ac.jp. の hidden master(新規)。DNS-01 の更新はここだけで行います。
dns1.example / dns2.example / dns3.example 権威DNSサーバ(参照用)。acme-master からゾーン転送を受けます。

権威DNSサーバ

  • dns1.example 133.11.254.1
  • dns2.example 130.69.254.1
  • dns3.example 157.82.254.1

DNS-01対応のmaster / zone 作成(acme-master)

# ディレクトリの作成
user@acme-master:~$ sudo mkdir -p /etc/bind/keys
user@acme-master:~$ ls -l /etc/bind
...

# tsigの鍵を作成
user@acme-master:~$ sudo tsig-keygen -a hmac-sha256 [tsig-key-name] > /etc/bind/keys/acme-example.key

# tsig鍵ファイルのパーミッションなど設定
user@acme-master:~$ sudo chown root:bind /etc/bind/keys/acme-example.key
user@acme-master:~$ sudo chmod 640 /etc/bind/keys/acme-example.key
user@acme-master:~$ sudo ls -l /etc/bind/keys/acme-example.key
-rw-r----- 1 root bind 109 Nov 11 15:31 /etc/bind/keys/acme-example.key

# 内容確認
user@acme-master:~$ sudo cat /etc/bind/keys/acme-example.key
key "[tsig-key-name]" {
       algorithm hmac-sha256;
       secret "[secret]";
};

# bindの設定
user@acme-master:~$ sudo vi /etc/bind/named.conf
// This is the primary configuration file for the BIND DNS server named.
//
// Please read /usr/share/doc/bind9/README.Debian for information on the
// structure of BIND configuration files in Debian, *BEFORE* you customize
// this configuration file.
//
// If you are just adding zones, please do that in /etc/bind/named.conf.local
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";
include "/etc/bind/named.conf.utnet";

# 追加したbindの設定
user@acme-master:~$ sudo vi /etc/bind/named.conf.utnet
include "/etc/bind/keys/acme-example.key";
zone "_acme-challenge.example.u-tokyo.ac.jp" IN {
  type master;
  file "/var/lib/bind/db._acme-challenge.example.u-tokyo.ac.jp";
  update-policy {
      grant [tsig-key-name] name _acme-challenge.example.u-tokyo.ac.jp TXT;
  };
  allow-query { "acme-hosts"; };
  allow-transfer { 133.11.254.1; 130.69.254.1; 157.82.254.1; };
  also-notify { 133.11.254.1; 130.69.254.1; 157.82.254.1; };
  notify yes;
};
acl "acme-hosts" {
  localhost;
  [example-host-ip];
};

user@acme-master:~$ sudo vi /var/lib/bind/db._acme-challenge.example.u-tokyo.ac.jp
$ORIGIN .
$TTL 60 ; 1 minute
_acme-challenge.example.u-tokyo.ac.jp IN SOA dns1.example.u-tokyo.ac.jp. nocstaff.example.u-tokyo.ac.jp. (
                                2025111100 ; serial
                                300        ; refresh (5 minutes)
                                60         ; retry (1 minute)
                                3600       ; expire (1 hour)
                                60         ; minimum (1 minute)
                                )
                        NS      dns1.example.u-tokyo.ac.jp.
                        NS      dns2.example.u-tokyo.ac.jp.
                        NS      dns3.example.u-tokyo.ac.jp.
$TTL 120        ; 2 minutes
user@acme-master:~$ sudo chown bind:bind /var/lib/bind/db._acme-challenge.example.u-tokyo.ac.jp

# 設定の反映
user@acme-master:~$ sudo systemctl reload bind9

# FWの設定、exampleからとdns1.example,dns2.example,dns3.exampleからのみBind9での接続受付
user@acme-master:~$ sudo ufw status numbered
Status: active
     To                         Action      From
     --                         ------      ----
...
[ 7] Bind9                      ALLOW IN    [example-host-ip]
[ 8] Bind9                      ALLOW IN    133.11.254.1
[ 9] Bind9                      ALLOW IN    130.69.254.1
[10] Bind9                      ALLOW IN    157.82.254.1

dns-master 設定

_acme-challenge.example.u-tokyo.ac.jp. だけ、別NSに切り出します。

bash-3.1$ sudo vi /etc/namedb/u-tokyo.ac.jp
; 以下を追加
; for acme / dns-01
_acme-challenge.example.u-tokyo.ac.jp.     IN      NS      dns1.example.u-tokyo.ac.jp.
                                            IN      NS      dns2.example.u-tokyo.ac.jp.
                                            IN      NS      dns3.example.u-tokyo.ac.jp.

dns1.example / dns2.example / dns3.example 設定(参考)

_acme-challenge.example.u-tokyo.ac.jp. のzone作成(参考情報のみ)。

user@dns1.example:~$ diff /etc/namedb/named.conf-dom.20251111 /etc/namedb/named.conf-dom
699a700,707
> zone "_acme-challenge.example.u-tokyo.ac.jp" in {
>         type slave;
>         file "bak/dom/_acme-challenge.example.u-tokyo.ac.jp";
>         masters {
>                 [acme-master-ip];
>         };
> };
>
user@dns2.example:~$ diff /etc/namedb/named.conf-dom.20251111 /etc/namedb/named.conf-dom
701a702,709
> zone "_acme-challenge.example.u-tokyo.ac.jp" in {
>         type slave;
>         file "bak/dom/_acme-challenge.example.u-tokyo.ac.jp";
>         masters {
>                 [acme-master-ip];
>         };
> };
>
user@dns3.example:~$ diff /etc/namedb/named.conf-dom.20251111 /etc/namedb/named.conf-dom
701a702,709
> zone "_acme-challenge.example.u-tokyo.ac.jp" in {
>         type slave;
>         file "bak/dom/_acme-challenge.example.u-tokyo.ac.jp";
>         masters {
>                 [acme-master-ip];
>         };
> };
>

DNS-01対応のクライアント側作業

HTTP-01チャレンジでのコマンド(参考)

user@example:~$ sudo certbot \
  --server https://secomtrust-acme.com/acme/ \
  --eab-hmac-key [secret] \
  --eab-kid [kid] \
  -d example.u-tokyo.ac.jp \
  --key-type rsa

DNS-01チャレンジ対応のコマンドオプション

certonlyオプションをつけて、証明書の生成のみにしています。

user@example:~$ sudo certbot certonly \
  --server https://secomtrust-acme.com/acme/ \
  --eab-hmac-key [secret] \
  --eab-kid [kid] \
  -d example.u-tokyo.ac.jp \
  --key-type rsa \
  --dns-rfc2136 \
  --dns-rfc2136-credentials /etc/letsencrypt/rfc2136.ini \
  --dns-rfc2136-propagation-seconds 60

サーバ側作業(インストールなど)

user@example:~$ sudo apt-get install certbot python3-certbot-dns-rfc2136
[sudo] password for user:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
...

certbotのDNS-01チャレンジ用設定ファイル

user@example:~$ sudo vi /etc/letsencrypt/rfc2136.ini
dns_rfc2136_server = [acme-master-ip]
dns_rfc2136_port = 53
dns_rfc2136_name = [tsig-key-name]
dns_rfc2136_secret = [secret]
dns_rfc2136_algorithm = HMAC-SHA256

# 設定ファイルのパーミッション設定
user@example:~$ sudo chown root:root /etc/letsencrypt/rfc2136.ini
user@example:~$ sudo chmod 600 /etc/letsencrypt/rfc2136.ini

実行

user@example:~$ sudo certbot certonly \
  --server https://secomtrust-acme.com/acme/ \
  --eab-hmac-key [secret] \
  --eab-kid [kid] \
  -d example.u-tokyo.ac.jp \
  --key-type rsa \
  --dns-rfc2136 \
  --dns-rfc2136-credentials /etc/letsencrypt/rfc2136.ini \
  --dns-rfc2136-propagation-seconds 60
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): user@example.ac.jp
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://repo1.secomtrust.net/spcpp/publicly-trusted-cpcps/. You must agree in
order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
Account registered.
Requesting a certificate for example.u-tokyo.ac.jp
Waiting 60 seconds for DNS changes to propagate
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.u-tokyo.ac.jp/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.u-tokyo.ac.jp/privkey.pem
This certificate expires on 2026-02-09.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

証明書の確認

user@example:~$ sudo certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
  Certificate Name: example.u-tokyo.ac.jp
    Serial Number: 7dafc3b1e77920e6ea035585d2c86223
    Key Type: RSA
    Domains: example.u-tokyo.ac.jp
    Expiry Date: 2026-02-09 06:10:26+00:00 (VALID: 88 days)
    Certificate Path: /etc/letsencrypt/live/example.u-tokyo.ac.jp/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/example.u-tokyo.ac.jp/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

user@example:~$ sudo openssl x509 -in /etc/letsencrypt/live/example.u-tokyo.ac.jp/fullchain.pem -text -noout

定期的に自動更新されることを確認

user@example:~$ systemctl list-timers | grep certbot
Thu 2025-11-13 04:46:14 JST   11h - - certbot.timer                 certbot.service

証明書更新時の反映

証明書ファイル /etc/letsencrypt/live/example.u-tokyo.ac.jp/fullchain.pem と、証明書鍵ファイル /etc/letsencrypt/live/example.u-tokyo.ac.jp/privkey.pem ができるので、これを参照するように設定を実施します。

証明書更新時にWebサーバなどに反映するためのコマンドを実施します。

user@example:~$ sudo vi /etc/letsencrypt/renewal-hooks/deploy/gitlab-reload.sh
#!/bin/bash
(gitlabのフロントとなるnginxをreloadするshell script, 省略)

参考:nsupdateコマンドについて

nsupdateコマンドで、ゾーンの更新などの確認ができます。

  • FWが正しく設定されているか
  • ACLが正しく設定されているか
  • TSIGが正しく設定されているか
# テストトークンの追加
user@acme-master:~$ sudo nsupdate -k /etc/bind/keys/acme-example.key
> server 127.0.0.1
> zone _acme-challenge.example.u-tokyo.ac.jp
> update add _acme-challenge.example.u-tokyo.ac.jp. 60 IN TXT "test-token-123"
> send
> quit

# 追加したテストトークンの削除
user@acme-master:~$ dig @localhost _acme-challenge.example.u-tokyo.ac.jp TXT
; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> @localhost _acme-challenge.example.u-tokyo.ac.jp TXT
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8393
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 97659a78206da0680100000069129e446f4de0917d881177 (good)
;; QUESTION SECTION:
;_acme-challenge.example.u-tokyo.ac.jp. IN TXT
;; ANSWER SECTION:
_acme-challenge.example.u-tokyo.ac.jp. 60 IN TXT "test-token-123"
;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(localhost) (UDP)
;; WHEN: Tue Nov 11 11:24:04 JST 2025
;; MSG SIZE rcvd: 125

# テストトークンの削除
user@acme-master:~$ sudo nsupdate -k /etc/bind/keys/acme-example.key
> server 127.0.0.1
> zone _acme-challenge.example.u-tokyo.ac.jp
> update delete _acme-challenge.example.u-tokyo.ac.jp. TXT
> send
> quit

# 削除の確認
user@acme-master:~$ dig @localhost _acme-challenge.example.u-tokyo.ac.jp TXT
; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> @localhost _acme-challenge.example.u-tokyo.ac.jp TXT
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28707
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: bdb4a9ff8fe7ea5c0100000069129ec9cc3b342c10da0467 (good)
;; QUESTION SECTION:
;_acme-challenge.example.u-tokyo.ac.jp. IN TXT
;; AUTHORITY SECTION:
_acme-challenge.example.u-tokyo.ac.jp. 60 IN SOA dns1.example.u-tokyo.ac.jp.
nocstaff.example.u-tokyo.ac.jp. 2025111103 300 60 3600 60
;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(localhost) (UDP)
;; WHEN: Tue Nov 11 11:26:17 JST 2025
;; MSG SIZE rcvd: 164

# 更新したデータは.jnlファイルに保存されている。それをzoneファイルに反映する
user@acme-master:~$ sudo rndc sync

# zoneファイルの最新の状態を確認する
user@acme-master:~$ sudo rndc zonestatus _acme-challenge.example.u-tokyo.ac.jp
name: _acme-challenge.example.u-tokyo.ac.jp
type: primary
files: /var/lib/bind/db._acme-challenge.example.u-tokyo.ac.jp
serial: 2025111103
nodes: 1
last loaded: Tue, 11 Nov 2025 01:57:20 GMT
secure: no
dynamic: yes
frozen: no
reconfigurable via modzone: no