VPNサーバーを新しいパブリックIPへ移す:最初に確認すべきこと
その場での差し替えと並行カットオーバーでは、壊れる場所が違います。設定、NAT、証明書を確認し、各クライアントが名前をどう解決するかを見ます。
アドレスの再割り当ては一分で終わります。問題が起きるのはその翌週であり、プロバイダーのコンソールが示す場所とは限りません。新しいパブリックIPは四か所で参照されます。デーモンが待ち受けるソケット、クライアントが検証する信頼の基点、古いアドレスを名指すすべてのルール、そしてそれらを結びつけるDNSレコードです。二つの移行は管理画面からは同じに見えても、振る舞いはまったく異なります。自分が運用するマシンでアドレスを再割り当てするか、二つ目のエンドポイントを立ててクライアントをそちらへ移すかです。以下の確認は安く済む失敗を先に置き、どの節がどちらの移行に当てはまるかを示します。
その場での差し替えと並行カットオーバーは別の作業です
その場での差し替えは、ホスト、鍵、ルーティングテーブル、ユーザー一覧をそのまま残し、変わるのはアドレスだけです。フローティングIPの再割り当てがこれにあたり、多くのプロバイダーではゲスト側は何も気づきません。変換がインスタンスの手前で行われるからです。再構築やプロバイダーによる再割り当てはより厳しく、ゲストが変化を見て、古い値を持っていたすべてが同じ瞬間にそれを知ります。
並行エンドポイントは、同じ仕事をする二台目のホストです。構築し、一つのプロファイルで試し、新しい側が実際の経路で自らを証明するまで古い側に応答させておきます。代償は状態です。ピアの登録、失効、ログを共有しなければ、たまたま名前を共有する二つのネットワークができるだけです。
| Question | In-place swap | Parallel endpoint |
|---|---|---|
| Rollback in one step? | Only if you can get the old address back | Point DNS back; old host still up |
| Blast radius | Every client at once | Only the clients you moved |
| Best when | The address is yours to reassign | The old address is gone for good |
古いアドレスが書かれている場所をすべて見つけます
まずテキスト検索から始めます。設定ファイルは簡単な半分だからです。デーモンの設定、ファイアウォールの断片、監視対象、ディスク上に生成されたクライアントバンドルを検索します。IPv6アドレスを公開しているならそれも含めます。Aレコードだけを追う移行は、デュアルスタックのクライアントを古い経路に残します。
OLD=203.0.113.10
grep -RIn -- "$OLD" /etc /root
ss -lunpt | grep -F "$OLD"
nft list ruleset | grep -F "$OLD"
iptables-save | grep -F "$OLD"
wg show all endpoints
次にカーネルを調べます。稼働中のシステムは、どのファイルにも書かれていない場所にアドレスを保持しています。静的な送信元NATのルール、ipsetのエントリ、バインドアドレス、conntrackのエントリは、それらを消した設定変更より長く生き、保存されたルールセットから戻ってくるため再起動も生き延びるものがあります。さらに上の層では、プロバイダーのセキュリティグループ、ロードバランサーのターゲット、監視チェックはあなたのファイルシステムにはまったくありません。
何かを変える前に棚卸しを書きます。これはロールバック用のスクリプトにもなります。
ホスト名のクライアントは回復し、リテラルIPのクライアントは沈黙します
クライアントがホスト名でサーバーに到達するなら、カットオーバーは主にDNSの問題であり、昨日設定したTTLがどれだけ悪化するかを決めます。リゾルバーはキャッシュし、スタブリゾルバーもさらにキャッシュし、多くのクライアントは新しい接続でしか名前を引かないため、確立済みのトンネルは開始時のアドレスを保ちます。
エンドポイントがリテラルアドレスなら、何も再解決せず、何も苦情を記録しません。WireGuardは解決済みのソケットアドレスを保存します。Endpoint = vpn.example.net:51820 は wg-quick up が走った瞬間にIPになり、変更するまでそのIPのままです。OpenVPN はより寛容で、接続時に remote のホスト名を解決し、resolv-retry infinite があれば再接続時に再びDNSを試します。リテラルIPの場合、どちらも存在しないマシンに接続し続けます。
人を惑わせるのは鏡像です。古いリスナーがまだ応答している間に新しいアドレスへ向けられたクライアントは、自分の机から行うあらゆるテストに合格します。私もこれに騙されました。新しいエンドポイントはスマートフォンで一発で上がり、古いプロファイルのクライアントは、古いリスナーをずっと後に止めたときに初めて姿を現しました。
信頼はアドレスとともに移りません
WireGuardは識別子と到達性を分けるため、アドレスの移行はほぼ無償です。ピアは公開鍵で識別され、エンドポイントは現在パケットが向かう先にすぎません。ホストは最後に認証されたパケットの送信元アドレスからピアのエンドポイントを更新します。待機中のピアはそれでも新しい場所と話す理由を必要とし、セッションが古くなりハンドシェイクの再試行が見える場所で失敗したときに初めてアドレスを学びます。WireGuardのクイックスタートがエンドポイントの項目を扱っています。
TLSベースのサーバーは逆のケースです。証明書は名前に結びつけられ、アドレスに接続するクライアントは接続先をサブジェクトの代替名と比較します。DNSのSANだけを持つ証明書にIPで接続すると検証は失敗します。クライアントが使った名前が証明書にないからです。IPのSANで再発行すればその一つの接続は直りますが、次の移行は悪くなります。プロファイルにホスト名を残し、verify-x509-name をそのままにしておけば、下のアドレスが変わっても検証は厳格なままです。
次にデーモンが何に束縛されているかを確認します。古いアドレスに固定されたソケットは静かに失敗します。local 203.0.113.10 で起動したOpenVPNサーバーは、そのアドレスが消えると上がるのを拒みます。一方、0.0.0.0 で待ち受けるリスナーは変化に無料で追随します。NATも同じように分かれます。MASQUERADE はマシンが今持つアドレスに従い、静的な SNAT --to-source 203.0.113.10 はもう所有していないアドレスへ書き換え続けるため、戻りの通信が消えます。新しいアドレスが別の上流ゲートウェイを伴うなら、rp_filter を確認します。逆経路フィルタリングは、カーネルが想定していないインターフェースに届いた戻り通信を落とします。
カットオーバーの順序と、それが機能した証拠
TTLを一日前に下げ、新しいリスナーを立て、自分だけが持つプロファイルで証明します。同じネットワークの内側からのテストはほとんど何も証明しないので、携帯回線のスマートフォンを使い、エンドポイントへのpingではなくトンネルが運ぶべきものを試します。
ウィンドウ全体で両方のアドレスを監視します。新しいホストの wg show all latest-handshakes 、またはOpenVPNのステータスファイルが、実際に何人のピアが移ったかを教えます。新しいエンドポイントに期待どおりのピアがあり、古い側に取り残しだけがいるなら、古いリスナーを退役させ、古いNATルールを削除し、プロバイダーのファイアウォールからアドレスを外します。古いリスナーの削除こそが飛ばされがちな手順であり、古いプロファイルがまだ古いネットワークに届く隙間を閉じます。
始める前にロールバックの引き金を文書で決めます。合意したウィンドウの後に新しいエンドポイントが実在のクライアントから一つもハンドシェイクを得られなければ、古いアドレスに戻し、プロファイルの配布を止めます。その後でもう一度検索を実行し、退役したアドレスに束縛されたリスナーが残っていないことを確認します。次の移行に持ち越すのは二つです。クライアントプロファイルにホスト名を入れて次の変更をDNSの編集にすること、そしてサーバーの復旧メモの隣に棚卸しを保管することです。