VPNゲートウェイの「死」と「蘇生」:HA構成でセッション断を極限まで減らす技術論
VPNゲートウェイは、エンタープライズネットワークの「喉元」です。ここが詰まればWeb APIは叩けず、リモートワークの社員は路頭に迷う。そんなクリティカルなインフラにおいて、単一障害点(SPOF)を放置するのは、運頼みのギャンブルに等しい。
今日は、VPNゲートウェイのHA(High Availability)構成、特に「いかにしてシームレスにアクティブ・スタンバイを切り替えるか」という、現場泣かせのテーマに深く切り込んでいこう。教科書的な冗長化の話ではなく、パケットが落ちる瞬間の「あの嫌な沈黙」をどう防ぐか、その泥臭い現実を語る。
—
1. 冗長化の黄金律:VRRPの限界と「同期」の重要性
VPNゲートウェイの冗長化で最も一般的なのが VRRP(Virtual Router Redundancy Protocol)を用いた構成だ。仮想IP(VIP)を共有し、マスタ機がダウンしたらバックアップ機がVIPを引き継ぐ。
しかし、ここで忘れてはならないのが「セッション情報の同期」だ。
単純な VRRP 切り替えだけでは、VPNの暗号化トンネル情報(IPsec SA/IKE SA)はスタンバイ機に引き継がれない。結果、切り替わった瞬間にすべてのVPNトンネルが再ネゴシエーションを始め、通信が数秒から十数秒間、完全にブラックアウトする。APIリクエストはタイムアウトし、クライアントは接続をリセットされる。
これを防ぐためには、ゲートウェイ間で State Sync(セッション同期)を行う独自プロトコル(各ベンダーが実装しているハック)が必須だ。
—
2. 実践:HA構成の肝となる設定の勘所
例えば、Linuxベースのルーター(FRRouting等)で冗長化を考える場合、keepalived を使うのが定石だ。以下に、最低限押さえておくべき keepalived.conf のエッセンスを記す。
! VRRP設定例
vrrp_instance VI_1 {
state BACKUP ! 基本はBACKUPで動かし、優先度でマスタを決める
interface eth0 ! 監視対象のインターフェース
virtual_router_id 51
priority 100 ! マスタは150、バックアップは100にするのが鉄則
advert_int 1 ! 1秒間隔で死活監視(負荷と検出速度のトレードオフ)
virtual_ipaddress {
192.168.10.1 ! VPNゲートウェイのVIP
}
! フェイルオーバー時に叩くスクリプト
notify_master "/usr/local/bin/sync_session_start.sh"
notify_backup "/usr/local/bin/sync_session_stop.sh"
}
ここで重要なのは advert_int の値だ。ネットワークが混雑している環境でこれを短くしすぎると、パケットロスによる「誤検知の嵐」が起き、フラッピング(マスタとバックアップが切り替わり続ける現象)が発生する。現場では、1秒をベースにしつつ、回線の安定度を見て微調整するのがセオリーだ。
—
3. アプリケーション視点:VPN断をどう「吸収」するか
どれほど完璧なHAを組んでも、数ミリ秒〜数百ミリ秒の瞬断は避けられない。Web API設計において、VPN経由の通信がこの瞬断を食らったとき、どう振る舞うべきか。
一番の悪手は「エラーをそのままユーザーに返す」ことだ。クライアントサイド(例えば Python の requests や Fetch API)で、リトライ(指数バックオフ)を実装しておく必要がある。
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
# 瞬断を考慮したリトライロジック
def get_api_with_retry(url):
session = requests.Session()
# 500系エラーやコネクションエラー時に最大3回リトライ
retries = Retry(total=3, backoff_factor=1, status_forcelist=[502, 503, 504])
session.mount('https://', HTTPAdapter(max_retries=retries))
try:
response = session.get(url, timeout=5)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"VPNの揺らぎ?リトライしてもダメでした: {e}")
この backoff_factor=1 という設定が重要だ。VPNゲートウェイが切り替わっている最中に爆速でリトライを繰り返すと、ゲートウェイにさらに負荷をかけ、事態を悪化させる。少しずつ間隔を空けて様子を見る、この「配慮」が堅牢なインフラを作る。
—
4. 現場の教訓:デバッグ手順の極意
もしVPNの切り替えで通信が死んだら、まずは以下の順序でパケットの足跡を追え。
1. VIPの所在確認: ip addr show でVIPがどちらの機体に浮いているか確認する。
2. ARPテーブルの確認: ネットワークスイッチ側で、VIPのMACアドレスが切り替わった後のノードに正しく紐付いているか show arp で見る。これ、意外とスイッチの学習待ちで詰まることが多い。
3. SA(Security Association)の生存確認: ip xfrm state(Linuxの場合)を叩き、トンネルが確立されているか確認する。
「設定したから大丈夫」という慢心は禁物だ。深夜のメンテナンス時にフェイルオーバーを実際に発生させ、どれくらいの通信ロスが発生するか、ping を叩きながら目で追う。その泥臭い検証の積み重ねだけが、トラブル対応の自信を形作る。
—
最後に:完璧を求めすぎない設計を
ゼロトラストの時代、VPNは「いずれ廃れる技術」とも言われる。しかし、現実のエンタープライズ環境では、まだまだレガシーなシステムを繋ぐための「生命線」だ。
VPNゲートウェイの冗長化は、100%の可用性を目指すものではない。「いかに素早く、かつ安全に復旧させるか」というリカバリーの速さが勝負だ。HA構成を組む際は、切り替わった瞬間の挙動を、アプリケーション側がどう許容するか。その両面からの設計を忘れないでほしい。
現場のエンジニア諸君、パケットの行方に常に疑いの目を持ち続けよう。それが、最強の防衛線への第一歩だ。
コメント