2026年6月13日
2026年6月13日
DoT (DNS over TLS) と DNSSEC を併用する設定|暗号化と署名検証の役割分担と Unbound・systemd-resolved の構成例
DoT(DNS over TLS)と DNSSEC は競合する技術ではなく、守っている区間が違うため組み合わせて使えます。DoT は「端末とリゾルバーの間の通信」を暗号化し、DNSSEC は「権威 DNS が出した応答が改ざんされていないこと」を署名で確かめます。この記事では、両者の役割分担を整理したうえで、Unbound を「DNSSEC を検証し、DoT で応答する」リゾルバーにする設定と、Linux 端末の systemd-resolved から DoT で使う設定、動作確認と切り分けの方法を説明します。
DoT と DNSSEC はどこを守るのか
名前解決の経路は大きく、端末(スタブリゾルバー)→ フルリゾルバー(キャッシュ DNS)→ 権威 DNS、の2区間に分かれます。
- DoT は、端末とフルリゾルバーの間を TLS で暗号化します。問い合わせ内容を経路上から見られにくくし、接続先のリゾルバーが本物かどうかを証明書で確かめられます。ただし、リゾルバーが受け取った応答そのものが正しいかは保証しません。
- DNSSEC は、権威 DNS がゾーンに付けた署名を、フルリゾルバーが検証する仕組みです。キャッシュポイズニングのような偽応答を見抜けますが、通信は暗号化しません。
併用したときに効いてくるのが、DNSSEC の検証結果の受け渡しです。検証済みの応答には AD フラグが付きますが、平文の UDP で端末へ返す区間ではこのフラグ自体を偽装されるおそれがあります。DoT で端末とリゾルバーの間を守ると、「検証済み」という結果を端末側が信用しやすくなります。つまり「リゾルバーで DNSSEC を検証し、その結果を DoT で端末まで運ぶ」のが基本の形です。
構成を決める
よくある構成は次の2つです。
- 自前のリゾルバー(Unbound など)で DNSSEC を検証し、社内や自宅の端末へ DoT で提供する。 検証を自分の管理下に置けます。上流へは再帰問い合わせをするか、パブリック DNS へ DoT で転送します。
- 端末からパブリック DNS(Quad9、Cloudflare など)へ DoT で問い合わせ、DNSSEC 検証は上流に任せる。 設定は少なくて済みますが、検証の可否は上流の方針に依存します。
以下では 1 を中心に、端末側の設定として 2 にも触れます。作業前に現在の設定ファイルを控え、本番の DNS を切り替える前に検証用の環境で動かしてください。
Unbound で DNSSEC 検証と DoT 待ち受けを設定する
証明書を用意する
DoT で待ち受けるには、端末が接続に使うホスト名(例: dns.example.com)の証明書と秘密鍵が要ります。社外の端末からも使うなら Let's Encrypt などの公的な証明書、社内専用なら社内 CA でも構いません。証明書はチェーンを含むファイル(fullchain)を指定します。中間証明書が欠けていると、端末によって検証に失敗します。
秘密鍵は Unbound の実行ユーザーから読める権限にしつつ、他のユーザーからは読めないようにします。ディストリビューションによっては AppArmor などのプロファイルで読めるパスが制限されているため、エラーが出たらそちらも確認します。
設定ファイルの例
# /etc/unbound/unbound.conf.d/dot-dnssec.conf(例。パスやネットワークは環境に合わせる)
server:
# 端末向け: 平文 53 番はローカルのみ、DoT は 853 番で待ち受け
interface: 127.0.0.1@53
interface: 0.0.0.0@853
interface: ::0@853
tls-port: 853
tls-service-pem: "/etc/unbound/tls/fullchain.pem"
tls-service-key: "/etc/unbound/tls/privkey.pem"
# 問い合わせを受け付ける範囲(オープンリゾルバーにしない)
access-control: 127.0.0.0/8 allow
access-control: 192.0.2.0/24 allow
# DNSSEC 検証
module-config: "validator iterator"
auto-trust-anchor-file: "/var/lib/unbound/root.key"
val-log-level: 2
# 上流へ DoT で転送するときに上流の証明書を検証する CA バンドル
tls-cert-bundle: "/etc/ssl/certs/ca-certificates.crt"
# 上流へ DoT で転送する場合(自前で再帰するならこのブロックは不要)
forward-zone:
name: "."
forward-tls-upstream: yes
forward-addr: 9.9.9.9@853#dns.quad9.net
forward-addr: 149.112.112.112@853#dns.quad9.net
ポイントは次のとおりです。
access-controlで許可するネットワークを絞ります。誰でも使えるリゾルバーを公開すると、DNS の増幅攻撃に悪用されます。auto-trust-anchor-fileはルートゾーンの鍵(トラストアンカー)を自動更新するための設定です。Debian/Ubuntu のパッケージでは別ファイルで設定済みのことがあるので、二重に書かないよう既存の設定を確認します。- 上流へ転送する場合でも、
validatorモジュールが有効なら Unbound 自身が DNSSEC を検証します。上流の応答に署名データが含まれていれば検証できるため、「暗号化は上流までの DoT、真正性は手元で検証」という分担になります。 forward-addrの#以降は上流の証明書に書かれたホスト名です。これがないと、接続先が本物かを名前で確かめられません。
設定を書いたら構文を確認してから再起動します。
sudo unbound-checkconf
sudo systemctl restart unbound
sudo ss -lntup | grep -E ':(53|853)\b'
853 番は TCP です。ファイアウォールやクラウドのセキュリティグループで、許可したいネットワークからの TCP 853 番を開けます。
動作を確認する
DNSSEC の検証が効いているか
まずサーバー上で、平文の 53 番に対して確認します。
# 署名されたドメイン: flags に ad が付けば検証成功
dig @127.0.0.1 +dnssec www.isc.org A
# 署名がわざと壊されているテスト用ドメイン: SERVFAIL になれば検証が効いている
dig @127.0.0.1 dnssec-failed.org A
# +cd(検証を無効にして問い合わせ)を付けると応答が返る
dig @127.0.0.1 +cd dnssec-failed.org A
dnssec-failed.org は検証のテストによく使われるドメインですが、外部のドメインなので状態が変わる可能性があります。結果が想定と違うときは DNSViz などで現状を確認してください。
DoT で応答しているか
次に端末側から DoT で問い合わせます。kdig(Knot DNS のツール、Debian/Ubuntu では knot-dnsutils)を使うと、証明書の検証まで含めて確かめられます。
# 証明書をシステムの CA で検証し、ホスト名も照合する
kdig @192.0.2.53 +tls-ca +tls-hostname=dns.example.com www.isc.org A
# 証明書チェーンそのものを見る
openssl s_client -connect dns.example.com:853 -servername dns.example.com </dev/null
BIND 9.18 以降の dig にも +tls がありますが、証明書の検証まで行うかはオプションとバージョンによって異なります。証明書の確認には kdig か openssl s_client を使うほうが分かりやすいです。
端末側(systemd-resolved)から DoT で使う
Ubuntu などで使われている systemd-resolved は、上流への DoT に対応しています。
# /etc/systemd/resolved.conf([Resolve] セクション)
[Resolve]
DNS=192.0.2.53#dns.example.com
DNSOverTLS=yes
DNSSEC=allow-downgrade
sudo systemctl restart systemd-resolved
resolvectl status
resolvectl query www.isc.org
DNSOverTLS=yesは DoT が使えないときに失敗させる設定です。opportunisticは使えないときに平文へ戻るため、経路上の妨害で暗号化が外れても気付けません。DNSSECは systemd-resolved 自身が検証するかどうかの設定です。上流の Unbound が検証している場合でも、端末側でも検証させるかは環境次第です。systemd-resolved の検証は一部のネットワーク機器や上流と相性問題が出ることがあり、ディストリビューションの既定値も分かれています。まず上流で検証し、端末側はallow-downgradeまたはnoから始めて、問題がないことを見てから強めるのが無難です。resolvectl queryの出力に、データが認証済みかどうかや暗号化された経路で取得したかが表示されます(表示内容は systemd のバージョンにより異なります)。
各設定値の意味は man resolved.conf で、手元のバージョンのものを確認してください(2026年10月現在)。
うまく動かないときの切り分け
症状が「名前が引けない(SERVFAIL・タイムアウト)」のとき、原因が DoT 側か DNSSEC 側かを分けると早く片付きます。
- 平文の 53 番では引けるか。 サーバー上で
dig @127.0.0.1が成功し、DoT 経由だけ失敗するなら、証明書・ポート・ファイアウォールの問題です。 - **
+cdを付けると引けるか。** 付けると引けるなら DNSSEC の検証失敗です。Unbound のログ(val-log-level: 2で理由が出ます)を見て、該当ドメインの署名や DS の不整合を DNSViz で確認します。自分のドメインなら、DS の登録ミスや鍵の更新漏れが典型例です。 - すべてのドメインで検証に失敗する。 サーバーの時刻ずれを疑います。DNSSEC の署名にも TLS 証明書にも有効期間があるため、時計が大きくずれると両方が同時に失敗します。
timedatectlで NTP 同期を確認します。トラストアンカーのファイルが壊れていたり古かったりする場合も全滅します。 - 一部のネットワークからだけ DoT がつながらない。 853 番を遮断しているネットワーク(公衆無線 LAN や一部の企業網)があります。この場合は DoH(443 番)を検討します。
なお、DNSSEC で署名された応答はサイズが大きくなりがちですが、DoT は TCP 上で動くため、UDP の断片化による取りこぼしは起きにくくなります。DoT 導入後に一部のドメインだけ改善した、という場合はこの影響であることもあります。
まとめ
- DoT は端末とリゾルバーの間の暗号化、DNSSEC は応答の真正性の検証で、守る区間が違うため併用できます。
- 基本形は「リゾルバーで DNSSEC を検証し、その結果を DoT で端末まで届ける」構成です。
- Unbound では
validatorモジュールとトラストアンカー、tls-service-pem・tls-service-keyと 853 番の待ち受けを設定し、access-controlでオープンリゾルバーにしないようにします。 - 確認は
dig +dnssec(ad フラグ)、テスト用ドメインでの SERVFAIL、kdig +tls-caでの DoT 接続の3点で行います。 - 失敗時は「平文なら引けるか」「
+cdで引けるか」「時刻は正しいか」の順に切り分けます。