2026年6月18日
2026年6月18日
DANE と CAA レコードを併用する設定|証明書の「発行」と「利用」の両方を DNS で縛り、更新や認証局の変更で止めない
CAA レコードと DANE(TLSA レコード)は、どちらも DNS に置いて証明書を管理する仕組みですが、効く場面が違います。CAA は「どの認証局がこのドメインの証明書を発行してよいか」を認証局に伝え、発行のときに確かめられます。DANE は「このサーバーが接続時に出す鍵はこれ」と接続相手に伝え、通信のたびに確かめられます。両方を置くと、ほかの認証局による誤発行を防ぎつつ、メールサーバーへの接続では鍵そのものを固定できます。この記事では、メールサーバー(SMTP)で両者を組み合わせる設定と、証明書の更新や認証局の変更で互いを壊さない順番を説明します。
DNSSEC と DANE の関係(署名が必要な範囲や、DNSSEC の作業で DANE を巻き込まない手順)は、別の記事で詳しく扱っています。ここでは CAA との組み合わせに絞ります。
CAA と DANE の役割の違い
| CAA | DANE(TLSA) | |
|---|---|---|
| 誰が確かめるか | 証明書を発行する認証局 | 接続する側(DANE に対応した送信メールサーバーなど) |
| いつ確かめるか | 証明書の発行・更新のとき | 接続のたび |
| 守るもの | 許可していない認証局による発行 | 偽の証明書を出すサーバーへの接続 |
| DNSSEC | なくても使えるが、署名があれば改ざんに強くなる | 必要 |
CAA は、すでに発行された証明書には影響しません。また、CAA を守らない認証局や、攻撃者が別の経路で手に入れた証明書を、接続する側が見分ける仕組みでもありません。そこを補うのが DANE です。逆に DANE は、Web ブラウザーの HTTPS では使われておらず(2026年10月現在)、実際に効くのは主に SMTP です。Web サイトの証明書については、CAA と証明書の透明性(CT)ログの監視が主な守りになります。
前提を確かめる
- ゾーンが DNSSEC で署名されている。 DANE には必須です。CAA にとっても、署名があれば応答の改ざんを防げます。署名が壊れて検証に失敗すると、多くの認証局は CAA を確かめられないとして発行を止めるため、更新が通らなくなる点にも注意します。
- DNS 事業者が CAA と TLSA を登録できる。 どちらか一方しか扱えないサービスもあります。
- 今の証明書の発行元が分かっている。 次のコマンドで確かめます。
# 今の証明書の発行者と期限(受信メールサーバー)
openssl s_client -connect mx1.example.com:25 -starttls smtp -servername mx1.example.com \
</dev/null 2>/dev/null | openssl x509 -noout -issuer -dates
# 今の CAA(なければ何も返らない)
dig +short CAA example.com
dig +short CAA mx1.example.com
CAA は、証明書の名前(ここでは mx1.example.com)から始めて、レコードが見つかるまで親のドメインへさかのぼって探されます。mx1.example.com 自体に CAA がなければ example.com の CAA が使われ、mx1.example.com に CAA を置けば、そちらが優先されます。サブドメインに古い CAA が残っていて、親の設定を変えても効かない、という失敗がよくあります。
手順1:CAA を書く
Let's Encrypt で証明書を取っている場合の例です。
example.com. 3600 IN CAA 0 issue "letsencrypt.org; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/123456789; validationmethods=dns-01"
example.com. 3600 IN CAA 0 issuewild ";"
example.com. 3600 IN CAA 0 iodef "mailto:security@example.com"
1行目は、Let's Encrypt だけに発行を許します。accounturi を付けると、自分の ACME アカウントからの申請に限られ、同じ認証局をほかの人が使って発行することも防げます。validationmethods は、ドメイン所有の確認方法を限定します。どちらも RFC 8657 で定められた拡張で、Let's Encrypt は対応していますが、認証局によっては対応していないため、使う認証局の文書で確かめます。2行目はワイルドカード証明書の発行をすべて禁止し、3行目は規則に反した申請があったときの連絡先です(連絡を送るかどうかは認証局次第です)。
アカウント URI の値(例の 123456789 の部分)は、certbot ならアカウント情報から確かめられます。新しめの certbot には certbot show_account というサブコマンドがあり、表示される URI をそのまま使います。値を間違えると次回の更新が拒否されるので、最初は accounturi と validationmethods を付けずに公開し、更新が通ることを確かめてから絞り込む進め方が安全です。
手順2:TLSA を公開する
受信メールサーバーの公開鍵から TLSA の値を作ります。CAA と組み合わせる場合も、推奨されるのは「3 1 1」(DANE-EE、公開鍵、SHA-256)です。
openssl x509 -in /etc/letsencrypt/live/mx1.example.com/cert.pem -noout -pubkey \
| openssl pkey -pubin -outform DER \
| openssl dgst -sha256 | awk '{print $NF}'
_25._tcp.mx1.example.com. 3600 IN TLSA 3 1 1 (上で得た16進文字列)
「3 1 1」は認証局を問わずに鍵だけを見るため、認証局を変えても、鍵が同じなら TLSA は変わりません。一方、「2 1 1」(DANE-TA)で中間証明書の鍵を指定する方法もありますが、Let's Encrypt のように中間証明書が定期的に切り替わる認証局では、切り替えのたびに TLSA が合わなくなるおそれがあるため、運用の手間が増えます。
手順3:証明書の更新で両方を保つ
更新のたびに、CAA は認証局によって、TLSA は接続相手によって確かめられます。どちらも壊さないための要点は2つです。
- 鍵を変えずに更新する。 certbot では、証明書の設定に鍵の再利用を指定しておくと(
--reuse-key)、更新後も公開鍵が変わらず、TLSA を触らずに済みます。 - 確認方法を CAA と合わせる。
validationmethods=dns-01と書いたのに、更新がhttp-01で行われる設定のままだと、更新が CAA で拒否されます。certbot の更新設定(/etc/letsencrypt/renewal/の設定ファイル)に記録された認証方式と、CAA の指定が一致しているかを確かめます。
更新を自動化している場合は、更新後にメールサーバーへ新しい証明書を読み込ませる処理(certbot の deploy フックで Postfix を再読み込みするなど)も含めておきます。
手順4:認証局を変えるときの順番
CAA を置いている状態で認証局を変えるには CAA の書き換えが要り、TLSA は鍵を変えるかどうかで対応が変わります。次の順番で進めると、途中で発行も配送も止まりません。
- CAA に新しい認証局を追加する(古い認証局の行は残す)
- CAA の TTL が切れるのを待ってから、新しい認証局で証明書を取る
- 鍵を変えた場合は、新しい鍵の TLSA を古い TLSA と並べて公開し、TLSA の TTL 分待つ
- メールサーバーの証明書を新しいものに差し替え、外から確かめる
- 古い TLSA を削除する
- 古い認証局での更新が不要になったことを確かめてから、CAA から古い認証局の行を外す
鍵を変えずに認証局だけ変える場合、3 と 5 は不要です。作業の前には、DNS のゾーンの内容をエクスポートするなどして控えておき、すぐ戻せるようにします。
確認のコマンド
# CAA と TLSA が署名つきで返るか(ad フラグを見る)
dig @1.1.1.1 +dnssec CAA example.com | grep -E 'flags:|status:'
dig @1.1.1.1 +dnssec TLSA _25._tcp.mx1.example.com | grep -E 'flags:|status:'
# サーバーの証明書と TLSA が一致するか
openssl s_client -connect mx1.example.com:25 -starttls smtp -servername mx1.example.com \
-dane_tlsa_domain mx1.example.com \
-dane_tlsa_rrdata "3 1 1 (TLSA の16進文字列)" </dev/null 2>/dev/null \
| grep -E 'Verification|DANE'
あわせて、CT ログの検索サービスで自分のドメインに発行された証明書を定期的に見ておくと、CAA をすり抜けた発行があった場合に気づけます。
よくあるつまずき
- 更新が CAA で拒否される。 サブドメイン側に古い CAA が残っている、
accounturiの値が別アカウントのもの、validationmethodsと実際の認証方式が違う、の順に疑います。認証局のエラーメッセージに CAA の語が含まれていれば、まずこの3点です。 - 更新後に DANE 対応の送信側からメールが届かない。 鍵が変わったのに TLSA を更新していない状態です。
openssl s_clientで照合し、鍵を再利用する設定になっているかを確かめます。 - CAA の変更が反映されない。 認証局側でも CAA の結果を一定時間保持することがあります。TTL を確かめ、時間を置いて再試行します。
まとめ
- CAA は発行のときに認証局が、DANE は接続のたびに相手が確かめます。両方を置くと、誤発行の防止と接続時の鍵の固定を組み合わせられます。
- CAA は
accounturiとvalidationmethodsで自分のアカウントと認証方式に絞れます。ただし最初は付けずに更新を確かめてから絞ります。 - TLSA は「3 1 1」にし、証明書の更新では鍵を再利用すると、CAA の更新と TLSA が互いに干渉しにくくなります。
- 認証局を変えるときは、CAA に追加、発行、TLSA を並べて公開、差し替え、古い TLSA と古い CAA の削除、の順に進めます。