VPC Route Server の設定を一通りやってみた

記事タイトルとURLをコピーする

エンタープライズクラウド本部の三好です。

4 月の初めに VPC Route Server なる機能が VPC に追加されました。なんか面白そうな気がしたので一通り設定してみた記録となります。

aws.amazon.com

そもそも何のための機能なのか

What’s New の原文の一部とその翻訳を示します。

Prior to this feature, you had to create custom scripts or use virtual routers with overlay network to dynamically update VPC route tables. VPC Route Server removes the operational overhead of creating and maintaining overlay networks or custom scripts and offers a managed solution for dynamically updating routes in route tables.

[翻訳]

この機能を導入する以前は、VPCルートテーブルを動的に更新するために、カスタムスクリプトを作成したり、オーバーレイネットワークを備えた仮想ルーターを使用する必要がありました。VPC Route Serverは、オーバーレイネットワークやカスタムスクリプトの作成と維持に伴う運用上のオーバーヘッドを排除し、ルートテーブル内のルートを動的に更新するためのマネージドソリューションを提供します。

これについては AWS で IPS/IDS などの仮想アプライアンスを動かしたことのある方は、あ~ってなるかもしれません。

今まで困ってたケース

例えば下図のようにインターネットに向けての通信はすべて仮想アプライアンスを通すようにしたいと仮定します。

今まで困ってたパターン

仮想アプライアンス自体の可用性を確保するため、仮想アプライアンスを 2 台配備しようとは思いつくのですが、問題となるのが仮想アプライアンスをゲートウェイとして指定するサブネットのルートテーブルです。何が困るかというと、仮想アプライアンスの 1 号機側が障害が発生したとしても、2 号機は存在するだけであり、ルートテーブルは動的にアップデートされるわけではないので、トラフィックが切り替わらず結果、上記の図でいうとサーバーに関する通信について障害となります

物理機器であれば仮想IPアドレスを共有して~みたいなやり方がりますが、それらの仕組みは大抵 AWS のネットワークの仕様上実装できないことがほとんどです。このため、AWS 上で仮想アプライアンスの冗長性を、仮想アプライアンスをゲートウェイと指定するルートテーブル含めて完全自動で確保するためには個別の工夫が必要となります。例えば片系の障害が発生したら、それを検知して AWS Lambda でルートテーブルをアップデート、もしくは何らかの製品固有の実装(オーバーレイネットワークを構築)を利用する必要がありました。

今回のアップデートのいいところ

今回のアップデートでは、BGP で経路情報を仮想アプライアンスから VPC Route Server に伝搬することで、動的にルートテーブルの値を変更できるようになりました。これにより固有の実装ではなく、ネットワーク機器のよくある BPGのオペレーションで経路切り替え、制御ができるようになったというのがいいところになります。ネットワーク機器オペレーションの一貫性・保守性オペレーションという観点でよいアップデートなのかなと思います。

ルートテーブルを動的に更新してみよう

概要構成

用途的には AWS Marketplace の仮想アプライアンス(IIJ SEIL、Palo Alto VM-Series for AWS、pfSence など)を使うのが本来ではありますですが、機能的には eBGP が利用できれば良さそうなので仮想アプライアンス相当のものは次のもので準備します。

  • 仮想アプライアンス相当のもの
    • Amazon Linux 2023(Graviton) + GoBGP*1 で BGP をしゃべるやつ
    • フォワーディング設定はあまり本筋ではないので、ループバックアドレスを Linux に新たに設定してそこにめがけて ICMP echo/reply を CloudShell in VPC からできるようにします。今回は192.0.2.1 を利用します。

構成図は以下の通りです。

VPC Route Server 実験構成

Multi Exit Discriminator(MED) の値を 1 号機は 10, 2 号機は 100 として設定します。これにより平時は 1 号機を通過するようにします。

各EC2 インスタンスに付与するセキュリティグループは以下の通りです。

  • Inbound は ICMP と TCP を ローカル VPC (172.31.0.0/16) と ループバックアドレス 192.0.2.1 には許可する
  • Outbound は任意の通信を許可
  • すべてのインスタンスを同一セキュリティグループに属するようにする。

あくまで実験なので本番環境では要件に合わせて、必要なセキュリティグループを設定してください。ちなみに BGP は TCP/179 を利用します。

GoBGP の配置場所をパブリックサブネットにしていますが、wget で GoBGP を取得するためだけなので、プライベートサブネットでも eBGP が利用できるのであれば同様の構成をとることが可能です。本番では仮想アプライアンスを配備するセグメントのルートテーブルは要件に合わせて適切に設定してください。

仮想アプライアンスの設定(基本セットアップからGoBGP の起動確認まで)

まずは仮想アプライアンスの通信確認用のループバックアドレスとそれ関連の設定とツールのダウンロードを行います。

EC2 インスタンスの設定として標準から変えたところは、ネットワークの設定で変更できる「送信元/送信先チェック中」のところで、停止にチェックを付けるところです。通信を中継する仮想アプライアンスはそれ自身のインスタンスの ENI に付与されている IPアドレスとは別のIPアドレスに通信を中継するので、送信元 / 送信先チェックをしないようにする必要があります。今回はループバックアドレス、すなわち ENI についているアドレスとは異なる IPアドレスに通信するので、チェックしないように設定します。

ソース/宛先 チェックの設定1
ソース/宛先チェックの設定2

Amazon Linux 2023 は root ユーザーで設定をします。本番では適切なユーザで設定してください。 ループバックアドレスの設定は以下のとおり行いました。

ip addr add 192.0.2.1/32 dev lo

GoBGP は daemon と daemon のコントロール用の CLI ツールで構成されています。とりあえず wget してきて中身を確認します。Graviton の Amazon Linux 2023 を使うので ARM のバイナリを取得します。

cd # ホームディレクトリに移動
wget https://github.com/osrg/gobgp/releases/download/v3.36.0/gobgp_3.36.0_linux_arm64.tar.gz # ツールのダウンロード
mkdir bgptool # 展開先フォルダを作成
tar xvf gobgp_3.36.0_linux_arm64.tar.gz -C bgptool/ # アーカイブを展開する
ls ./bgptool # 中身を確認
cd bgptool # 以降 $HOME/bgptool でコマンド実行します。

1 号機と 2号機の gobgpd の設定をそれぞれ以下のようにします。gobgpd.conf という名称で保存します。

# 1号機の設定

[global.config]
  as = 65002
  router-id = "192.0.2.100"
# 2号機の設定

[global.config]
  as = 65003
  router-id = "192.0.2.200"
./gobgpd -f gobgpd.conf
./gobgp global
# route-id などが表示されれば OK

GoBGP の BGP ピアに対する設定をしたいところですが、BGP ピアである VPC Route Server を作らないと進まないのでここからが、 VPC Route Server の構築・設定になります。

VPC Route Server のセットアップ

公式チュートリアルがあります。BGP の理屈がわかっていれば、動かすだけならあまり難しいことはありません。ざっくりいうと以下の手順です。

  1. BGP ルートサーバーを作る
  2. どこのサブネットのテーブルを動的に更新するのか指定する。
  3. BGP をしゃべるインターフェースを作る
  4. 対向ピア(今回は GoBGP の IPアドレス)設定する。

上記はチュートリアルとは一部順番が異なります。筆者が試しながら触った順序であるので、公式チュートリアル順でも問題ありません。 BGP 経験者は Web UI で BGPのルートサーバー みたいなやつを設定してるみたいなものと思えば迷わないと思います。

VPC Route Server の作成

VPC のサービスに移動し、左ペインから「ルートサーバー」を押下し、ルートサーバーを作成を押下します。

VPC Route Server の作成

VPC Route サーバーの作成します。今回は動かすことが目的なのでとりあえず動く値を入れていきます。本番で利用する際はドキュメントを見て構築しましょう。

設定項目 設定値
名前 適切な名前
Amazon 側の ASN 65001
ルートを保持 無効化

VPC Route Server の作成

VPC Route Server 自体は瞬時に作成されます。

VPC Route Server と VPCとサブネットの紐づけ

VPC Route Server と VPC などのリソースを紐づけていきます。

VPC と VPC Route Server の関連付け1

接続する VPC をプルダウンメニューから選びます。使用する VPC を選択し「ルートサーバーを関連付ける」を押下します。

VPC と VPC Route Server の関連付け2

VPC への関連付けが成功した旨のメッセージが出てきます。伝播タブを押下し、伝播を有効にするを押下して、経路注入するルートテーブルを選択します。

経路を動的に入れるルートテーブルの関連付け1

VPC Route Server の関連付けと同じくサブネットを選択するプルダウンメニューが出てくるので、経路注入するプライベートサブネットを押下します。

経路を動的に入れるルートテーブルの関連付け2

成功すると以下のように有効化されたルートテーブルが表示されます。一度に一つしか設定できなさそうですが、ルートテーブルとの紐づけ自体は複数設定可能です。

経路を動的に入れるルートテーブルの関連付け3

VPC Route Server のエンドポイントのデプロイ

インターフェースとなるルートサーバーエンドポイントを作っていきます。「ルートサーバーエンドポイントの作成」を押下します。

ルートサーバーエンドポイントの作成1

サブネットを選択します。構成図の通り 2 つ作りますが、1 個づつ作成することになります。

ルートサーバーエンドポイントの作成2

作成後は自動的にルートサーバーピア(BGPを VPC Route Server に接続してくる側つまり GoBGP のサーバー)についての情報を入れる画面に移動します。

VPC Route Server の対向ピアの設定

「ルートサーバーピアを作成」を押下してください。

ルートサーバーピアの設定1

ルートサーバーピアの設定については アーキテクチャ図を見ながら入れていきます。

設定項目 設定値
名前 適切な名前
ルートサーバーエンドポイント ID 前手順で作成したルートサーバーエンドポイントを指定
ピアアドレス 仮想アプライアンスのeBGP の通信を行うインターフェースの IP アドレスを指定します。
ピアASN 仮想アプライアンス側に設定した AS 番号を入れます。このケースでは 65002 です。
ピアライブネス検出 BGP もしくは Bidirectional Forwarding Detection(BFD)で切断を検知します。今回は BGP を選択します。

ルートサーバーピアの設定2

作成が完了すると次のような表示になります。

VPC Route Server の設定のGoBGP1号機向け設定完了

仮想アプライアンスの設定(GoBGP で経路情報を入れて、ルートテーブルに経路が入ることを確認する)

VPC Router Server 側の設定が完了したので、GoBGP で経路を入れるための設定をしていきます。以下のようにやっていきます。

  1. 2 号機の BGP 経路情報設定を行う。紐づけたルートテーブルに 0.0.0.0/0 への経路が作成されて、2 号機の ENI が 0.0.0.0/0 のゲートウェイとして指定されることを確認する。
  2. 1 号機の BGP 経路情報設定を行う。紐づけたルートテーブルに 0.0.0.0/0 への経路について、1 号機の ENI が 0.0.0.0/0 のゲートウェイとして指定されることを確認する。

2号機から経路情報を広告する

まず最初に VPC Server 側の BGP ステータスとルートテーブルを確認します。 ルートサーバーピアの状態を見ると BGP ダウンとなっています。BGP そのものが期待するピア(GoBGP#2)からきていないことを示しています。

ルートサーバーピアの状態 - BGPステータスDown

プライベートサブネットの経路情報 - 0.0.0.0/0 のルートなし

VPC Route Server の GoBGP#2 と対応するエンドポイントに付与された IP アドレスを GoBGP#2 にて BGP ピア の IPアドレスとして設定します。 今回は 172.31.1.123 が ENI に指定されたのでそれを指定します。gobgpd.conf を以下のように編集してください。

[global.config]
  as = 65003
  router-id = "192.0.2.200"
[[neighbors]]
  [neighbors.config]
    neighbor-address = "172.31.1.123" # ここは環境で書き換えること
    peer-as = 65001

設定作成後 GoBGP#2 で gobpgd を起動します。起動した後にも操作するのでバックグラウンドに回します。

 ./gobgpd -f gobgpd.conf &
[1] 4908
sh-5.2$ {"level":"info","msg":"gobgpd started","time":"2025-04-03T13:59:22Z"}
{"Topic":"Config","level":"info","msg":"Finished reading the config file","time":"2025-04-03T13:59:22Z"}
{"Key":"172.31.1.123","Topic":"config","level":"info","msg":"Add Peer","time":"2025-04-03T13:59:22Z"}
{"Key":"172.31.1.123","Topic":"Peer","level":"info","msg":"Add a peer configuration","time":"2025-04-03T13:59:22Z"}
{"Key":"172.31.1.123","State":"BGP_FSM_OPENCONFIRM","Topic":"Peer","level":"info","msg":"Peer Up","time":"2025-04-03T13:59:24Z"}

Peer Up のログ出力が出れば OK です。ルートサーバーピア側も BGPステータスがアップしています。

ルートサーバーピアの状態 - BGPステータスUp

しかしルートテーブルには何も情報が入っていないはずです。これはまだ GoBGP でピアの設定はしたが経路情報を入れていないからです。GoBGP#2 で以下のコマンドを打鍵してください。2 つめのコマンドは冗長化設定の優先度指定のための設定なので動かすだけなら必要ではありません。

./gobgp global rib add -a ipv4 0.0.0.0/0 nexthop 172.31.1.103
./gobgp global rib add -a ipv4 0.0.0.0/0 med 100

再びプライベートサブネットの ルートテーブルを見ると 0.0.0.0/0 への経路について GoBGP#2 に紐づくENIが指定されています。これにより、プライベートサブネットに対して VPC Route Server を利用することで動的に経路を入れることができました。

プライベートサブネットの経路情報 - 0.0.0.0/0 のルートあり

CloudShell in VPC で tmux を起動し左ペインで ping 192.0.2.1、右で GoBGP#2 に SSH ログイン後 tcpdump をとっています。ping ごとに GoBGP#2 ループバックアドレスから返事がされていることがわかります。

ping での通信疎通確認

1号機から経路情報を広告する

GoBGP#1 からも経路情報を広告してみましょう。gobgpd の設定は以下の通りです。

[global.config]
  as = 65002
  router-id = "192.0.2.100"

[[neighbors]]
  [neighbors.config]
    neighbor-address = "172.31.0.209" # ここは環境で書き換えること
    peer-as = 65001

設定作成後 GoBGP#1 で gobpgd を起動します。起動した後にも操作するのでバックグラウンドに回します。

./gobgpd -f gobgpd.conf &
[1] 7725
sh-5.2$ {"level":"info","msg":"gobgpd started","time":"2025-04-03T15:37:30Z"}
{"Topic":"Config","level":"info","msg":"Finished reading the config file","time":"2025-04-03T15:37:30Z"}
{"Key":"172.31.0.209","Topic":"config","level":"info","msg":"Add Peer","time":"2025-04-03T15:37:30Z"}
{"Key":"172.31.0.209","Topic":"Peer","level":"info","msg":"Add a peer configuration","time":"2025-04-03T15:37:30Z"}
{"Key":"172.31.0.209","State":"BGP_FSM_OPENCONFIRM","Topic":"Peer","level":"info","msg":"Peer Up","time":"2025-04-03T15:37:32Z"}

画像省略していますが、上記手順で VPC Route Server の 1 号機に対応するルートサーバーピアの BGP ステータスが Up になります。GoBGP#1 に引き続きコマンドを入れていきます。

./gobgp global rib add -a ipv4 0.0.0.0/0 nexthop 172.31.0.97
./gobgp global rib add -a ipv4 0.0.0.0/0 med 10

この後あらためてプライベートサブネットのルートテーブルを見ると、送信先 0.0.0.0/0 に対するターゲットのインターフェースが変わっているのがわかると思います。構成図上でいうと eni-y から eni-x に切り替わりました。これはパスアトリビュートの MED 属性により、どっちの仮想アプライアンスを通すかコントロールできるということになります。

プライベートサブネットの経路情報 - 0.0.0.0/0 のルートのターゲットが変わっている

また便利なのが、ルートサーバーの「ルート」タブで見れる情報で、 BGP でインストールされなかった経路の情報も出ることです。これで何のプレフィックスがどこからどの AS Path, MED 属性の値で広告されてもってきているのかがわかります*2。この機能はほかの BGP を受け取って経路設定するゲートウェイにもほしいところではあります。

受け取っている経路情報の閲覧ができる

障害試験をしてみよう

試験の内容

CloudShell in VPC から ping を 192.0.2.1 に継続的に打ちながら、仮想アプライアンス 1 号機の GoBGP のプロセス自体を止めて、2 号機の BGP 経路に切り替わるかを確認します。仮想アプライアンスが完全にハングしたことを想定した障害となります。 CloudShell の tmux で画面を分割しています。

  • 左上: CloudShell から ping 192.0.2.1 をうつ
  • 左下: CloudShell から GoBGP#1 にログインし、gobgpd のプロセスを停止させる。
  • 右上: CloudShell から GoBGP#1 にログインし、tcpdump で icmp 通信を見る
  • 右下: CloudShell から GoBGP#2 にログインし、tcpdump で icmp 通信を見る

以下の GIF アニメのとおり、gobgpd プロセスを kill した瞬間に切り替わりが発生しています。VPC Route Server 設定や BGP の切り方次第ですが、今回はピアが切れた瞬間に代替経路(GoBGP#2)に切り替わっています。

BGP プロセス停止による障害切り替えの実験 | GoBGP#1 -> GoBGP#2 に切り替え

まとめ

仮想アプライアンスの箇所を GoBGP とループバックアドレスで実現しましたが、AWS Marketplace 等で販売されている eBGP をしゃべることが可能な IPS/IDS などであれば大体本手順と同じような設定で実装可能です。

ネクストホップの障害発生時切り替えをAWS Lambda での作りこみや メーカー特有の機構に頼ると保守の観点でコード保守や特別なナレッジが必要など発生してしまいますが、BGP を利用した仕組みであれば標準化され、ある程度枯れた技術で完結するという観点で保守性はよいのかなと感じました。現に GoBGP のようなソフトウェアで eBGP さえ使えればルートテーブルを容易に制御できるというわけですし。

冗長性設定については、切り替わりのホールドダウンタイムなども設計しないといけないと思いますが今回は やってみた なので深くは言及しませんでした。一般の BGP ルーターとしての冗長設計をするという点と AWS 固有の仕様については本番利用の際はより調査が必要かなと思います。

また価格については悩ましいものがあります。1 エンドポイントあたり、東京リージョンだと $1.03/hr 、つまり一か月だいたい $751.9 します。冗長性の担保という観点では最低でも2つエンドポイントを作りたい*3ので、一か月だいたい $1503.8 かかるということになります。この機能はフォールトトレラントのための機能なので 24H365D 動かさないと真価を発揮しない、すなわち動かしっぱなしになると思います。単一の規模が小さいシステムのためにとかでなく、一つの VPC にいろいろのっていて、個別に制御しないといけないとか、そこそこの規模のネットワークを収容している仮想アプライアンスに対して行うなど、一か月 1 エンドポイントあたり大体 $751.9 の価値を見出せる環境・運用・保守体制であるかどうかというのが採択ポイントになるかと思います。

最新の価格については公式サイトをご確認ください。

aws.amazon.com

あと、この VPC Route Server の課題というわけではないですが、Layer 4 以上の機器の宿命として HA 切替発生時にセッションテーブルなどの L4 以上のステータスをどうやって引継ぎするのかという問題もこのやり方では解決はできないというところかなと思います。あくまで L3 レベルの冗長化であることを念頭に置く必要があります。

個人の所感としてはルートテーブルの経路情報の動的変更もユーザー側でもっと詳細にできるようになっていくのだろうかと思ったアップデートでした。あまり詳しくないですが BGP Flowspec、NFV、 サービスチェイン的な NW のアップデートがあると面白いかもしれないですね。 機能のすみわけや運用は大変そうですが。

余談

今回は BGP で経路広告する機能(コントロールプレーン)とパケットをフォワーディングする機能(データプレーン)を一つの仮想アプライアンスでやりました。ほかの構成として、GoBGP が入っていない仮想アプライアンスの IPアドレスをフォワーディング先として GoBGP で指定してもルートテーブルに経路はインストールされ通信もできました(2025-04-04 時点)。

BGP 経路広告とフォワーディングの分離

  • ping でも確認してみます。
    • 左: CloudShell から ping 192.0.2.1 をうつ
    • 右上: CloudShell から GoBGP#1 にログインして、0.0.0.0/0 の経路を別のサーバー(ここでは 172.31.0.212 のサーバー)に割り当てる
    • 右下: CloudShell から BGPを有効にしていない Amazon Linux 2023 にログインし、tcpdump で icmp 通信が来ていることが確認できる。

BGP 広告とフォワーディングの分離での ping チェック

ルートテーブルでの見え方は次の通りです。

BGP 経路広告とフォワーディングをサーバー分離をしても経路はルートテーブルにインストールされる

経路情報を GoBGP で操作することでL3の通信制御は NW 担当で、より上位レイヤーのセキュリティ仮想アプライアンスはセキュリティ担当で、などのサービス分離もできるのかなと思いました。しかし、これが意図した仕様なのかは未確認なので、ルート広告とフォワーディングを分離せず同じ仮想アプライアンスでするのがいいのかなと個人的には考えています。

*1:GoBGP はシングルバイナリで簡単に BGP を使えるようになるので、自宅でフルルート受け取りたい人にもおすすめ!

*2:それぞれ日本語が パスとして(AS Path)、医学(MED) になっちゃってるのはそのうち修正されるかな・・・

*3:公式チュートリアルではエンドポイントを 4 つ作成していました。