DNSSECとDNS update(RFC2136,nsupdate)とdelegation Let's Encryptワイルドカード証明書とDANE TLSA RRを添えて

締め切りより品質という記事が出ていますが、お疲れ様です。Let’s Encryptのワイルドカード証明書のサポートはとても便利になるので期待しながらDNSSECでdns-01を使った自動化の下準備をしてみます。(2018/3/14 ACME v2 and Wildcard Certificate Support is Liveということでcertbotにてワイルドカード証明書を取得しました。末尾に簡単に追記します)

tls-sni-01(とtls-sni-02)は多くのホスティング環境でなりすませるので新規発行用には消えてなくなり、いずれtls-sni-03になるそうです。それはともかくワイルドカード証明書の発行ではdns-01だけになるだろうということでdns-01、あとは長期に渡ってサポートされそうなcertbotを使おうと思います。もしワイルドカード証明書発行がproduction環境に登場する前のテストに参加される方は自力でAPI叩くか、ACME v2 Compatible Clientsを利用されると良いかと思います。Example hook script using Dynamic DNS update utility for dns-01 challengeはcertbot用の例ではないですが、末尾の例に書かれているようにdns-01でCNAMEは解決してくれるようなので既存のゾーンをダイナミックな更新をすることはせずに、DNS update(RFC2136, nsupdate)専用のゾーンを1個だけ作成するシンプルな作業をDNSSECを有効にしたISC BIND 9.11で行ってみます。ACMEのdraft-09を見ても特にDNS query回数の上限など書かれていないので良さそうです。ダイナミックではないDNSSECのsign周りは適宜ご利用のツールで行ってください。当たり前とは思いますが各種の権限の設定など重々ご注意を。鍵無しや不要なIP範囲から更新できてしまわないかなどのテストもどうぞお忘れなく。amazon.com.___________________.dynamic.example.comなどというRRを作成されちゃうかもしれません。なおmasterが公開権威サーバである必要はないので、ClouDNS(Equinix TY8 POP追加されました。かゆいところに手が届き、サポートに連絡して何度かやりとりしてるとCEOが登場して解決にむけて動きだすという身軽さも含めて、人生の中で本当に使ってよかったと思える数少ないお気に入りサービス。)のような外部のDNSSEC対応セカンダリサーバのサービスを利用して公開権威サーバにするという方法もあります。

まずは既存のexample.comの設定が次のようになっているとします。RRは適当です。

ただでさえ複雑なsplit-horizon DNSで多数のviewなうえにDNSSECも有効である設定で、in-viewが実装された時には狂喜乱舞した、スクリプトによる処理無しではメンテが不可能な環境の再編成と抜粋で、viewはTSIGでsplit、IPアドレスでの制限はzone宣言で行っています。ゾーン転送においてはポートやIPアドレスを追加してsplitする方法よりシンプルな設定になります。ここではmasterとslaveが1viewに対して1キーを共有しています。

次にダイナミックに更新可能専用ゾーンをここではdynamic.example.comサブドメインで作ってみることにします。簡単のため親と同じDNSサーバを公開権威サーバにしています。negative cacheやdns-01とぶつかるワイルドカードなTXT RRのTTLは短めにしておきます。

dynamic.example.com 用のKSKとZSKを作成し、上のゾーンファイルをsignしたものをdynamic.example.com.zone.signedとします。またKSKからDSレコードを表示させておきます。

DNSSECとは関係なく、今度はnsupdate用の鍵を作成します。

tsig-keygenが無いバージョンではdnssec-keygenを流用します。

出来上がったKdynamic-key*.privateのKey:の行から以下のようなファイルを作成します。Kdynamic-key*.keyファイルも同じような内容ですが途中にスペースが入っているのでご注意です。

環境に合わせて適切な権限を設定しておきます。

このゾーン用の設定を追加します。

BINDのreloadにより、ここまででDNSSEC環境下でnsupdate可能になりました。

などとやってみてサーバ共にエラーにならないことを確認します。ちゃんと鍵を指定しているにもかかわらず、クライアント側で

というエラーが出る場合は、server指定がTSIGを受け付けないキャッシュサーバなどを指している可能性があります。
クライアント側で

というエラーが出る場合は、権威サーバの管轄外を更新しようとしていて、サーバ側ではREFUSEDとなっているはずです。
サーバ側で

というエラーが出る場合は、その前に以下のような警告が出ているはずなので修正します。

などと出る場合は、sign用の鍵が無いといっているので、named.confにて

のようにdirectoryで指定されているディレクトリに鍵を置きます。

環境に合わせて適切な権限を設定しておきます。

などと出る場合は、sign用の鍵が存在しているけど読む権限がないといっているので、symlinkの場合は元のファイルおよびそこから上の全てのディレクトリの権限を確認して、namedが読むのに適切かつ最小限の権限を追加するか、symlinkをやめてファイルを移動するなどの対応します。

などと出る場合は、サーバの設定ファイルの確認およびnsupdateに直接鍵名と鍵を指定して確認すると何がおかしいのかわかるかもしれません。

ダイナミックに更新できるゾーンができたのは良いですが、ゾーンを作っただけなのでdynamic.example.comの権威サーバを自力で知っている人にしか内容は伝わりません。それではdns-01で評価してもらえないので今度はexample.com側でdelegationします。DNSSECのチェーンをつなぐために、先ほどdynamic.example.comのKSKより取得したDSレコードも追加しなればなりませんが、DSレコードをレジストラ経由でレジストリに登録するよりは素早くできる作業かもしれません。

lame delegationにならないようにNSおよびDSレコードはコピペ間違いなど十分注意します。example.comをsignしてBINDをreloadでdynamic.example.comの中のダイナミックなRRがインターネットから解決できるようになります。あとは Let’s Encrypt のACME challengeに対応するCNAMEを追加していきます。*.example1.jpというワイルドカード証明書を発行したければ恐らくACME v1でexample1.jpの証明書を発行する場合と同様の次のようなCNAMEをexample1.jpゾーンに追加しておいて、

_acme-challenge.example1.jpではなくexample1.jp._acme.dynamic.example.comのTXTを追加して成功後に削除すればよい、ということになるかと思います。example1.jp.dynamic.example.comのdns-01チャレンジのTXT RRとぶつからないように念のため丸ごと先頭につけるのではない別な規則のCNAMEにしておきます。またこれによってCNAME先を完全に信頼することになるので、この例ではexample1.jp._acme.dynamic.example.comを第三者が更新できてしまう場合(第三者が更新できるような設定にしてしまった場合)、第三者による成りすまし発行が可能になります。将来なにか事件でも起きればCNAMEは解決しなくなるかもしれません。TLSA用にもCNAMEを追加しておきます。

certbot用にちょいっとスクリプトを書きます。ドキュメント真面目に読んでないのがばれますが、ちゃんとしたプラグインcertbot-dns-rfc2136があるのに後で気付いたので書く必要なかったか。もっとも権威サーバに届いたことを確認したり、TLSA周りを自動化したので、結局自分でやらないといけない部分はあったのでまあ良いか。certbotを信用してますが、厳しくやるならば$CERTBOT_… のvalidationしたり利用時にエスケープしたりする必要があるかもしれません。sleepするだけだと芸がないのでPUBLIC_AUTH_SERVERSには、先ほどdynamic.example.comゾーンのNS RRで指定した公開権威サーバを並べて実際に問い合わせてゾーン転送(IXFR)されたことを確認します。TLSA RRの追加もしてみました。TXT RRはすぐ消せますが、これを使った環境では冗長サーバに証明書が行き渡るのに最大で24時間かかるので、TLSA RRは保存しておいて(テキストファイルでも何でも良いですが、簡単なのでSQLiteつかって)次回時間が経っていたら削除です。

簡単のためここではsymlinkでモードを変えます。

certbotにスクリプトを渡して確認してみます。

まだACME v2未対応なcertbotなのでワイルドカード証明書の要求ではありませんがoutbound1.letsencrypt.orgおよびAWSから飛んでくるDNS queryを見ているとちゃんとCNAMEも解決され、CNAME元の権威サーバとCNAME先の権威サーバが異なっていても正常終了となりました。さて下準備もできたのでワイルドカード証明書対応がproduction環境に降臨するのをわくわくしながら待つことにします。やってきました。せっかくダイナミックなゾーンを作ったので、このままTLSAの自動化もしてしまいましょうか。やってみました。


2018/3/14 ACME v2 and Wildcard Certificate Support is Liveということでありがたいことでございます。
certbot 0.22初版ではconstants.pyのserverもSTAGING_URIもACME v1のサーバを指していますが、ACME v2 Compatible Clientsに0.22以降で追加されていて、実際ACME v2 Production Environment & Wildcardsに書かれているURLを指定することでワイルドカード証明書が発行されました。

この例のように*.example.comとその親example.comをSAN(Subject Alternative Names)に指定した場合、dns-01は片方だけでは許してもらえずに両方のvalidationが同時に発生し、従ってexample.comのTXT RRは複数必要となるので、直前にTXT RRを削除してから追加、というやり方ではエラーになりました。authenticatorではひたすら追加、cleanupでお掃除ということになります。certbot-dns-rfc2136使ってればきっと何も気にしないですんなりいってこれを気にすることもなかったのだろうななどと思ってます。

コメントを残す

メールアドレスが公開されることはありません。