バックアップを復元し、サービスが起動し、クライアントは最初の試行で接続した。その成功こそ罠である。復元が返すのはスナップショット時点でサーバーが持っていたファイルであり、その後変化したアクセス状態ではない。古いエンドポイントがまだ到達可能なら、いま一つの同一性に応答するマシンが二台ある。解決策はより良いバックアップではなく、一つのハンドシェイクに応答する前に復元されたホストが何であるべきかを決めることだ。

バックアップが返すのはファイルであり、権限ではない

スナップショットには、バックアップ実行時点のサーバー設定、秘密鍵、認証局、ピア一覧、ファイアウォール規則が入っている。その後変更されたものは入らない。失効させた端末、再発行した鍵、ノート PC を売ったときに外したピア、移設したサブネットである。復元はファイルをその時点に巻き戻す。人々がその後下した判断は巻き戻さない。

被害はまさにこの隙間から生じる。バックアップの二週間後に失効させた盗難ノート PC は、復元されたツリー内の古い CRL に対してなお検証が通る証明書を提示し、サーバーは引退させた端末を受け入れる。WireGuard はさらに直接的だ。ピアは一覧に載っていることで認可されるため、スナップショット後に削除したピアは単に再び存在する。誰もそのアクセスを再承認していない。古いファイルが承認したのだ。

サーバーの同一性とクライアントの同一性は別の形で破綻する

WireGuard ではサーバーの同一性は wg0.conf の秘密鍵であり、そのファイルを二台目の到達可能なホストにコピーすると、同じ同一性を持ち互いを知らないサーバーが二台できる。それぞれが独自のピア一覧を保つ。新しいホストでピアを外しても古い方は受け入れ続ける。片方で wg show を確認すれば真実の半分しか見えない。クライアントも勝手に切り替わらない。プロファイルは Endpoint を一つ持つため、端末は設定されたアドレスと話し続け、それが引退させたかったホストであることもある。

OpenVPN は同じ層で、サーバー証明書、その秘密鍵、tls-auth または tls-crypt の静的鍵によって重複する。三つともコピーすればクライアントはインスタンスを見分けられない。両方が到達可能なら再接続はどちらに着地してもおかしくなく、各ログは部分的な物語しか語らない。認証局こそより深い複製だ。復元された easy-rsa ツリーは第二の真実の源であり、与えた任意の名前に対して有効な証明書を発行できる。

クライアントも重複する。多くは移行作業そのものの最中だ。予備端末へ「試すだけ」でプロファイルをコピーすると、同じ鍵と同じコモンネームを持つ二台目ができる。duplicate-cn があれば二つのセッションが同時に立ち続けられ、ccd や ifconfig-pool-persist の静的アドレス割り当てが元の端末と衝突しうる。同じ同一性をまとった二台のマシンであり、サーバー設定のどこにも両者を区別するものはない。

古いエンドポイントには三つの状態から一つを選ぶ

復元が安全になるのは、古いエンドポイントの行く末を決めてからだ。引退させる場合、新しいホストが起動する前に古いサービスが VPN ポートの受け付けを止めねばならず、マシンに到達できないならそのポートをネットワーク境界で管理元以外に遮断する。同じホストを修理する場合、一台が同一性を保持するので再利用は問題ないが、その後で古い鍵のディスク複製や VM スナップショットを破壊し、戻らないようにする。可用性ペアを組む場合、二台のホストには別々のホスト同一性と、共有された一つのエンドポイント(フローティングアドレス、ロードバランサー、動かせる DNS など)が要る。秘密鍵のコピーはフェイルオーバー設計ではなく、一つの名前を主張する二つのサーバーにすぎない。

クライアントに触れる前に、実際にどの状態にあるかを確認する。VPN ポートで応答している古いホストこそが、DNS が移っていても失効端末を受け入れる側だ。リスナーと公開鍵を確認する。

ss -lunp | grep -E ':51820|:1194'
wg show wg0
wg pubkey < /etc/wireguard/server.key

まずピア、失効、アドレスを突き合わせる

復元が主張する内容と現在認可されている内容を並べる。WireGuard では wg show wg0 が各ピアの鍵、エンドポイント、最終ハンドシェイク、転送カウンターを示し、もう所有していない端末を見つけるのに足りる。wg set wg0 peer <key> remove で稼働中に外し、その後設定も編集する。さもなければ次の起動でピアが戻る。wg show wg0 allowed-ips は第二の問題を暴く。一つのアドレスに二つのピア、あるいはすでに再割り当てしたアドレスだ。

OpenVPN では失効リストは日付を持つファイルであり、復元は古いものを戻しうる。クライアントが接続する前に確認する。

openssl crl -in /etc/openvpn/crl.pem -noout -lastupdate -nextupdate
grep -E 'crl-verify|reneg-sec' /etc/openvpn/server.conf

最終更新が失効より前なら、サーバーは失効させた証明書をいまだに尊重している。OpenVPN 2.4 以降は新しい接続ごとに CRL ファイルを読み直すため、ファイルを差し替えれば新規セッションは止まるが、確立済みのトンネルは再交渉まで続く。reneg-sec の既定値は 3600 秒で、これを下げるかサービスを再起動することが今すぐ変更を効かせる方法だ。古いビルドはファイルをそこまで確実に取り込まないことがあるので、その版の挙動を確認できないときは再起動する。上で使ったピア削除と allowed-ips の構文は wg(8) のマニュアル が扱っている。

もう存在しない端末の静的割り当ても片付ける。古いプロファイルが入ったまま、引退端末のアドレスを新しい端末に再利用すると、避けたい重複がそのまま生まれる。

失効させたクライアントで検証する

トンネルの外のネットワークから、順番に検査する。まず認可された端末が接続し、プッシュされたリゾルバーで DNS を解き、プライベートなリソースに届く。次に失効端末は、新しいプロファイルではなく既存のプロファイルで失敗しなければならない。そして外から古いエンドポイントを試す。VPN ポートがまだハンドシェイクを完了するなら、古いホストは生きており、重複は理論ではなく現実だ。

復元したホストを再起動し、認可と失効の検査を繰り返す。設定ファイルが実行中に変えたものを上書きするのはそのときだからだ。ホストの公開鍵または証明書指紋を、引退したマシンが使っていたものと比べる。二台の稼働マシンで指紋が一致するなら復元が同一性を複製したということだ。一台だけの一致は問題ない。復元した版、鍵の指紋、失効したシリアル番号またはピア鍵を記録し、この突き合わせの後に次のバックアップを取る。そうすれば今のサービスを表す。機能する試験は、クライアントが接続することではない。外したクライアントが外に留まり、古いエンドポイントが閉じたままであることだ。

関連記事