プライベート VPN の名前が解決できない?疑うべきは DNS リバインド保護
プライベート空間の応答を拒否するリゾルバは、トンネルではなく内部名を壊します。応答を読み、例外を範囲限定し、保護は他の場所に残してください。
オフィスの LAN では内部名が即座に応答します。VPN を接続した途端に動かなくなり、アプリケーションはタイムアウトを報告し、トンネル自体は文句も言わずにトラフィックを流しています。変わったのはリゾルバであり、そのリゾルバはプライベートアドレスについて一家言あります。
リバインド保護は、ある特定の手口を止めるために存在します。意図的に公開されたプライベート名は、防御が発動する程度には似て見えるのです。
ポリシーより先に応答を読む
VPN が実際に配布するリゾルバに対して名前を問い合わせます。自宅でノート PC が使うリゾルバではなく、応答を期待するレコードと比較し、その返答が空なのか、拒否なのか、誰も想定していないパブリックアドレスで埋まっているのかを記録します。
症状は重なり合うため、診断を決めるのは応答の形です。NXDOMAIN はレコードの欠落、REFUSED はアクセスルール、内部名に対するパブリックアドレスはポリシーかスプリット DNS の誤り、そしてクライアントが使えない正しいプライベートアドレスはまったく別の問題です。接続拒否や要求の停止はそれ自体では何も証明しないので、こうしたチケットの最初のコマンドは再起動ではなく問い合わせであるべきです。何かを変える前に応答を書き留めてください。
防御が実際に止めているもの
DNS リバインドは、クライアントがすでに名前を信頼した後に、その名前が解決する先を変えることで成立します。攻撃者が管理する名前からページが読み込まれ、応答がプライベートアドレスに切り替わり、ブラウザは直接接続なら決して受け入れなかったローカルネットワーク上の何かと通信させられます。防御とは、リゾルバがプライベート名前空間を提供するよう求められていない場合に、プライベート空間を指す応答を拒否することです。その非対称性が攻撃のすべてです。
dnsmasq はまさにその挙動を、ドメインごとの例外とともに文書化しています。マニュアルでは、そのようなアドレスを正当に返してよいドメインを指定する方法として rebind-domain-ok を説明しています。意図された修正は範囲を限定した許可であり、全体のスイッチではないという合図として読んでください。
例外を名前空間に限定する
まず名前空間を直し、それから例外です。失敗する名前が組織の管理するドメインに属し、そのレコードが意図的に維持されていることを確認します。見慣れた LAN の範囲に似ているだけの予期しないアドレスは、例外ではなく疑いの対象に値するので、許可を書く前にゾーンの所有者を確認してください。
# ask the resolver the VPN pushed, and show the full answer
dig +noall +answer db.corp.example @10.40.0.1
dig +short db.corp.example @10.40.0.1
# dnsmasq: what does the running configuration already allow?
grep -R 'rebind' /etc/dnsmasq.d /etc/dnsmasq.conf
次に、VPN クライアントが問い合わせるリゾルバ設定で、対象の名前を覆う最も狭い許可、つまり一つのドメインか一つの委任されたサブドメインを追加します。そのリゾルバ上のすべての名前で保護を切ると、それを必要としなかった名前も含めて全員の防御が一度に失われます。
スプリット DNS も同じ判断に属します。プライベート名前空間を内部リゾルバだけで応答すべきなら、そこに公開してパブリックリゾルバへの漏えいを止め、そうすれば例外はあらゆる経路ではなく一つの経路を覆います。
リソースと防御を再テストする
もう一度問い合わせ、次にサービスへ接続してクライアントが見るものを確認します。正しいプライベート応答と動作するセッションなら、例外は効いています。正しい応答なのにセッションが止まるなら、次に疑うべきはルートかサービスの身元です。
# the internal name and the public control should behave differently
dig +short db.corp.example @10.40.0.1
dig +short www.example.com @10.40.0.1
# and the service itself, with the certificate it presents
curl -sS -o /dev/null -w '%{http_code}\n' https://db.corp.example/health
同じリゾルバ経由でパブリック名も試してください。例外の外にある名前では保護が引き続き正しく働くはずで、その確認が失敗するなら変更は意図より広すぎたことになります。証明書の検証は最後まで手を付けないでください、正しく解決する名前でもサービスが提示する証明書と一致しなければならないからです。
拒否された応答、ドメイン、リゾルバ、ポリシーの所有者をチケットに記録します。その記録が、謎の内部障害を誰かがレビューできる設定変更へと変えるのです。