今回はAWSのVPC Traffic Mirroringについて、某案件で検証を行なったので、紹介/注意点/使い所について書きます。
展開中のノードへの通信をサクッと覗きたいなど特定用途として使えるケースがあると思うので参考になればと思います。
はじめに
- 今回導入を考えたシステムについて、顧客からの要件としては外部システムから本番環境への通信をテスト環境へ転送し、本番環境と同一のデータでテストを行いたいというものでした。
- 複数ある外部システムとはWebSocketでそれぞれとコネクションを確立し、システムは一度に最大100MB程のデータpushを受信し続けます。
- VPC Traffic Mirroringを利用してデータの転送が可能であるかを検証し、使えそうならシステムに組み込みたいという流れです。
VPC Traffic Mirroringの概要
- 大まかにいうと特定インスタンスのNIC(ENI)に流れてきたネットワーク上のpacketを特定のノードへ転送することが可能です。
- AWSからの説明そのままですが、ユースケースとして以下のようなものを想定しています。
- コンテンツ検査
- 脅威の監視
- トラブルシューティング
- 転送先はリージョンまたぎやVPC間も考慮されており、マネージメントコンソールのグルーピングとしてはVPCのページから設定が可能です。
- 料金
- Traffic Mirroringを有効にしたENIが起動している間、料金がかかります。
- 東京リージョンであると0.018USD/hour(2023/2現在)
- 1ヶ月30日とすると30日×24時間×0.018=12.96USD/month
- そこまでの値段ではないですが、転送先の仕組みなども用意することも考えたら使う時だけ有効にするのが良いかと。
動作/設定
- Traffic Mirroringを使う際のリソースは以下の呼称で呼ばれます。以降の説明はこの呼称でしていきます。
- ソース: 転送元(指定したノード(ENI)への通信を転送)
- ターゲット: 転送先(EC2/NLB/GLB(他VPC宛など))
- フィルタ: 転送対象(ポート/プロトコルなど指定)
- セッション: 上らをまとめたもの
- 設定例は以下。
- ミラーフィルタ/ミラーターゲット/ミラーセッションの順に上記リソースを設定します。
ターゲット側の準備
- 転送されてきたpacketをどう扱うかターゲットに仕組みが必要です。
- 例1. packet解析ソフトウェアにかけて分析
- 例2. packetを処理するようなアプリを自作する
- ターゲットのNICに対しpacket captureをするようなアプリを自作する。
- この際、転送されてきたpacketのみ処理するような仮想NICを作るなど工夫がいる(後述)
- 検証ではGo(gopacket)/Java(pcap4j)でアプリを実装した実績あり。
転送されてくるpacketについて
- ターゲットに流れてくるpacketはVXLANというL2->L3トンネリングプロトコルの形式で流れてきます。
- VXLANはUDPで扱います。なので再送/フロー制御は期待できません。また、NLBなどを転送先にする場合には順番が維持できないことがあるとのこと。
- packetにはVXLANのヘッダ(40byte)が付与されており、その後ろに元のpacketが繋がる形。
- すなわち、元のpacketを取り出したい場合にはVXLANヘッダ部を取り除く必要がありますが、LinuxであればVXLANタイプの仮想NICを以下のようなip(iproute2)コマンドで作成することで自動的に行うことが可能です。
- 作成した仮想NICをcaptureすることでVXLANヘッダを除外した元のpacketを取得できます。
- VNIというVXLAN packetのグループを識別するためのIDと転送時に使用するUDPポートを指定します。(マネージメントコンソールで設定した値)
- Amazon Linux2で動作確認済み。(kernel versionやdestiributionの細かいところの条件は未確認)
- NICのMTUについての注意もあるので参考に。
- 説明の通り、VXLANで転送されたpacketはオリジナルpacketよりHeader分サイズが大きくなります。
- そのため、ソースNICのMTU < ターゲットNICのMTUという関係になっていないとpacketが切り捨てられる可能性があります。(必要なMTUサイズ設定については上のリンクを参照)
$ sudo ip link add vxlan0 type vxlan id 1 dev eth0 dstport 4789
$ sudo ip link set vxlan0 up
検証とそこから見えた注意点
- 実際の構成を想定して右図のような仮の環境を用意し、要件に合うか検証してみました。
問題
- 想定するデータ量を外部システムノードからソースに送信->転送した際、分割されたpacket群の途中から転送されて来ない。。。
- WebSocketでデータpushするデータを1MB/10MB/100MBと順に上げていってみたところ、10MBぐらいから後半のpacket転送がされていないことが判明しました。
- ソースに配置したアプリへは正しくデータが送られており、最初はターゲット側のpacket captureアプリ設定なりがおかしいのかと思い試行錯誤したがどうもうまくきません。
原因
- 「なんでじゃ」と夜も寝られなくなった中、よくよくヘルプを見直すと次のようなものを発見しました。
- Traffic bandwidth and prioritization
- Mirrored traffic counts toward instance bandwidth. For example, if you mirror a network interface that has 1 Gbps of inbound traffic and 1 Gbps of outbound traffic, the instance must handle 4 Gbps of traffic (1 Gbps inbound, 1 Gbps mirrored inbound, 1 Gbps outbound, and 1 Gbps mirrored outbound).
- つまりは、ソースの帯域幅について、想定するトラフィックの2倍〜4倍を見積もっておかないといけない。
- 今回の要件では上り方向への通信のみ転送したいので本番+テスト環境のインバウンドトラフィック用に2倍必要。
- ポイントはソース(転送元)の帯域幅が大事ということ。
- Production traffic has a higher priority than mirrored traffic when there is traffic congestion. As a result, mirrored traffic is dropped when there is congestion.
- つまりは、ソースの帯域が輻輳した場合、packetがドロップされ転送されない。
- Mirrored traffic counts toward instance bandwidth. For example, if you mirror a network interface that has 1 Gbps of inbound traffic and 1 Gbps of outbound traffic, the instance must handle 4 Gbps of traffic (1 Gbps inbound, 1 Gbps mirrored inbound, 1 Gbps outbound, and 1 Gbps mirrored outbound).
- 問題が起きた流れとしては、以下と考えられます。
- 大きいデータをソースに向けてドカっと送る
- ソースの帯域で輻輳が起こる
- 輻輳のために本番トラフィックが優先される
- データの途中から転送が行われなくなる
- ヘルプの通りCloudWatchを監視してみたところ、データ転送に失敗した場合、輻輳によるpacket dropのメトリクスの値が増えており、上記の制限によりpacketがdropされてしまっていることがわかりました。
対策検討
ソースへの通信の輻輳が起こらないようにデータ流量をコントロールできれば良いのではと思い、以下のようなことを試してみました。
- ソースのインスタンスタイプを上げて、ネットワーク帯域を強いもの(c5n.largeなり)に上げてみる。
- 100MBを一斉に送ると、変更前よりも転送された量は多くなったが、後半のpacketがdropされてしまう。
- ソースで輻輳が起こらないようなインスタンスタイプの関係にしてみる。
- 外部システム(t2.micro) -> ソース(c5n.large)というようにソースへの通信がゆっくり流れる(?)であろう関係にすると100MBのデータも転送ができる場合が増えた。
- 当然ながら転送対象のデータだけがネットワーク上に流れているわけでもないため、うまくいったりいかなかったり完璧ではない。
- AWSへ質問を出してみる。
- どうにかして輻輳を起こらないようにする方法がないかAWSへも問い合わせてはみましたが、今回用途に合致するような方法は見つからなかった。
- NLBなどにはデータ流量をコントロールするような機能は公開されていない。
- また、流量をコントロールする用の別ノードを用意するのは今回用途(テスト環境に流す)に対して、対応が大きすぎる。本番環境に影響が出ては元も子もない。
結果
対策の検討結果より、今回用途に適さないところから「使用しない」という結論に至りました。
- テスト環境へのデータ転送のためpacket dropしても問題はないが、本番環境と同じデータで動作再現したいことから極力dropは避けたい。(そもそもVXLANがUDPということもある。)
- インスタンスタイプ(ネットワーク帯域)による制御については、今後増加しうる外部システムが増えるごとにサイジングし続けないといけなくなり、現実的でない。
- 流入制御する別ノードの必要性など本番環境に影響を与えない形での実現が難しい。
まとめ/使い所
- 「稼働中ノードへの通信を少し覗き見したい」などのケースにおいてはとても有用なプロダクトかと思います。
- 通信の監視がアプリ組み込みせずとも後付けで可能。
- システムに取り込むような本格的な利用となると、検証結果を踏まえて以下のポイントを抑えておくと良いかと思います。
- 転送するデータ量がどのくらいか
- packet欠損が起きても問題がないか
- ソースのネットワーク帯域が輻輳を起こさない環境であるか
- 制限事項がいくつかあります。特にここは一通り目を通しておくべきです。
- 検証内容から得た教訓として「困ったら基本に戻ってヘルプを読め」というのを実感させられました。
- その他参考
以上。