サイズ: 8089
コメント:
|
サイズ: 15483
コメント:
|
削除された箇所はこのように表示されます。 | 追加された箇所はこのように表示されます。 |
行 1: | 行 1: |
= Let's EncryptでSSL証明書の新規作成と自動更新(dns-01編) = == Let's Encrypt とは == <<Include(SSL証明書/Memo_Of_LetsEncrypt)>> == dns-01 とは == * サイト利用者を証明するための「チャレンジ・レスポンス」のやりとりをHTTP(http-01)ではなく、DNS(dns-01)を使う方法である。 * 環境(イントラネット内である、アプライアンス機器でHTTPのランディングが不可能、SMTP等で http-01 できないなど)によってはこの方法しか採れないケースもある。 * DNSコンテンツサーバーとの連携(諸設定)が必要になってしまうが、この味を知ってしまうと http-01 手順には戻れなくなること請け合いである:-)。 * どれくらい戻れないかというと、Webサーバーに対しても dns-01 手順を適用したくなってしまうくらい中毒性がある:-)。 == 目次 == |
|
行 3: | 行 15: |
= Let's EncryptでSSL証明書の新規作成と自動更新(dns-01編) = * [[https://letsencrypt.jp/|Lets' Encrypt]]によるSSL証明書の自動取得・自動更新に関するメモを残す。 * Let's Encrypt について復習ではあるが、 * 認証局のブランドの一つである。これは「Symantec(旧Verisign)セキュア・サーバーID」「!CyberTrust !SureServer」「!SecomTrust セコムパスポート for Web3.0」「!GlobalSign クイック認証SSL」「!GeoTrust RapidSSL」「Comodo PositiveSSL」などの一つと考えれば良い。たぶんどれかは聞いたことあるはずと思う。 * 他の認証局と明確に違う点は、 * 無償。当然ではあるが、1証明書をどのように(複数IP, 複数バックエンド, 複数プロトコル)使用しても1取得で済む。 * 親ドメインをまたぐ、マルチドメイン証明書(Subject Alternative Names)に対応している。 * その代わり、ワイルドーカード証明書には対応していない。 * RSA(2048bit, 3072bit, 4096bit), ECDSA(prime256v1, secp384r1) の5種類の鍵が選べる。 * ACME(Automated Certificate Management Environment)プロトコルによる証明書の認証から発行までの一連のバッチ化(自動化)が可能。 * 扱える端末が(比較的)少ない。全アクセスの 0.5% であってもフォローしないといけない用途なら使えない。逆に今時のメジャーどころのブラウザは対応している。 * DV(Domain Validation)証明書のみ。ただしOV(Organization Validation)やEV(Extended Validation)との純技術的な優劣は無い。 * 取得数制限(特に単位時間あたりの)があるので注意。詳しくは [[https://letsencrypt.org/docs/rate-limits/|Rate Limits]] を参照のこと。 * [[https://letsencrypt.org/docs/staging-environment/|検証(ステージング)用認証局]]も用意されているので、セットアップ時の検証や、ACMEクライアントの開発といった用途ではこちらを使う。 * 「現在の」ルート証明書は「!IdentTrust|DST(Digital Signature Trust) Root CA X3」である。 * 少なくとも中間証明書の発行者(Issuer)はそうである([[https://letsencrypt.org/isrg/|ISRG - Internet Security Research Group]] ではない)。 * このルート証明書がインストールされた端末が対応端末となる。 * 中間証明書は「Let's Encrypt Authority X3」である(場合によってはこっち「も」入ってることがあるかもしれない)。 * 使用するツール・傾向については [[SSL証明書/Let's EncryptでSSL証明書の新規取得と自動更新(http-01編)|Let's EncryptでSSL証明書の新規取得と自動更新(http-01編)]] を参照のこと。 * ここでは「チャレンジ・レスポンス」を HTTP ではなく、DNS を使う方法について説明する。 * 環境(イントラネット内など)によってはこの方法しか採れないケースもありうる。 * DNSサーバーとの連携(諸設定)が必要になってしまうが、この味を知ってしまうと http-01 手順には戻れなくなること請け合いである:-)。 |
|
行 27: | 行 16: |
* OSは FreeBSD 11.0-R。 * ACMEクライアントは dehydrated 0.4.0。 * DNSサーバーは BIND 9.11.0-P3。 いずれも最新のリリースということで確認しているが、ある程度古い環境でも問題無いと思われ。 本例では、www.example.jp というコモンネームに対して証明書を発行するものとする。 チャレンジ/レスポンスコードをダイナミックアップデートするため、 example.jp ゾーンに対する権威DNSサーバーへの更新権限があるものとする。 少なくとも _acme-challenge.www.example.jp ゾーン(と分けて/委任してもらって)に対する更新権限は最低限必要である。 |
* 以下のソフトウェアの利用を前提に検証を実施した。いずれも最新のリリースということで確認しているが、ある程度古い環境でも問題無いと思われる。 * OS: FreeBSD 11.0-R * ACMEクライアント: dehydrated 0.4.0 * DNSクライアント: BIND 9.11.1P3(nsupdate コマンド) * DNSコンテンツサーバー: BIND 9.11.1P3 * SSL証明書利用サーバーについては言及しない。 * 上記以外の環境では、以下の点に相違が発生する。必要に応じて読み替えたし。 * インストール方法 * インストールされるディレクトリ * 自動更新のための手続きとその設定 * 逆に以下の点は参考にできる。 * 設定パラメータとその意味 * 運用事例 == 検証作業内容 == * 本例では、www.example.jp というサイトに対して証明書を発行するものとする。 * チャレンジ・レスポンスコードをDNSダイナミックアップデートするため、example.jp ゾーンに対するDNSコンテンツサーバーへの更新権限があるものとする。 * ある程度制限できるとは言え、DNSダイナミックアップデートは「ゾーン」に対してフリーダムに更新できてしまうので、_acme-challenge.www.example.jp ゾーン(に分けて/委任してもらって)に、更新が閉じるよう制限するのが必要と思われる。 * ここでは敢えて「example.jp」ゾーンから「_acme-challenge.www.example.jp」を自分自身(DNSコンテンツサーバー)へ委任するものとし、外部のDNSコンテンツサーバーへは向けないものとする。 * ここまでお膳立てが整えられていれば、例えば、サービスゾーンのDNSコンテンツサーバーへの更新権限は得られなくても、自分のDNSコンテンツサーバーに委任してもらって、更新できるようにするのは難しくないと思う。 === 想定サーバー・ドメイン === * DNSコンテンツサーバーは ns.example.jp とする。 * 実際には複数のDNSコンテンツサーバーで運用されていると思う。 * それらサーバーへの反映は ns.example.jp の notify yes; およびIXFR(Incremental Zone Transfer)により、全てのサーバーへ即時通達されるものとする。 * それら詳細についてはここでは取り上げない。 * SSLサーバーは www.example.jp とする。 * 上記サーバーは同一でもかまわないし、別々でもかまわない。 === DNSコンテンツサーバー側 === * DNSサーバーは BIND 9.11.1([[https://www.freshports.org/dns/bind911|ports/dns/bind911]])。 === SSLサーバー側 === * DNSダイナミックアップデートクライアントは BIND 9.11.1([[https://www.freshports.org/dns/bind-tools|ports/dns/bind-tools]])。 * 既に BIND 9.11.1 ([[https://www.freshports.org/dns/bind911|ports/dns/bind911]])がインストールされている環境では不要。 * FreeBSD 9.x 等といった古い環境では nsupdate コマンドが存在したため、そのような環境でもインストールは不要である。 * ACMEクライアントは dehydrated 0.4.0([[https://www.freshports.org/security/dehydrated|ports/security/dehydrated]])。 |
行 39: | 行 55: |
* いずれも ports/security/dehydrated、ports/dns/bind911 よりインストールする。 | * いずれも ports/security/dehydrated、ports/dns/bind911 または ports/dns/bind-utils よりインストールする。 |
行 42: | 行 58: |
= DNSサーバーの設定 = | = DNSコンテンツサーバー側の設定 = |
行 44: | 行 60: |
* よってディレクトリ作成は不要である。 * ここでは「example.jp」ゾーンから「_acme-challenge.www.example.jp」を委任する。 * また自分自身(権威DNSサーバー)への委任とし、特に外部のDNSサーバーへは向けない。 * DNS権威(コンテンツ)サーバーは ns.example.jp とする。 == named.conf の設定例 == {{{ include "ダイナミックアップデートキーファイル名"; |
* よってディレクトリ作成作業は不要である。 == named.conf の設定(一部)例 == {{{ include "ダイナミックアップデートキーフルパス名"; |
行 55: | 行 68: |
file "example.jpゾーンファイル名"; | file "example.jpゾーンフルパス名"; |
行 60: | 行 73: |
file "_acme-challenge.www.example.jpゾーンファイル名"; | file "_acme-challenge.www.example.jpゾーンフルパス名"; |
行 67: | 行 80: |
* 「DNS権威サーバー」と「SSL証明書を発行したいサーバー」とで、TSIG(Transaction SIGnature)キーを共有する。 | * 「DNSコンテンツサーバー」と「SSLサーバー」とで、TSIG(Transaction SIGnature)キーを共有する。 |
行 71: | 行 84: |
== example.jp ゾーンファイルの設定例 == |
* また変更できるレコード名およびリソースレコードを限定する(name _acme-challenge.www.example.jp. TXT)。 == example.jp ゾーンファイルの設定例(/usr/local/etc/namedb/master/example.jp.db) == |
行 87: | 行 101: |
== _acme-challenge.www.example.jp ゾーンファイルの設定例 == | * 本ファイルの設置場所、命名規則はそれぞれのポリシーに従う。 * 少なくともFreeBSD的には、/usr/local/etc/namedb/master/ ディレクトリ以下に設置されるものとしている。 * さらに「example.jp.db」とするか「jp.example.db」とするかなどは、好きにすれば良い。 == _acme-challenge.www.example.jp ゾーンファイルの設定例(/usr/local/etc/namedb/dynamic/_acme-challenge.www.example.jp.db) == |
行 101: | 行 119: |
* 本ファイルの設置場所、命名規則はそれぞれのポリシーに従う。 * 少なくともFreeBSD的には、/usr/local/etc/namedb/dynamic/ ディレクトリ以下に設置されるものとしている。 * さらに「_acme-challenge.www.example.jp.db」とするか「jp.example.www._acme-challenge.db」とするかなどは、好きにすれば良い。 |
|
行 105: | 行 127: |
secret "シークレットキー(BASE64表現)"; }; }}} 上記ファイルは以下のコマンドにより生成することができる。 {{{ tsig-keygen -a hmac-sha256 キー名 > ダイナミックアップデートキーファイル名 chmod 0400 ダイナミックアップデートキーファイル名 }}} * もちろん secret の部分は毎回ランダムに発行される。 * このファイルは named.conf でも、(後で説明する)nsupdate コマンド(-k オプションで)でもそのまま解釈してくれる。 * 本ファイルの設置場所、命名規則については一概に言えることが無く、「ポリシーで」で逃げるには無責任すぎるので、例を出してみる。 === 本例における具体的設定例 === * BIND側に設置する場合は、/usr/local/etc/namedb/ ディレクトリに設置することとする。 * dehydrated側に設置する場合は、/usr/local/etc/dehydrated/ ディレクトリに設置することとする。 * ファイル名についてだが、「キー名.key」とするのが違和感なくていいと思う。 * 肝心のキー名だが、[[https://ftp.isc.org/isc/bind9/cur/9.11/doc/arm/Bv9ARM.ch04.html#tsig|BIND9.11のマニュアル(TSIG)]]によれば「ホスト名1-ホスト名2.」という例がある。 * 本気かどうかわからないが、「DNSコンテンツサーバー-ダイナミックアップデートするサーバー.」というニュアンスらしい。 * 本件の場合、ns.example.jp と www.example.jp であることから「ns-www.」とするのが妥当か(ほんと?)。 * まぁなんでもいいけど、わかりやすいようにね。 {{{ key "ns-www." { algorithm hmac-sha256; |
|
行 109: | 行 159: |
上記ファイルは以下のコマンドにより生成することができる。 {{{ tsig-keygen -a hmac-sha256 キー名 > ダイナミックアップデートキーファイル名 }}} もちろん secret の部分は毎回ランダムに発行される。 このファイルは named.conf でも(後で説明する)nsupdate コマンドでもそのまま解釈してくれる。 |
* /usr/local/etc/namedb/ns-www.key * /usr/local/etc/dehydrated/ns-www.key = SSLサーバー側の設定 = * ほとんど[[SSL証明書/Let's EncryptでSSL証明書の新規取得と自動更新(http-01編)|Let's EncryptでSSL証明書の新規取得と自動更新(http-01編)]]で実施した作業と同じになる。 * 明確に違う点は、先のページでは解説してない「HOOK」設定となる。 * ここでは一通り作業の意味がわかってる前提で、一通り設定を紹介する。 == /etc/periodic.conf == {{{ weekly_dehydrated_enable="YES" }}} 自動更新設定(YES=自動更新する)。 [[https://www.freebsd.org/cgi/man.cgi?periodic(8)|periodic(8)]]にある通り、毎週土曜日3時に実行される。 なお今回、weekly_dehydrated_deployscript は指定しない(後述の HOOK 設定参照のこと)。 == /usr/local/etc/dehydrated/ns-www.key == これは先に tsig-keygen コマンドで作成されたファイルである。 DNSコンテンツサーバーと同一になるように設定すること。 == /usr/local/etc/dehydrated/config == {{{ alias openssl="/usr/bin/openssl" CHALLENGETYPE="dns-01" HOOK="${BASEDIR}/hook.sh" RENEW_DAYS="30" KEY_ALGO="rsa" KEYSIZE="2048" #KEY_ALGO="prime256v1" CONTACT_EMAIL="メールアドレス" #テスト発行したい場合、以下の2行を有効にすること。 #CA="https://acme-staging.api.letsencrypt.org/directory" #CA_TERMS="https://acme-staging.api.letsencrypt.org/terms" }}} * http-01 との時との大きな違いは CHALLENGETYPE と HOOK 設定にある。 * HOOK 設定(によって指定されるファイル)については後述する。 * CHALLENGETYPE には dns-01 を指定する。 * CHALLENGETYPE は現在 http-01 か dns-01 の2つしか選択肢は無い。 == /usr/local/etc/dehydrated/domains.txt == {{{ example.org www.example.org example.com www.example.com wiki.example.com }}} 本ファイルの設定については [[/SSL証明書/Let's EncryptでSSL証明書の新規取得と自動更新(http-01編)#A.2BMLMw4jDzMM0w.2FDDgMNUwoTCkMOs-|コモンネームの設定]]に準拠するものとする(例)。 == /usr/local/etc/dehydrated/hook.sh == {{{ #!/usr/local/bin/bash TTL="300" DNSSERVER="ns.example.jp" alias nsupdate="/usr/local/bin/nsupdate -k ${BASEDIR}/ns-www.key" function deploy_challenge { local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}" printf 'server %s\nupdate add _acme-challenge.%s. %d TXT "%s"\nsend\n' "${DNSSERVER}" "${DOMAIN}" "${TTL}" "${TOKEN_VALUE}" | nsupdate } function clean_challenge { local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}" printf 'server %s\nupdate delete _acme-challenge.%s. TXT\nsend\n' "${DNSSERVER}" "${DOMAIN}" | nsupdate } function deploy_cert { /usr/sbin/service apache24 restart && /usr/local/bin/dehydrated -gc } function unchanged_cert { # NOTHING TO DO # } function invalid_challenge() { # NOTHING TO DO # } function request_failure() { # NOTHING TO DO # } function exit_hook() { # NOTHING TO DO # } HANDLER=$1; shift; $HANDLER $@ }}} HOOK ファイルのひな形として、/usr/local/etc/dehydrated/hook.sh.example を参照すること。 == /usr/local/etc/dehydrated/deploy.sh == * 先に述べたように、本ケースでは本ファイルを取り扱わない。 * HOOK で指定するシェルスクリプトの deploy_cert 関数で代替できるからである。 * HOOK(/usr/local/etc/dehydrated/config)と weekly_dehydrated_deployscript(/etc/periodic.conf)の違いは以下の通りである。 * 証明書取得する単位毎に実行されるのが HOOK、全て取得終って実行されるのが weekly_dehydrated_deployscript。 * 証明書取得に成功した・失敗した(または更新なし)がわかるのが HOOK、わからないのが weekly_dehydrated_deployscript。 * よって、1枚の証明書を相手にする時はそう違いは無いが、複数枚を取得して分散デプロイしたいなら HOOK しかない。 * ファインチューニング(更新ない時は何もしないなど)したいなら HOOK 一択。 * 逆に HOOK はデプロイだけしたいユースケースにおいて若干ながら大味(ダミーの関数を置く必要がある)。 * この HOOK はバージョンによって拡張されることがあるので、場合によっては(エラーで止まるなど)追随しなければならないこともありうる。 = 参考文献 = * [[https://ftp.isc.org/isc/bind9/cur/9.11/doc/arm/Bv9ARM.html|BIND 9 Administrator Reference Manual]] |
Let's EncryptでSSL証明書の新規作成と自動更新(dns-01編)
Let's Encrypt とは
Lets' Encrypt は認証局(Certificate Authority)のブランドの一つである。
これは「Symantec(旧Verisign)セキュア・サーバーID」「CyberTrust SureServer」「SecomTrust セコムパスポート for Web3.0」「GlobalSign クイック認証SSL」「GeoTrust RapidSSL」「Comodo PositiveSSL」などの一つと考えれば良い。
- たぶんどれかは聞いたことあるはずと思う。アレが抜けてるというツッコミは却下で:-)。
- 他の認証局と同じような点は、
- 1証明書をどのように(複数IP、複数バックエンド、複数プロトコル)使用しても1取得で済む(安い認証局は大抵そうだよね)。
- 親ドメインをまたぐ、マルチドメイン証明書(Subject Alternative Names)に対応している(全ての認証局で対応してるね)。
いよいよワイルドカード証明書に対応(対応してるブランドと対応してないブランドとあるね)。
DV(Domain Validation)証明書のみ提供(DVだけでなくOV・EVにも対応してるブランドもあるね)。
ただしOV(Organization Validation)証明書やEV(Extended Validation)証明書との純技術的な優劣は無い。
- 他の認証局と明確に違う点は、
- 無償。
RSA(2048bit、3072bit、4096bit), ECDSA(prime256v1、secp384r1) の5種類の鍵が選べる(ここまで選べるブランドは限られるね)。DSAが無い?時代だ。諦めろ。
ACME(Automated Certificate Management Environment)プロトコルによる証明書の認証から発行までの一連のバッチ化(自動化)が可能。
- 今どき誤差だけど、扱える端末が(他の認証局と比べて)少ない。
- ごく一部のエンドユーザーが粘り強く使用しているような、全アクセスの0.1%未満の端末であってもサポートしないといけない用途であるならお勧めしない。
- 逆に今どきのメジャーどころの端末・ブラウザは対応している。
よってPC相手にはほぼ問題無い(Windows XP? IE6? 知らんがな)。
取得数制限(特に単位時間あたりの)があるので注意。詳しくは Rate Limits を参照のこと。
検証(ステージング)用認証局も用意されているので、セットアップ時の検証や、ACMEクライアントの開発といった用途ではこちらを使う。
「現在の」ルート証明書は「IdentTrust|DST(Digital Signature Trust) Root CA X3」である。
IdentTrust なの? DST なの? については旧会社のブランドも残ってるらしい、としか自分は認識してない。詳しくは会社概要でも読んでくれい。
少なくとも中間証明書の発行者(Issuer)はそうである(Let's Encrypt運用元の ISRG - Internet Security Research Group ではない)。
- このルート証明書がインストールされた端末が対応端末となる。
中間証明書(Subject)は「Let's Encrypt Authority X3」である(場合によってはこっち「も」入ってることがあるかもしれない)。
ここでは全て dehydrated を使用を前提に解説する。certbotとdehydratedの違いについては特に解説しない。
dehydratedを選んだ理由は、
dehydratedはBash/ZSH依存スクリプトであるため、特別な言語環境(Python)を必要としない。
certbotの場合、Pythonに依存する分には問題無いが、依存するPythonモジュールが極めて大量にあって維持が大変。
dehydratedはまだ依存が少ない(curl のせいでずいぶん増えてるが)。
dehydratedの場合、わけわかんなくなっても、シェルスクリプトなのでソースコード読んで理解できる。また長いコードではない。
dehydratedはWebサーバー機能を内蔵していないため、Webサーバーとの競合に配慮しなくてよい。
dehydratedはエイリアス機能により、同じコモンネームでRSA/ECDSA両方の証明書取得が可能である。
dns-01 とは
- サイト利用者を証明するための「チャレンジ・レスポンス」のやりとりをHTTP(http-01)ではなく、DNS(dns-01)を使う方法である。
- 環境(イントラネット内である、アプライアンス機器でHTTPのランディングが不可能、SMTP等で http-01 できないなど)によってはこの方法しか採れないケースもある。
- DNSコンテンツサーバーとの連携(諸設定)が必要になってしまうが、この味を知ってしまうと http-01 手順には戻れなくなること請け合いである:-)。
- どれくらい戻れないかというと、Webサーバーに対しても dns-01 手順を適用したくなってしまうくらい中毒性がある:-)。
目次
検証環境
- 以下のソフトウェアの利用を前提に検証を実施した。いずれも最新のリリースということで確認しているが、ある程度古い環境でも問題無いと思われる。
- OS: FreeBSD 11.0-R
- ACMEクライアント: dehydrated 0.4.0
- DNSクライアント: BIND 9.11.1P3(nsupdate コマンド)
- DNSコンテンツサーバー: BIND 9.11.1P3
- SSL証明書利用サーバーについては言及しない。
- 上記以外の環境では、以下の点に相違が発生する。必要に応じて読み替えたし。
- インストール方法
- インストールされるディレクトリ
- 自動更新のための手続きとその設定
- 逆に以下の点は参考にできる。
- 設定パラメータとその意味
- 運用事例
検証作業内容
- 本例では、www.example.jp というサイトに対して証明書を発行するものとする。
- チャレンジ・レスポンスコードをDNSダイナミックアップデートするため、example.jp ゾーンに対するDNSコンテンツサーバーへの更新権限があるものとする。
- ある程度制限できるとは言え、DNSダイナミックアップデートは「ゾーン」に対してフリーダムに更新できてしまうので、_acme-challenge.www.example.jp ゾーン(に分けて/委任してもらって)に、更新が閉じるよう制限するのが必要と思われる。
- ここでは敢えて「example.jp」ゾーンから「_acme-challenge.www.example.jp」を自分自身(DNSコンテンツサーバー)へ委任するものとし、外部のDNSコンテンツサーバーへは向けないものとする。
- ここまでお膳立てが整えられていれば、例えば、サービスゾーンのDNSコンテンツサーバーへの更新権限は得られなくても、自分のDNSコンテンツサーバーに委任してもらって、更新できるようにするのは難しくないと思う。
想定サーバー・ドメイン
- DNSコンテンツサーバーは ns.example.jp とする。
- 実際には複数のDNSコンテンツサーバーで運用されていると思う。
- それらサーバーへの反映は ns.example.jp の notify yes; およびIXFR(Incremental Zone Transfer)により、全てのサーバーへ即時通達されるものとする。
- それら詳細についてはここでは取り上げない。
- SSLサーバーは www.example.jp とする。
- 上記サーバーは同一でもかまわないし、別々でもかまわない。
DNSコンテンツサーバー側
DNSサーバーは BIND 9.11.1(ports/dns/bind911)。
SSLサーバー側
DNSダイナミックアップデートクライアントは BIND 9.11.1(ports/dns/bind-tools)。
既に BIND 9.11.1 (ports/dns/bind911)がインストールされている環境では不要。
- FreeBSD 9.x 等といった古い環境では nsupdate コマンドが存在したため、そのような環境でもインストールは不要である。
ACMEクライアントは dehydrated 0.4.0(ports/security/dehydrated)。
インストール
- いずれも ports/security/dehydrated、ports/dns/bind911 または ports/dns/bind-utils よりインストールする。
- オプションの選択によって手順が変わる点は無いため、ここでは明示しない。
DNSコンテンツサーバー側の設定
Let's EncryptでSSL証明書の新規取得と自動更新(http-01編)で実施した「ドメイン所有者確認トークンディレクトリの指定」の代わりの作業となる。
- よってディレクトリ作成作業は不要である。
named.conf の設定(一部)例
include "ダイナミックアップデートキーフルパス名"; zone "example.jp" { type master; file "example.jpゾーンフルパス名"; }; zone "_acme-challenge.www.example.jp" { type master; file "_acme-challenge.www.example.jpゾーンフルパス名"; update-policy { grant ダイナミックアップデートキー名 name _acme-challenge.www.example.jp. TXT; }; };
- 「DNSコンテンツサーバー」と「SSLサーバー」とで、TSIG(Transaction SIGnature)キーを共有する。
- TSIGキーはキー名と秘密鍵で構成された、named.conf の書式に準拠したテキストファイルである。
- このTSIGキーを「ダイナミックアップデートキーファイル名」で保存しておく(所有者は root:wheel、パーミッションは 0400 で)。
- また、ダイナミックアップデートキーファイル名で定義されているキー名に対して、更新許可設定を与える(update-policy および grant)。
- また変更できるレコード名およびリソースレコードを限定する(name _acme-challenge.www.example.jp. TXT)。
example.jp ゾーンファイルの設定例(/usr/local/etc/namedb/master/example.jp.db)
$TTL 300 @ IN SOA ns.example.jp. domain.example.jp. ( 2017032201 ; serial 7200 ; refresh (2 hours) 900 ; retry (15 minutes) 2419200 ; expire (4 weeks) 86400 ; minimum (1 day) ) IN NS ns _acme-challenge.www IN NS ns
- 本ファイルの設置場所、命名規則はそれぞれのポリシーに従う。
- 少なくともFreeBSD的には、/usr/local/etc/namedb/master/ ディレクトリ以下に設置されるものとしている。
- さらに「example.jp.db」とするか「jp.example.db」とするかなどは、好きにすれば良い。
_acme-challenge.www.example.jp ゾーンファイルの設定例(/usr/local/etc/namedb/dynamic/_acme-challenge.www.example.jp.db)
$TTL 300 @ IN SOA ns.example.jp. domain.example.jp. ( 2017032201 ; serial 7200 ; refresh (2 hours) 900 ; retry (15 minutes) 2419200 ; expire (4 weeks) 86400 ; minimum (1 day) ) IN NS ns
- 本ファイルの設置場所、命名規則はそれぞれのポリシーに従う。
- 少なくともFreeBSD的には、/usr/local/etc/namedb/dynamic/ ディレクトリ以下に設置されるものとしている。
- さらに「_acme-challenge.www.example.jp.db」とするか「jp.example.www._acme-challenge.db」とするかなどは、好きにすれば良い。
ダイナミックアップデートキーファイルの設定例
key "キー名" { algorithm hmac-sha256; secret "シークレットキー(BASE64表現)"; };
上記ファイルは以下のコマンドにより生成することができる。
tsig-keygen -a hmac-sha256 キー名 > ダイナミックアップデートキーファイル名 chmod 0400 ダイナミックアップデートキーファイル名
- もちろん secret の部分は毎回ランダムに発行される。
- このファイルは named.conf でも、(後で説明する)nsupdate コマンド(-k オプションで)でもそのまま解釈してくれる。
- 本ファイルの設置場所、命名規則については一概に言えることが無く、「ポリシーで」で逃げるには無責任すぎるので、例を出してみる。
本例における具体的設定例
- BIND側に設置する場合は、/usr/local/etc/namedb/ ディレクトリに設置することとする。
- dehydrated側に設置する場合は、/usr/local/etc/dehydrated/ ディレクトリに設置することとする。
- ファイル名についてだが、「キー名.key」とするのが違和感なくていいと思う。
肝心のキー名だが、BIND9.11のマニュアル(TSIG)によれば「ホスト名1-ホスト名2.」という例がある。
- 本気かどうかわからないが、「DNSコンテンツサーバー-ダイナミックアップデートするサーバー.」というニュアンスらしい。
- 本件の場合、ns.example.jp と www.example.jp であることから「ns-www.」とするのが妥当か(ほんと?)。
- まぁなんでもいいけど、わかりやすいようにね。
key "ns-www." { algorithm hmac-sha256; secret "PfzeGvXiOqtPOwQJY/iNFrvlD3/eKAHRZ0TbyK5GYII="; };
- /usr/local/etc/namedb/ns-www.key
- /usr/local/etc/dehydrated/ns-www.key
SSLサーバー側の設定
ほとんどLet's EncryptでSSL証明書の新規取得と自動更新(http-01編)で実施した作業と同じになる。
- 明確に違う点は、先のページでは解説してない「HOOK」設定となる。
- ここでは一通り作業の意味がわかってる前提で、一通り設定を紹介する。
/etc/periodic.conf
weekly_dehydrated_enable="YES"
自動更新設定(YES=自動更新する)。 periodic(8)にある通り、毎週土曜日3時に実行される。
なお今回、weekly_dehydrated_deployscript は指定しない(後述の HOOK 設定参照のこと)。
/usr/local/etc/dehydrated/ns-www.key
これは先に tsig-keygen コマンドで作成されたファイルである。 DNSコンテンツサーバーと同一になるように設定すること。
/usr/local/etc/dehydrated/config
alias openssl="/usr/bin/openssl" CHALLENGETYPE="dns-01" HOOK="${BASEDIR}/hook.sh" RENEW_DAYS="30" KEY_ALGO="rsa" KEYSIZE="2048" #KEY_ALGO="prime256v1" CONTACT_EMAIL="メールアドレス" #テスト発行したい場合、以下の2行を有効にすること。 #CA="https://acme-staging.api.letsencrypt.org/directory" #CA_TERMS="https://acme-staging.api.letsencrypt.org/terms"
- http-01 との時との大きな違いは CHALLENGETYPE と HOOK 設定にある。
- HOOK 設定(によって指定されるファイル)については後述する。
- CHALLENGETYPE には dns-01 を指定する。
- CHALLENGETYPE は現在 http-01 か dns-01 の2つしか選択肢は無い。
/usr/local/etc/dehydrated/domains.txt
example.org www.example.org example.com www.example.com wiki.example.com
本ファイルの設定については コモンネームの設定に準拠するものとする(例)。
/usr/local/etc/dehydrated/hook.sh
TTL="300" DNSSERVER="ns.example.jp" alias nsupdate="/usr/local/bin/nsupdate -k ${BASEDIR}/ns-www.key" function deploy_challenge { local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}" printf 'server %s\nupdate add _acme-challenge.%s. %d TXT "%s"\nsend\n' "${DNSSERVER}" "${DOMAIN}" "${TTL}" "${TOKEN_VALUE}" | nsupdate } function clean_challenge { local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}" printf 'server %s\nupdate delete _acme-challenge.%s. TXT\nsend\n' "${DNSSERVER}" "${DOMAIN}" | nsupdate } function deploy_cert { /usr/sbin/service apache24 restart && /usr/local/bin/dehydrated -gc } function unchanged_cert { # NOTHING TO DO # } function invalid_challenge() { # NOTHING TO DO # } function request_failure() { # NOTHING TO DO # } function exit_hook() { # NOTHING TO DO # } HANDLER=$1; shift; $HANDLER $@
HOOK ファイルのひな形として、/usr/local/etc/dehydrated/hook.sh.example を参照すること。
/usr/local/etc/dehydrated/deploy.sh
- 先に述べたように、本ケースでは本ファイルを取り扱わない。
- HOOK で指定するシェルスクリプトの deploy_cert 関数で代替できるからである。
- HOOK(/usr/local/etc/dehydrated/config)と weekly_dehydrated_deployscript(/etc/periodic.conf)の違いは以下の通りである。
- 証明書取得する単位毎に実行されるのが HOOK、全て取得終って実行されるのが weekly_dehydrated_deployscript。
- 証明書取得に成功した・失敗した(または更新なし)がわかるのが HOOK、わからないのが weekly_dehydrated_deployscript。
- よって、1枚の証明書を相手にする時はそう違いは無いが、複数枚を取得して分散デプロイしたいなら HOOK しかない。
- ファインチューニング(更新ない時は何もしないなど)したいなら HOOK 一択。
- 逆に HOOK はデプロイだけしたいユースケースにおいて若干ながら大味(ダミーの関数を置く必要がある)。
- この HOOK はバージョンによって拡張されることがあるので、場合によっては(エラーで止まるなど)追随しなければならないこともありうる。