デフォルトのルーティングテーブルが障害となる時
2つの異なるクライアントからVPN接続を要求されたものの、両方が 192.168.1.0/24 という同じIPレンジを使用していた、という経験はありませんか?通常、Linuxカーネルは1つのメインルーティングテーブル(Main Routing Table)のみを保持します。eth0からトンネルまで、すべてのインターフェースがここを参照してパケットを転送します。IPが重複すると、サーバーはパケットを誰に返すべきか判断できず、完全に迷走してしまいます。
以前は、ip rule と組み合わせたポリシーベースルーティング(PBR)を使用していました。しかし、システムが50や100のクライアント規模になると、数百行ものルールを管理することはまさに悪夢です。ルーティングエラーのデバッグには、膨大な時間がかかってしまいます。
VRF(Virtual Routing and Forwarding)は、この問題を根本的に解決するために登場しました。これは独立した仮想ルーティングエンティティを作成します。VRFは、レイヤー2におけるVLANの分割と同じように、レイヤー3のルーティングテーブルを分割するものだと考えてください。
実践的な比較:PBRとVRF
適切なツールを選択するために、現在最も一般的な2つのアプローチの違いを明確にしましょう:
1. ポリシーベースルーティング (PBR)
- 仕組み: 流入するパケットの内容(ソースIP、ポートなど)を検査し、対応するルーティングテーブルに割り当てます。
- 弱点:
ip ruleの設定が重複しやすく、インターフェースレベルで完全に隔離されているわけではありません。ルールが増えるほど、パケット処理のパフォーマンスに影響が出ます。
2. VRF (Virtual Routing and Forwarding)
- 仕組み: インターフェースを「VRFデバイス」に固定で割り当てます。各VRFはシステム全体から完全に切り離された、独自のルーティングテーブルを保持します。
- 強み: 完璧な隔離。プロセスはVRF内で独立して動作でき、他のネットワークの存在を意識することはありません。
実環境でのVRF導入ステップ
開始するには、Linuxカーネル 4.3以降が必要です。現在のUbuntu 22.04やRHEL 9などの主要なディストリウルーションでは、十分にサポートされています。この例では、tenant-A と tenant-B の2つのVRFを作成します。
ステップ1:VRFモジュールの有効化
まず、カーネルに必要なモジュールがロードされているか確認します:
sudo modprobe vrf
# 再確認
lsmod | grep vrf
ステップ2:VRFデバイスの初期化
Linuxにおける各VRFは、仮想的な「親」インターフェースとして機能します。各VRFを識別するために、一意のテーブルID(Table ID)を割り当てる必要があります。
# テナントA用のVRFを作成 (テーブル 10)
sudo ip link add vrf-a type vrf table 10
sudo ip link set vrf-a up
# テナントB用のVRFを作成 (テーブル 20)
sudo ip link add vrf-b type vrf table 20
sudo ip link set vrf-b up
ステップ3:インターフェースの割り当てとIP重複の処理
ここが最も重要な部分です。eth1をテナントAに、eth2をテナントBに接続すると仮定します。多くのテナント向けにサブネットを細かく計算する必要がある場合は、ネットワーク設定やブロードキャストアドレスのミスを防ぐために IP Subnet Calculator を活用することをお勧めします。
# テナントAの設定
sudo ip link set dev eth1 master vrf-a
sudo ip addr add 192.168.1.1/24 dev eth1
sudo ip link set eth1 up
# テナントBの設定(同じIPレンジを使用しても問題なく動作する)
sudo ip link set dev eth2 master vrf-b
sudo ip addr add 192.168.1.1/24 dev eth2
sudo ip link set eth2 up
ステップ4:独立性の確認
この時点では、通常の ip route コマンドにはテナントのIPレンジは表示されません。個別のルーティングテーブルを確認するには、VRF名を明示的に指定する必要があります:
# テナントAのルーティングを確認
ip route show vrf vrf-a
# またはテーブルIDを直接指定して確認
ip route show table 10
VRF内でのアプリケーション実行方法
設定完了後、「ping が通らない」という相談をよく受けます。その原因は、デフォルトのコマンドが常にメインルーティングテーブル(Main Table)で実行されるためです。
Pingコマンドの実行
テナントAの接続を確認するには、対応するVRF経由でpingを実行するように強制する必要があります:
# テナントAのIP 192.168.1.100へPingを送信
ping -I vrf-a 192.168.1.100
サービスの運用 (Nginx, SSH, Python)
ip vrf exec は非常に強力な仕組みです。これにより、特定のVRFのコンテキスト内でプロセスを起動できます。
# テナントB専用のWebサーバーを起動
sudo ip vrf exec vrf-b python3 -m http.server 8080
その結果、eth2から接続するクライアントのみがポート8080にアクセスできるようになります。テナントAのクライアントは、たとえ同じIPレンジであっても、完全に遮断されます。
VRFを使用する際の重要な注意点
実際の導入プロセスを通じて得られた、特に注意すべき3つのポイントを挙げます:
- Localhostの問題: VRF内のサービスが
127.0.0.1に接続できないことがあります。net.ipv4.tcp_l3mdev_accept = 1を有効にすることで、各VRFに手動でバインドすることなく、すべてのVRFでサービスをリッスンできるようになります。 - DNS解決: DNSサーバーがメインルーティングテーブルにある場合、VRF内のプロセスはドメイン名を解決できません。各VRFに個別のDNSサーバーを配置するか、VRF間ルーティングを設定する必要があります。
- Iptablesの罠: VRFデバイスを通過するパケットは、PREROUTINGとPOSTROUTINGのチェーンを2回通過します。パケットが不当にドロップされないよう、ファイアウォールルールを注意深く確認してください。
おわりに
VRFは、単にルーティングテーブルを分離するためだけに仮想マシンやコンテナを乱用することに代わる、完璧なツールです。このアプローチにより、インフラはより透明性が高く、安全で、拡張しやすくなります。マルチテナント向けのゲートウェイやVPNを構築している場合は、ネットワーク管理を簡素化するために、ぜひ今すぐVRFを導入してみてください。

