east – west traffic を NAT Gatway を経由させてみた(VPC 内のサブネット間の通信なのに NAT してみた)

サブネットルートテーブルで VPC の CIDER より狭い宛先を指定し、ターゲットに NAT Gateway を指定してみました。使い道は思いついていません。

後からついてくるものだ、意味なんてものは。


コンバンハ、千葉(幸)です。まずは以下をご覧ください。

はい。そしてこちらを。

VPC にまつわる通信について、インターネットゲートウェイや仮想プライベートゲーウェイを経由して VPC に入ってくる通信を north - south trafic、 VPC 内部のサブネット間の通信を east - west traffic と呼ぶことがあります。

先日、east - west traffic をより柔軟にルーティングできるアップデートが行われました。従来サブネットルートテーブルでは VPC の CIDR より具体的な宛先を指定したルートの登録はできませんでしたが、それが可能になったというものです。

例えば10.0.0.0/16という VPC があった場合に、それより具体的な10.0.1.0/24という宛先を指定したルートを定義できるようになっています。この機能の主な使い道はアプライアンス製品に通信をルーティングさせることであり、そのインスタンスが持つネットワークインターフェース(ENI)をターゲットに指定することが多いかと思います。

「より具体的なルート」におけるターゲットとしてサポートされているのは以下の通りです。

  • ゲートウェイロードバランサーエンドポイント
  • NAT Gateway
  • ネットワークファイアウォールエンドポイント
  • ネットワークインターフェース

Example routing options - Amazon Virtual Private Cloud

他の 3 つはまだしも NAT Gateway をターゲットにするのはどういったケースだ……?というのが初見では分かりませんでした。その後も事あるごとに引っ張り出してきては考えていましたが、考えても考えても分からないので、そのうち考えるのを止めました。

どういう時に使うのかわからないけど、なんか面白そうだからやってみるか」というモチベーションでやってみることにしました。

やりたいことの構成

以下の通りです。

送信元のインスタンスから宛先インスタンスへの通信を行います。その際に直接ルーティングするのでなく NAT Gateway を経由させます。宛先インスタンスから見ると送信元 IP アドレスは NAT Gateway が持つプライベート IP アドレスとなります。

送信元サブネットのルートテーブルで赤編みかけしている部分が「より具体的なルート」を登録しているところです。

パケットの気持ちになって考えると、以下のようになります。

ここでやりたいことができると何が嬉しいのか

すみません、よく分かりません。

環境の準備

先程載せた図の通りの構成を作成しました。IP アドレスは以下のように採番されました。

インスタンスをパブリックサブネットに配置しているのは、Systems Manager 経由で接続したいためです。

EC2 インスタンス

Amazon Linux2 の AMI から立ち上げて、 Systems Manager 経由で接続できるように IAM ロールをセットアップしました。

アタッチしている SecuriryGroup では、VPC (10.0.0.0/16)内からのすべてのトラフィックのインバウンドを許可しています。

NAT Gateway

プライベートタイプの NAT Gateway を作成しました。

% aws ec2 describe-nat-gateways --region ap-northeast-3 --output table
-----------------------------------------------------
|                DescribeNatGateways                |
+---------------------------------------------------+
||                   NatGateways                   ||
|+-------------------+-----------------------------+|
||  ConnectivityType |  private                    ||
||  CreateTime       |  2021-09-25T10:50:53+00:00  ||
||  NatGatewayId     |  nat-0efd1351c899a1d4b      ||
||  State            |  available                  ||
||  SubnetId         |  subnet-06139abbf53962d56   ||
||  VpcId            |  vpc-0e9326bf225102d4e      ||
|+-------------------+-----------------------------+|
|||              NatGatewayAddresses              |||
||+---------------------+-------------------------+||
|||  NetworkInterfaceId |  eni-0f62ab5dbbe7cffb5  |||
|||  PrivateIp          |  10.0.2.149             |||
||+---------------------+-------------------------+||
|||                     Tags                      |||
||+------------------+----------------------------+||
|||  Key             |  Name                      |||
|||  Value           |  osaka-NAT                 |||
||+------------------+----------------------------+||

今回やりたいことに関しては、パブリックタイプでも問題なく実現できます。(単に EIP が無駄に割り当てられるだけです。)

サブネットルートテーブル

冒頭の図の通りの設定で作成しています。

送信元 サブネット(10.0.0.0/24)用

% aws ec2 describe-route-tables --route-table-ids rtb-0c4b26d537894d810 --region ap-northeast-3 --query 'RouteTables[].Routes' --output table
----------------------------------------------------------------------------------------------------------
|                                           DescribeRouteTables                                          |
+----------------------+------------------------+------------------------+--------------------+----------+
| DestinationCidrBlock |       GatewayId        |     NatGatewayId       |      Origin        |  State   |
+----------------------+------------------------+------------------------+--------------------+----------+
|  10.0.1.0/24         |                        |  nat-0efd1351c899a1d4b |  CreateRoute       |  active  |
|  10.0.0.0/16         |  local                 |                        |  CreateRouteTable  |  active  |
|  0.0.0.0/0           |  igw-09e9571aa689c8066 |                        |  CreateRoute       |  active  |
+----------------------+------------------------+------------------------+--------------------+----------+

宛先サブネット(10.0.1.0/24)用

% aws ec2 describe-route-tables --route-table-ids rtb-0477da6dc8cf13cc0 --region ap-northeast-3 --query 'RouteTables[].Routes' --output table
---------------------------------------------------------------------------------
|                              DescribeRouteTables                              |
+----------------------+-------------------------+--------------------+---------+
| DestinationCidrBlock |        GatewayId        |      Origin        |  State  |
+----------------------+-------------------------+--------------------+---------+
|  10.0.0.0/16         |  local                  |  CreateRouteTable  |  active |
|  0.0.0.0/0           |  igw-09e9571aa689c8066  |  CreateRoute       |  active |
+----------------------+-------------------------+--------------------+---------+

NAT Gateway サブネット(10.0.2.0/24)用

% aws ec2 describe-route-tables --route-table-ids rtb-09d8f9c413cda3505 --region ap-northeast-3 --query 'RouteTables[].Routes' --output table
---------------------------------------------------------------------
|                        DescribeRouteTables                        |
+-----------------------+------------+--------------------+---------+
| DestinationCidrBlock  | GatewayId  |      Origin        |  State  |
+-----------------------+------------+--------------------+---------+
|  10.0.0.0/16          |  local     |  CreateRouteTable  |  active |
+-----------------------+------------+--------------------+---------+

やってみた

早速やっていきます。

再掲すると各コンポーネントの IP アドレスは以下の通りです。

コンポーネント IP アドレス
送信元インスタンス 10.0.0.11
宛先インスタンス 10.0.1.55
NAT Gateway 10.0.2.149

送信元インスタンスからの traceroute

traceroute で経由する IP アドレスを確認します。

その前に、宛先インスタンス側で NAT Gatewy の IP を指定して tcpdump を行います。該当する通信があれば、その内訳が出力されていきます。

宛先インスタンス

sh-4.2$ sudo tcpdump -i eth0 host 10.0.2.149
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

送信元インスタンスに切り替え、宛先インスタンスの IP を指定して traceroute を行います。実行時刻が分かるよう date を先に実行しています。

送信元インスタンス

sh-4.2$ date +%H:%M:%S.%6N && traceroute 10.0.1.55
11:17:40.880630
traceroute to 10.0.1.55 (10.0.1.55), 30 hops max, 60 byte packets
 1  10.0.2.149 (10.0.2.149)  0.082 ms  0.072 ms  0.063 ms
 2  10.0.1.55 (10.0.1.55)  0.423 ms  0.422 ms  0.406 ms
sh-4.2$

↑ NAT Gateway(10.0.2.149)を経由したのち、宛先インスタンス(10.0.1.55)に到達していることがわかります。

宛先インスタンス側では、該当する通信が出力されています。

宛先インスタンス

# sh-4.2$ sudo tcpdump -i eth0 host 10.0.2.149
# tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
# listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
11:17:40.881952 IP 10.0.2.149.59743 > ip-10-0-1-55.ap-northeast-3.compute.internal.33437: UDP, length 32
11:17:40.881986 IP ip-10-0-1-55.ap-northeast-3.compute.internal > 10.0.2.149: ICMP ip-10-0-1-55.ap-northeast-3.compute.internal udp port 33437 unreachable, length 68
11:17:40.881992 IP 10.0.2.149.62576 > ip-10-0-1-55.ap-northeast-3.compute.internal.33440: UDP, length 32
11:17:40.881995 IP ip-10-0-1-55.ap-northeast-3.compute.internal > 10.0.2.149: ICMP ip-10-0-1-55.ap-northeast-3.compute.internal udp port 33440 unreachable, length 68
11:17:40.881997 IP 10.0.2.149.58860 > ip-10-0-1-55.ap-northeast-3.compute.internal.33439: UDP, length 32
11:17:40.882000 IP ip-10-0-1-55.ap-northeast-3.compute.internal > 10.0.2.149: ICMP ip-10-0-1-55.ap-northeast-3.compute.internal udp port 33439 unreachable, length 68
11:17:40.882002 IP 10.0.2.149.40488 > ip-10-0-1-55.ap-northeast-3.compute.internal.33444: UDP, length 32
11:17:40.882005 IP ip-10-0-1-55.ap-northeast-3.compute.internal > 10.0.2.149: ICMP ip-10-0-1-55.ap-northeast-3.compute.internal udp port 33444 unreachable, length 68
11:17:40.882008 IP 10.0.2.149.39818 > ip-10-0-1-55.ap-northeast-3.compute.internal.33438: UDP, length 32
11:17:40.882011 IP ip-10-0-1-55.ap-northeast-3.compute.internal > 10.0.2.149: ICMP ip-10-0-1-55.ap-northeast-3.compute.internal udp port 33438 unreachable, length 68
11:17:40.882014 IP 10.0.2.149.51062 > ip-10-0-1-55.ap-northeast-3.compute.internal.33441: UDP, length 32
11:17:40.882017 IP ip-10-0-1-55.ap-northeast-3.compute.internal > 10.0.2.149: ICMP ip-10-0-1-55.ap-northeast-3.compute.internal udp port 33441 unreachable, length 68
11:17:40.882019 IP 10.0.2.149.27348 > ip-10-0-1-55.ap-northeast-3.compute.internal.33442: UDP, length 32
11:17:40.882021 IP 10.0.2.149.12585 > ip-10-0-1-55.ap-northeast-3.compute.internal.33443: UDP, length 32
11:17:40.882050 IP 10.0.2.149.31037 > ip-10-0-1-55.ap-northeast-3.compute.internal.33446: UDP, length 32
11:17:40.882054 IP 10.0.2.149.46422 > ip-10-0-1-55.ap-northeast-3.compute.internal.33445: UDP, length 32
11:17:40.882056 IP 10.0.2.149.59721 > ip-10-0-1-55.ap-northeast-3.compute.internal.33447: UDP, length 32
11:17:40.882058 IP 10.0.2.149.64526 > ip-10-0-1-55.ap-northeast-3.compute.internal.33448: UDP, length 32
11:17:40.882063 IP 10.0.2.149.29773 > ip-10-0-1-55.ap-northeast-3.compute.internal.33449: UDP, length 32
11:17:40.884336 IP 10.0.2.149.48575 > ip-10-0-1-55.ap-northeast-3.compute.internal.33450: UDP, length 32
11:17:40.884347 IP 10.0.2.149.15369 > ip-10-0-1-55.ap-northeast-3.compute.internal.33451: UDP, length 32
11:17:40.884370 IP 10.0.2.149.22250 > ip-10-0-1-55.ap-northeast-3.compute.internal.33452: UDP, length 32

同一 VPC 内の通信で NAT Gateway を経由させることができました。

送信元インスタンスからの Ping

せっかくなので Ping も実行してみます。

もちろん問題なく成功します。

送信元インスタンス

sh-4.2$ date +%H:%M:%S.%6N && ping 10.0.1.55 -c 3
11:19:51.280053
PING 10.0.1.55 (10.0.1.55) 56(84) bytes of data.
64 bytes from 10.0.1.55: icmp_seq=1 ttl=254 time=0.987 ms
64 bytes from 10.0.1.55: icmp_seq=2 ttl=254 time=0.199 ms
64 bytes from 10.0.1.55: icmp_seq=3 ttl=254 time=0.208 ms

--- 10.0.1.55 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2026ms
rtt min/avg/max/mdev = 0.199/0.464/0.987/0.370 ms
sh-4.2$

宛先インスタンス側の tcpdump でも同じように確認できます。

宛先インスタンス

11:19:51.285069 IP 10.0.2.149 > ip-10-0-1-55.ap-northeast-3.compute.internal: ICMP echo request, id 31391, seq 1, length 64
11:19:51.285094 IP ip-10-0-1-55.ap-northeast-3.compute.internal > 10.0.2.149: ICMP echo reply, id 31391, seq 1, length 64
11:19:52.286277 IP 10.0.2.149 > ip-10-0-1-55.ap-northeast-3.compute.internal: ICMP echo request, id 31391, seq 2, length 64
11:19:52.286298 IP ip-10-0-1-55.ap-northeast-3.compute.internal > 10.0.2.149: ICMP echo reply, id 31391, seq 2, length 64
11:19:53.311180 IP 10.0.2.149 > ip-10-0-1-55.ap-northeast-3.compute.internal: ICMP echo request, id 31391, seq 3, length 64
11:19:53.311203 IP ip-10-0-1-55.ap-northeast-3.compute.internal > 10.0.2.149: ICMP echo reply, id 31391, seq 3, length 64

host で 送信元インスタンスの IP を指定して tcpdump

ここまでは NAT Gateway の IP を指定して tcpdump をしていましたが、送信元インスタンスの IP を指定して試してみます。

送信元インスタンスから宛先サブネットへの通信は常に NAT Gateway を経由しているため、通信は発生していないはずです。

宛先インスタンス

sh-4.2$ sudo tcpdump -i eth0 host 10.0.0.11
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

送信元インスタンスから再度 Ping を実行します。

送信元インスタンス

sh-4.2$ date +%H:%M:%S.%6N && ping 10.0.1.55 -c 3
11:21:32.928691
PING 10.0.1.55 (10.0.1.55) 56(84) bytes of data.
64 bytes from 10.0.1.55: icmp_seq=1 ttl=254 time=0.440 ms
64 bytes from 10.0.1.55: icmp_seq=2 ttl=254 time=0.258 ms
64 bytes from 10.0.1.55: icmp_seq=3 ttl=254 time=0.209 ms

--- 10.0.1.55 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2044ms
rtt min/avg/max/mdev = 0.209/0.302/0.440/0.100 ms
sh-4.2$

宛先インスタンスの tcpdump では、何も出力されていませんでした。想定通りです。

宛先インスタンスの SecuriryGroup のインバウンドを制限して Ping

これまで 宛先インスタンスの SecuriryGroup では VPC(10.0.0.0/16)からのインバウンドを許可するようにしていましたが、送信元サブネット(10.0.0.0/24)からのインバウンドのみ許可するように設定変更してみます。

パケットの気持ちになって考えると、宛先インスタンスに到達する際の送信元 IP アドレスは NAT Gateway の持つ 10.0.2.194 です。そこからのインバウンドが許可されていないと通信はブロックされるはずです。

SecuriryGroup の設定変更後、送信元インスタンスから Ping を行います。

送信元インスタンス

sh-4.2$ date +%H:%M:%S.%6N && ping 10.0.1.55 -c 3
11:22:36.676545
PING 10.0.1.55 (10.0.1.55) 56(84) bytes of data.

--- 10.0.1.55 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2040ms

sh-4.2$

すべてのパケットがロストしました。これも想定通りです。

ちなみに:NAT Gateway は Ping に応答しない

今回の本旨からは外れますが、NAT Gateway を宛先にして Ping を実行してみました。

送信元インスタンス

sh-4.2$ date +%H:%M:%S.%6N && ping 10.0.2.149 -c 3
11:24:38.673278
PING 10.0.2.149 (10.0.2.149) 56(84) bytes of data.

--- 10.0.2.149 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2028ms

すべてのパケットがロストしました。 ICMP も NAT してくれるものの、自身を宛先にした通信には応答しない、ということが分かりました。

わたしの行為に意味を与えてください

east - west traffic こと VPC 内部の通信を、 NAT Gateway を経由させてみました。

ひとしきりやってみましたが、いまだに使い道は思いついていません。このままだとわたしがただ単に意味が無い行為に手を染めたということになってしまいます。

それはそれで(とても)楽しいのでいいのですが、せっかくなら意味があったほうが嬉しいので、ユースケースが思い付いた方は教えてください。

ひとまず今回は「より具体的なルート」の宛先に NAT Gateway を指定してもきちんと動作する、というところまで持ち帰っていただければと思います。

以上、 チバユキ (@batchicchi) がお送りしました。