ノート PC は接続し、トンネルも上がっているのに、内部サービスへのリクエストは接続のところで止まる。サービス側では、リクエストは 10.90.0.25 のようなアドレスから届き、応答はデフォルトゲートウェイへ向かって出ていき、何も戻ってこないのは、そのゲートウェイが 10.90.0.25 の在り処を知らないからだ。反対側から見ると、同じ不具合は接続中のクライアントに ping できない内部ホストのように見える。どちらも欠けているものは一つで、VPN クライアントプールへの戻り経路であり、これを追加できるのはプライベートネットワークだけだ。

サービスが見る送信元アドレスを読む

その一つのフィールドが他のすべてを決める。内部サービスがプールのアドレスを見ているなら、Access Server はクライアントの通信を隠しているのではなくルーティングしており、すべての応答をプールへ戻す経路が必要になる。逆にサーバー自身のプライベートアドレスを見ているなら、サーバーはマスカレードしており、戻り経路はすでに機能しているが、その代わり、サービスのログやアクセスルールからクライアントごとの識別情報が失われる。

何かを変える前に両端を比較する。サーバーではトンネルのインターフェースとそのアドレスを一覧にし、クライアントでは実際にどのアドレスを保持しているかを確認し、内部ホストでは確立中の接続を見る。

ip -br addr show
ss -tnp state established '( dport = :443 )'
ip route get 10.90.0.25

壊れたケースで失敗するのは最後のコマンドで、トンネルのプレフィックスを到達不能と報告するか、さらに悪いことにデフォルトゲートウェイを返し、そうして応答はインターネットへ出てしまう。

プールは一つだけと決めつけない。サーバーには動的範囲に加えてユーザーごとの静的マッピングがあり得るし、静的アドレスは動的プレフィックスの完全に外側にあることもある。覚えている範囲だけをルーティングすると、固定アドレスのユーザーは壊れたままで、他の全員が問題は解決したと報告する。

応答が決まる場所に経路を追加する

経路は、内部サービスがすでに使っているゲートウェイに置くものであって、サービス自身が自分の通信をルーティングしない限りサービス側ではない。宛先は Access Server の到達可能なプライベートアドレスで、クライアントが保持するトンネルアドレスとは別の値だ。

ip route add 10.90.0.0/24 via 10.0.1.5
ip route get 10.90.0.25

クラウドネットワークでは、同じ記述がルートテーブルのエントリになり、その対象はサーバーを実行しているインスタンスやネットワークインターフェースで、そのインターフェースでは送信元と宛先のチェックが無効になっており、そのエントリが何をしないかに注意してほしい。経路はアクセス許可ではないので、セキュリティグループ、ネットワーク ACL、ホストのファイアウォールが依然として通信を許可する必要がある。

経路を永続化し、プールのサイズを正直に保つ。隣接しない二つのプールには二つの経路が必要で、設定されたプレフィックスを超えて成長するプールは、応答の行き先がないクライアントを静かに生み出す。プールの範囲を管理しているなら、一度ルーティングして放置できる集約を選ぶ。

転送とフィルターは経路と一致させる

ルーティングは経路の半分にすぎない。サーバーはトンネルとプライベートインターフェースの間で転送できる必要があり、Linux では net.ipv4.ip_forward と、そのインターフェースの組を許可する転送チェーンを意味し、強化されたホストでは通常、方向ごとに明示的なルールが必要だ。

sysctl net.ipv4.ip_forward
nft list ruleset | grep -A5 forward

ステートフルなフィルタリングは、人を間違った道へ導く症状を説明する。確立済みのフロー内の応答には新しい受信ルールは不要なので、SYN-ACK の後に止まる接続は、受け入れルールの欠落でブロックされているのではなく、破棄されるか誤ってルーティングされている。この区別を保つことが、ルーティングの変更とファイアウォールの変更を切り分ける。

非対称な戻り経路は、同じ問題のより静かな形だ。二つの経路がプールに届き、応答がリクエストの到着したインターフェースとは別のインターフェースから出る経路を選ぶと、厳密な逆経路フィルタリングがそれを破棄し、一部のクライアントだけでフローが失敗する。

ルーテッドかマスカレードか、意図して選ぶ

ルーテッドモードはサービスの側でクライアントのプールアドレスを保つので、クライアント単位のログ記録とポリシーが可能になるが、その代わり、クライアントに応答する必要のある内部ネットワークはすべてプール経路を必要とする。マスカレードモードは応答がサーバーに戻るためその要件を取り除くが、サービスはもはやクライアント同士を区別できず、特定のクライアントへ何かを開始することもできない。

稼働中のサーバーでこの動作を変えると既存のセッションが切れるので、まず一つのクライアントと一つのフローで試す。切り替えが正解なら、それはサーバー側の設定判断であり、後で不要になる経路を足して回避するものではない。

クライアント背後のサブネットは別の作業

ノート PC 自身の LAN にある機器へ到達する はノート PC のトンネルアドレスへ到達することとは違う。クライアントがサブネットゲートウェイとして動作する必要があり、クライアント側で宣言されたネットワーク、クライアントの OS で有効化された転送、その LAN からクライアントへ戻る経路が要る。ノート PC の自宅側の範囲にプライベートネットワーク経路を追加してもこれは実現せず、二人のユーザーが同じ自宅範囲を持つと競合する。

方向もポリシーの問題だ。クライアントが内部サービスへ接続を開く許可は、内部ホストがそのクライアントへ接続を開く許可を自動的に与えるものではない。経路が壊れていると結論づける前に、サーバーのアクセスポリシーとクライアントのホストファイアウォールを確認する。

一つのフローと一つのキャプチャで確認する

一般的な到達性テストではなく、一つの接続で経路を証明する。同じフローを両端で、つまりサービスに届くリクエストとそこから出ていく応答を観察する。

tcpdump -ni any host 10.90.0.25 and port 443

修正前は、応答がルーティングしないゲートウェイへ向かって出ていく様子がキャプチャに映る。修正後は応答がサーバーへ向かって出ていき、フローが完了する。次に、カバーしていないプールが一週間後ではなく今見つかるように、二つ目のクライアントアドレスに対してゲートウェイが使う経路を確認する。

この件を締める四つの確認で終える。サービス側の送信元アドレスが意図したモードと一致していること、ゲートウェイが使用中のすべてのプールへの経路を持つこと、転送とフィルターが両方向を許可すること、実際のフローが端から端まで完了することを確かめ、Access Server のルーティングに関するよくある質問 はインストール済みリリースについて同じ原則を示しており、そのサポートされる設定インターフェースは古いガイドと異なる場合がある。

関連記事