Linux上でstrongSwanとOpenNHRPを用いたDMVPNの構築:動的Spoke-to-Spoke VPNアーキテクチャ

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

課題:従来の拠点間VPNにおけるハブのボトルネック

ブランチオフィスと本社間の接続は、通常、静的な拠点間(Site-to-Site)IPsecトンネルの構築から始まります。Spoke AからHubへ、そしてSpoke BからHubへと個別にトンネルを張る構成です。各拠点が中央の給与計算サーバーやデータベースサーバーにのみアクセスする環境であれば、この構成でも問題ありません。しかし、拠点間のSIPトランキング、リアルタイムのデータベースレプリケーション、rsyncバックアップジョブなど、拠点同士が直接通信する必要が生じた瞬間に問題が表面化します。

例えば、フランクフルトのSpoke Aから東京のSpoke BへVoIP通話を発信する場合を考えてみましょう。すべての音声パケットは、まずパブリックインターネットを経由してバージニア州にある中央のHubへ送られます。Hubでペイロードを復号し、ルーティングテーブルを参照した上で再暗画化し、太平洋を越えてSpoke Bへと転送されます。この「ヘアピン現象(Hair-pinning)」により、本来なら直接通信で往復210ミリ秒程度で済むレイテンシが430ミリ秒にまで跳ね上がり、同時にHubゲートウェイの上り帯域を大幅に消費します。

全拠点間にフルメッシュの静的IPsecトンネルを構築すればヘアピン現象は回避できます。しかし、そのスケーリングコストはO(N²)と極めて過酷です。わずか50のブランチオフィスを接続するだけでも、1,225本もの独立したIPsec設定が必要になります。IPアドレスの変更やサブネットの変更が1つ発生しただけでも、運用管理は破綻してしまいます。

基本概念:LinuxにおけるDMVPNの仕組み

Cisco社は、トンネルのエンドポイントを固定パブリックIPアドレスから分離するためにDMVPN(Dynamic Multipoint VPN)を開発しました。Linux環境では、高価なプロプライエタリハードウェアやエンタープライズ向けSD-WANライセンスは不要です。以下の3つのモジュール型コンポーネントを組み合わせることで、全く同じ動的メッシュを実現できます。

  • Multipoint GRE (mGRE): 標準的なGREはポイントツーポイントのリンクを作成するため、対向ピアごとに個別の仮想インターフェースが必要です。これに対してmGREは、単一のトンネルインターフェース(gre1など)を使用して、何百もの任意のパブリックエンドポイントからのトラフィックを動的に終端します。
  • Next Hop Resolution Protocol (NHRP): opennhrpによって処理され、オーバーレイネットワークにおけるARPのように機能します。SpokeはNext Hop Server(NHS:通常はHub)に対して自身のパブリックIPアドレスを登録(チェックイン)します。Spoke AがSpoke BのLAN宛てにパケットを送信したい場合、Hubに対してSpoke Bの実際のパブリックIPを問い合わせ、オンデマンドで直接のオーバーレイリンクを確立します。
  • IPsecトランスポートモード: すべてのGREトラフィックを暗号化するためにstrongSwanを採用します。オーバーレイのルーティングとアドレッシングはすでにmGREヘッダーによって処理されているため、IPsecはトンネルモードではなく軽量なトランスポートモードで動作します。これにより、パケットごとのヘッダーオーバーヘッドを従来の56バイト以上から約36バイトへと削減できます。

実践:検証環境の構築

HetznerとAWSにまたがる異種ベアメタル環境を相互接続する場合でも、動的IPで運用されているリモートのエッジゲートウェイを接続する場合でも、この構成であれば高価なハードウェアを導入することなく、堅牢かつベンダー非依存のメッシュネットワークを構築できます。

1. ネットワークトポロジとアドレス設計

Debian 12またはUbuntu 24.04 LTSを実行する3台のLinuxホストを設定します。

  • Hub (NHS): パブリックIP 198.51.100.1、VPNオーバーレイIP 10.255.255.1/24
  • Spoke 1: パブリックIP 203.0.113.10、VPNオーバーレイIP 10.255.255.10/24、LAN 192.168.10.0/24
  • Spoke 2: パブリックIP 203.0.113.20、VPNオーバーレイIP 10.255.255.20/24、LAN 192.168.20.0/24

2. 必要なパッケージのインストール

まず、3台すべてのインスタンスにstrongSwan、ルーティングユーティリティ、OpenNHRPをインストールします。その後、IPv4パケット転送を有効化します。

sudo apt-get update
sudo apt-get install -y strongswan strongswan-pki opennhrp iproute2

# カーネルでパケット転送を有効化
sudo sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.d/99-dmvpn.conf

# 動的インターフェースでのドロップを防ぐためリバースパスフィルタリングを無効化
sudo sysctl -w net.ipv4.conf.all.rp_filter=0
sudo sysctl -w net.ipv4.conf.default.rp_filter=0

3. GREトラフィック保護のためのstrongSwan設定

mGREはトラフィックの発生に応じて動的に対向SpokeのIPをターゲットにするため、strongSwanには固定ピア定義ではなくワイルドカードトランスポートポリシーが必要です。Hubおよび両Spokeで/etc/ipsec.confを開きます。

# HubおよびSpoke共通の /etc/ipsec.conf
config setup
    charondebug="ike 1, knl 1, cfg 1"

conn %default
    keyexchange=ikev2
    ike=aes256-sha256-modp2048!
    esp=aes256-sha256!
    type=transport
    dpdaction=restart
    dpddelay=30s
    auto=route

conn dmvpn-gre
    left=%defaultroute
    leftprotoport=gre
    right=%any
    rightprotoport=gre
    authby=secret

全ノードの/etc/ipsec.secretsに共通の事前共有鍵(PSK)を設定します。

# /etc/ipsec.secrets
: PSK "RobustSharedKeyForDMVPN_2026"

設定を反映します:sudo ipsec restart

4. Hub(Next Hop Server)の設定

キーID 1234を指定してHub上にmultipoint GREインターフェースを作成します。

sudo ip tunnel add gre1 mode mgre key 1234 ttl 64
sudo ip addr add 10.255.255.1/24 dev gre1
sudo ip link set dev gre1 up

続いて、静的なマッピングファイルなしで名前解決リクエストに応答できるよう、Hubの/etc/opennhrp/opennhrp.confを設定します。

# Hubの /etc/opennhrp/opennhrp.conf
interface gre1
    holding-time 7200
    multicast dynamic
    shortcut
    redirect

NHRPデーモンを起動します:sudo opennhrp -d

5. Spoke 1およびSpoke 2の設定

Spoke 1でmGREインターフェースを立ち上げます。

sudo ip tunnel add gre1 mode mgre key 1234 ttl 64
sudo ip addr add 10.255.255.10/24 dev gre1
sudo ip link set dev gre1 up

Spoke 1のOpenNHRPデーモンが自身のWANアドレスをHubに登録するように設定します。

# Spoke 1の /etc/opennhrp/opennhrp.conf
interface gre1
    map 10.255.255.1/24 198.51.100.1 register
    holding-time 3600
    shortcut
    redirect

同様の設定をSpoke 2でも行い、インターフェースアドレスを10.255.255.20/24に変更します。設定後、両Spokeでデーモンを起動します:sudo opennhrp -d

6. 動的Spoke-to-Spoke接続の検証

両Spokeが自身のパブリックNBMAアドレスをHubに正しく登録できているか確認します。

hub$ sudo opennhrpctl show
Type: local, IP: 10.255.255.1/32
Type: dynamic, IP: 10.255.255.10/32, NBMA: 203.0.113.10, flags: registered
Type: dynamic, IP: 10.255.255.20/32, NBMA: 203.0.113.20, flags: registered

Spoke 1からSpoke 2のトンネルIPに向けてトラフィックを送信します。

spoke1$ traceroute 10.255.255.20

内部では以下のシーケンスが実行されます。第1パケットはHub(10.255.255.1)を経由します。OpenNHRPが2つのSpoke間の通過トラフィックを検知し、Spoke 1へNHRP Redirectを送信します。Spoke 1はNHRP Resolution Requestを送信し、Spoke 2のNBMAアドレス(203.0.113.20)を取得します。40ミリ秒以内にstrongSwanが203.0.113.10と203.0.113.20の間で直接IKEv2 SAをネゴシエーションします。第2パケット以降のすべてのトラフィックはHubを完全にバイパスし、わずか1ホップで直接転送されます。

まとめ

DMVPNは、運用のオーバーヘッドとネットワークレイテンシの間の厳しいトレードオフを解消します。何百本ものポイントツーポイントトンネルを保守する代わりに、各ノードは単一のmGREインターフェースを管理するだけで済みます。strongSwanがIPsecトランスポートモードを介して暗号化を処理し、OpenNHRPはアクティブなトラフィックが必要とした時にのみショートカットを確立します。

本構成を本番環境へ導入する際は、gre1オーバーレイ上でFRRouting(FRR)によるBGPまたはOSPFを実行することをお勧めします。これにより、Spoke間で直接パスが確立されるたびに、各拠点背後の内部サブネットが自動的にアドバタイズされコンバージェンスされます。

Share: