Multi-VPC ENI Attachmentsの検証記事part2です。
part1の記事はこちら。
検証のNW構成
part2の検証に使用した環境の構成図です。
part1の検証ではvpc-2とvpc-3のCIDRが異なっていましたが今回は同一CIDRとなっています。
もしもこのような構成のシステムがあったら絶対に近づきたくありません。
この構成で以下の通信テストを実施しました。
テスト1:host-1から10.0.1.10にping
テスト2:host-4から10.0.1.10にping
テスト3:host-2から172.16.1.10にping
補足事項
・VPC Peeringで接続したvpc-1とvpc-2及びvpc-3とvpc-4の間のルーティングはroutetableに設定済。
・各EC2及びvpc-3のENIのセキュリティグループ設定は以下とする。
inbound:RFCで定義されているプライベートIPのCIDRからの通信を全許可
outboundは0.0.0.0/0に対する通信を全許可
・全てのsubnetは同一AZに配置。
・各VPCにはインターネットゲートウェイを作成してインターネット経由でEC2のOSにログインする。
・EC2のOSはAmazonLinux2023を使用。
vpc-2のhost-2にvpc-3のENIをアタッチする
part1の時と同様にAWS CLIでENIをアタッチします。
aws ec2 attach-network-interface --device-index 1 --instance-id <ENIをアタッチするインスタンスID> --network-interface-id <アタッチするENIのID>
ENIアタッチ前のインターフェースの状態です。
[root@host-2 ~]# ifconfig
ens5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 9001
inet 10.0.1.10 netmask 255.255.255.0 broadcast 10.0.1.255
inet6 fe80::4b5:a5ff:fe3d:1839 prefixlen 64 scopeid 0x20<link>
ether 06:b5:a5:3d:18:39 txqueuelen 1000 (Ethernet)
RX packets 17002 bytes 23332741 (22.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1751 bytes 160143 (156.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 12 bytes 1020 (1020.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 12 bytes 1020 (1020.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
host-2にvpc-3のENIをアタッチ後、host-2にSSH接続しているターミナルが反応しなくなり落ちました。(原因は後述)
そのためEC2シリアルコンソールでhost-2に接続してインターフェースの状態を確認しています。
ENIアタッチ後のインターフェースの状態です。
[root@host-2 ~]# ifconfig
ens5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 9001
inet 10.0.1.10 netmask 255.255.255.0 broadcast 10.0.1.255
inet6 fe80::4b5:a5ff:fe3d:1839 prefixlen 64 scopeid 0x20<link>
ether 06:b5:a5:3d:18:39 txqueuelen 1000 (Ethernet)
RX packets 17350 bytes 23367585 (22.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2118 bytes 195649 (191.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens6: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 9001
inet 10.0.1.10 netmask 255.255.255.0 broadcast 10.0.1.255
inet6 fe80::44c:45ff:fe8f:15a3 prefixlen 64 scopeid 0x20<link>
ether 06:4c:45:8f:15:a3 txqueuelen 1000 (Ethernet)
RX packets 6 bytes 2360 (2.3 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 26 bytes 5050 (4.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 12 bytes 1020 (1020.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 12 bytes 1020 (1020.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
テスト1:host-1から10.0.1.10にping
疎通できません。
[root@host-1 ~]# ping 10.0.1.10 -c 3
PING 10.0.1.10 (10.0.1.10) 56(84) bytes of data.
--- 10.0.1.10 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2048ms
テスト2:host-4から10.0.1.10にping
問題無く疎通できました。
[root@host-4 ~]# ping 10.0.1.10 -c 3
PING 10.0.1.10 (10.0.1.10) 56(84) bytes of data.
64 bytes from 10.0.1.10: icmp_seq=1 ttl=127 time=0.175 ms
64 bytes from 10.0.1.10: icmp_seq=2 ttl=127 time=0.173 ms
64 bytes from 10.0.1.10: icmp_seq=3 ttl=127 time=0.180 ms
--- 10.0.1.10 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2057ms
rtt min/avg/max/mdev = 0.173/0.176/0.180/0.003 ms
テスト3:host-2から172.16.1.10にping
問題無く疎通できました。
[root@host-2 ~]# ping 172.16.1.10 -c 3
PING 172.16.1.10 (172.16.1.10) 56(84) bytes of data.
64 bytes from 172.16.1.10: icmp_seq=1 ttl=127 time=0.684 ms
64 bytes from 172.16.1.10: icmp_seq=2 ttl=127 time=0.216 ms
64 bytes from 172.16.1.10: icmp_seq=3 ttl=127 time=0.199 ms
--- 172.16.1.10 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2051ms
rtt min/avg/max/mdev = 0.199/0.366/0.684/0.224 ms
host-1から10.0.1.10になぜ疎通できないのか?
「テスト1:host-1から10.0.1.10にping」で疎通できなかった原因を探るためhost-1とhost2のインターフェースでパケットキャプチャを実行した状態でhost-1から10.0.1.10にpingを実行してみました。
その際の各インターフェースのパケットキャプチャの結果です。
host-1のパケットキャプチャの結果
[root@host-1 ~]# tcpdump -p icmp -n
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens5, link-type EN10MB (Ethernet), snapshot length 262144 bytes
22:53:40.715935 IP 172.16.1.10 > 10.0.1.10: ICMP echo request, id 6, seq 1, length 64
22:53:41.724873 IP 172.16.1.10 > 10.0.1.10: ICMP echo request, id 6, seq 2, length 64
22:53:42.764871 IP 172.16.1.10 > 10.0.1.10: ICMP echo request, id 6, seq 3, length 64
ICMP echo request(以下request)は発信されていますがICMP echo reply(以下reply)の受信がありません。
host-2のvpc-2のENI(ens5)のパケットキャプチャの結果
[root@host-2 ~]# tcpdump -p icmp -i ens5 -n
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens5, link-type EN10MB (Ethernet), snapshot length 262144 bytes
22:53:40.716070 IP 172.16.1.10 > 10.0.1.10: ICMP echo request, id 6, seq 1, length 64
22:53:41.724958 IP 172.16.1.10 > 10.0.1.10: ICMP echo request, id 6, seq 2, length 64
22:53:42.764947 IP 172.16.1.10 > 10.0.1.10: ICMP echo request, id 6, seq 3, length 64
requestを受信していますがreplyを返していません。
replyはどこへ行ってしまったのでしょうか?
ICMP echo replyの行方
host-2のvpc-3のENI(ens6)のパケットキャプチャを取得したところreplyの行方が判明しました。
host-2ではvpc-2のENI(ens5)で受信したrequestに対するreplyをvpc-3のENI(ens6)から発信しており、このreplyはhost-4で受信されていることがhost-4でのパケットキャプチャで分かりました。
host-2のvpc-3のENI(ens6)のパケットキャプチャ
[root@host-2 ~]# tcpdump -p icmp -i ens6 -n
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens6, link-type EN10MB (Ethernet), snapshot length 262144 bytes
22:59:38.776675 IP 10.0.1.10 > 172.16.1.10: ICMP echo reply, id 7, seq 1, length 64
22:59:39.804986 IP 10.0.1.10 > 172.16.1.10: ICMP echo reply, id 7, seq 2, length 64
22:59:40.844985 IP 10.0.1.10 > 172.16.1.10: ICMP echo reply, id 7, seq 3, length 64
host-4のパケットキャプチャ
[root@host-4 ~]# tcpdump -p icmp -n
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens5, link-type EN10MB (Ethernet), snapshot length 262144 bytes
22:59:38.776736 IP 10.0.1.10 > 172.16.1.10: ICMP echo reply, id 7, seq 1, length 64
22:59:39.805050 IP 10.0.1.10 > 172.16.1.10: ICMP echo reply, id 7, seq 2, length 64
22:59:40.845050 IP 10.0.1.10 > 172.16.1.10: ICMP echo reply, id 7, seq 3, length 64
なぜrequestとreplyでインターフェースが変わるのか?
これは理由が分かりませんでした。
part1の検証であったようなOSのルートテーブルのMetricが原因かと考えたのですが、Metricの値としてはvpc-2のENI(ens5)が優先されると思うのですが。。。
以下はhost-2のルートテーブルの情報です。
[root@host-2 ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.0.1.1 0.0.0.0 UG 512 0 0 ens5
0.0.0.0 10.0.1.1 0.0.0.0 UG 522 0 0 ens6
10.0.1.0 0.0.0.0 255.255.255.0 U 512 0 0 ens5
10.0.1.0 0.0.0.0 255.255.255.0 U 522 0 0 ens6
10.0.1.1 0.0.0.0 255.255.255.255 UH 512 0 0 ens5
10.0.1.1 0.0.0.0 255.255.255.255 UH 522 0 0 ens6
10.0.1.2 0.0.0.0 255.255.255.255 UH 512 0 0 ens5
10.0.1.2 0.0.0.0 255.255.255.255 UH 522 0 0 ens6
この謎はもう少し調査してみて原因が分かったらこの記事を更新したいと思います。
テスト3の172.16.1.10はhost-1とhost-4のどちらなのか?
host-1とhost-4でhost-2から172.16.1.10にpingをパケットキャプチャを実行した状態でhost-2から172.16.1.10にpingを実行して確認したところ、host-1でrequestを受信してreplyを返していました。
host-2ではvpc-2のENI(ens5)が使用されていることも確認しました。
host-2のvpc-2のENI(ens5)のパケットキャプチャ
[root@host-2 ~]# tcpdump -p icmp -i ens5 -n
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens5, link-type EN10MB (Ethernet), snapshot length 262144 bytes
09:20:32.963378 IP 10.0.1.10 > 172.16.1.10: ICMP echo request, id 7, seq 1, length 64
09:20:32.963549 IP 172.16.1.10 > 10.0.1.10: ICMP echo reply, id 7, seq 1, length 64
09:20:34.003706 IP 10.0.1.10 > 172.16.1.10: ICMP echo request, id 7, seq 2, length 64
09:20:34.003847 IP 172.16.1.10 > 10.0.1.10: ICMP echo reply, id 7, seq 2, length 64
09:20:35.043686 IP 10.0.1.10 > 172.16.1.10: ICMP echo request, id 7, seq 3, length 64
09:20:35.043912 IP 172.16.1.10 > 10.0.1.10: ICMP echo reply, id 7, seq 3, length 64
host-1のパケットキャプチャ
[root@host-1 ~]# tcpdump -p icmp -n
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens5, link-type EN10MB (Ethernet), snapshot length 262144 bytes
09:20:32.963441 IP 10.0.1.10 > 172.16.1.10: ICMP echo request, id 7, seq 1, length 64
09:20:32.963468 IP 172.16.1.10 > 10.0.1.10: ICMP echo reply, id 7, seq 1, length 64
09:20:34.003769 IP 10.0.1.10 > 172.16.1.10: ICMP echo request, id 7, seq 2, length 64
09:20:34.003795 IP 172.16.1.10 > 10.0.1.10: ICMP echo reply, id 7, seq 2, length 64
09:20:35.043833 IP 10.0.1.10 > 172.16.1.10: ICMP echo request, id 7, seq 3, length 64
09:20:35.043860 IP 172.16.1.10 > 10.0.1.10: ICMP echo reply, id 7, seq 3, length 64
これはpart1の検証のテスト3と同様の結果で想定していた挙動でした。
※ens5のMetricの値が小さいのでens5が優先して使用される
[root@host-2 ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.0.1.1 0.0.0.0 UG 512 0 0 ens5
0.0.0.0 10.0.1.1 0.0.0.0 UG 522 0 0 ens6
host-2にvpc-3のENI(ens6)をアタッチした時にターミナルが落ちた理由
これは「テスト1:host-1から10.0.1.10にping」で疎通できなかった原因と同様です。
host-2にはvpc-2のENI(ens5)にEIPを付与してインターネット経由でSSH接続していましたがvpc-3のENI(ens6)をアタッチしたことによってens5で受けた通信に対する戻りの通信がens6から出るようになって作業端末まで返ってこなくなったのです。
host-2のvpc-2のENI(ens5)のパケットキャプチャです。
ens5でクライアントからのSSH通信を受信していることが分かります。
[root@host-2 ~]# tcpdump -i ens5 port 22 -n
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens5, link-type EN10MB (Ethernet), snapshot length 262144 bytes
13:42:59.434217 IP XXX.XXX.149.74.54526 > 10.0.1.10.ssh: Flags [S], seq 1085428056, win 64240, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 0
13:43:00.439532 IP XXX.XXX.149.74.54526 > 10.0.1.10.ssh: Flags [S], seq 1085428056, win 64240, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 0
13:43:02.443768 IP XXX.XXX.149.74.54526 > 10.0.1.10.ssh: Flags [S], seq 1085428056, win 64240, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 0
13:43:06.455153 IP XXX.XXX.149.74.54526 > 10.0.1.10.ssh: Flags [S], seq 1085428056, win 64240, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 0
13:43:14.469496 IP XXX.XXX.149.74.54526 > 10.0.1.10.ssh: Flags [S], seq 1085428056, win 64240, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 0
host-2のvpc-3のENI(ens6)のパケットキャプチャです。
SSH通信の戻りをens6から返そうとしていることが分かります。
[root@host-2 ~]# tcpdump -i ens6 port 22 -n
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens6, link-type EN10MB (Ethernet), snapshot length 262144 bytes
13:42:59.434250 IP 10.0.1.10.ssh > XXX.XXX.149.74.54526: Flags [S.], seq 197844736, ack 1085428057, win 62727, options [mss 8961,nop,nop,sackOK,nop,wscale 7], length 0
13:43:00.439560 IP 10.0.1.10.ssh > XXX.XXX.149.74.54526: Flags [S.], seq 197844736, ack 1085428057, win 62727, options [mss 8961,nop,nop,sackOK,nop,wscale 7], length 0
13:43:01.468210 IP 10.0.1.10.ssh > XXX.XXX.149.74.54526: Flags [S.], seq 197844736, ack 1085428057, win 62727, options [mss 8961,nop,nop,sackOK,nop,wscale 7], length 0
13:43:02.443797 IP 10.0.1.10.ssh > XXX.XXX.149.74.54526: Flags [S.], seq 197844736, ack 1085428057, win 62727, options [mss 8961,nop,nop,sackOK,nop,wscale 7], length 0
13:43:04.508223 IP 10.0.1.10.ssh > XXX.XXX.149.74.54526: Flags [S.], seq 197844736, ack 1085428057, win 62727, options [mss 8961,nop,nop,sackOK,nop,wscale 7], length 0
vpc-3のENI(ens6)にはEIPは付与していないのでインターネットからグローバルIPで受信したSSH通信をインターネット側に戻すことはできません。
尚、vpc-3のENI(ens6)にEIPを付与してもSSH通信をインターネット側に戻すことはできませんでした。
追加検証
vpc-2とvpc-3にEC2を1台ずつ追加で起動して、そのEC2から10.0.1.10にpingを実行してみました。
host-5でのping 10.0.1.10の結果
疎通できません。
[root@host-5 ~]# ping 10.0.1.10 -c 3
PING 10.0.1.10 (10.0.1.10) 56(84) bytes of data.
--- 10.0.1.10 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2097ms
host-2のvpc-2のENI(ens5)でのパケットキャプチャではrequestを受けていることは確認できます。
[root@host-2 ~]# tcpdump -p icmp -i ens5 -n
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens5, link-type EN10MB (Ethernet), snapshot length 262144 bytes
22:59:53.792519 IP 10.0.1.20 > 10.0.1.10: ICMP echo request, id 3, seq 1, length 64
22:59:54.831005 IP 10.0.1.20 > 10.0.1.10: ICMP echo request, id 3, seq 2, length 64
22:59:55.870967 IP 10.0.1.20 > 10.0.1.10: ICMP echo request, id 3, seq 3, length 64
host-2のvpc-3のENI(ens6)でのパケットキャプチャで10.0.1.20に対するARP Requestが発信されていることが確認できました。
これはhost-5からvpc-2のENI(ens5)で受けたrequestに対するreplyをvpc-3のENI(ens6)から発信しようとしているためです。(vpc-3には10.0.1.20が存在せずens6に10.0.1.20に対応するARPキャッシュが無いのでARP Requestで10.0.1.20のMACアドレスを確認しようとしている)
[root@host-2 ~]# tcpdump -i ens6 -p arp -n
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens6, link-type EN10MB (Ethernet), snapshot length 262144 bytes
22:59:53.792551 ARP, Request who-has 10.0.1.20 tell 10.0.1.10, length 28
22:59:54.842264 ARP, Request who-has 10.0.1.20 tell 10.0.1.10, length 28
22:59:55.882270 ARP, Request who-has 10.0.1.20 tell 10.0.1.10, length 28
試しにvpc-3に10.0.1.20のEC2を起動して再度host-5で再度ping 10.0.1.10を実行したところ、やはりens6からreplyを発信してvpc-3に10.0.1.20のEC2で受信していました。
host-2のvpc-3のENI(ens6)のパケットキャプチャ
[root@host-2 ~]# tcpdump -i ens6 -p icmp -n
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens6, link-type EN10MB (Ethernet), snapshot length 262144 bytes
23:09:03.264250 IP 10.0.1.10 > 10.0.1.20: ICMP echo reply, id 6, seq 1, length 64
23:09:04.270988 IP 10.0.1.10 > 10.0.1.20: ICMP echo reply, id 6, seq 2, length 64
23:09:05.311021 IP 10.0.1.10 > 10.0.1.20: ICMP echo reply, id 6, seq 3, length 64
vpc-3の10.0.1.20のパケットキャプチャ
[root@ip-10-0-1-20 ~]# tcpdump -p icmp -n
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens5, link-type EN10MB (Ethernet), snapshot length 262144 bytes
14:09:03.264427 IP 10.0.1.10 > 10.0.1.20: ICMP echo reply, id 6, seq 1, length 64
14:09:04.271160 IP 10.0.1.10 > 10.0.1.20: ICMP echo reply, id 6, seq 2, length 64
14:09:05.311184 IP 10.0.1.10 > 10.0.1.20: ICMP echo reply, id 6, seq 3, length 64
host-3でのping 10.0.1.10の結果
問題無く疎通できました。
[root@host-3 ~]# ping 10.0.1.10 -c 3
PING 10.0.1.10 (10.0.1.10) 56(84) bytes of data.
64 bytes from 10.0.1.10: icmp_seq=1 ttl=127 time=0.346 ms
64 bytes from 10.0.1.10: icmp_seq=2 ttl=127 time=0.374 ms
64 bytes from 10.0.1.10: icmp_seq=3 ttl=127 time=0.424 ms
--- 10.0.1.10 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2097ms
rtt min/avg/max/mdev = 0.346/0.381/0.424/0.032 ms
host-2のパケットキャプチャからもvpc-3のENI(ens6)でrequestの受信、replyの返信を実行していることが確認できます。
[root@host-2 ~]# tcpdump -i ens6 -p icmp -n
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens6, link-type EN10MB (Ethernet), snapshot length 262144 bytes
23:34:15.092201 IP 10.0.1.30 > 10.0.1.10: ICMP echo request, id 3, seq 1, length 64
23:34:15.092228 IP 10.0.1.10 > 10.0.1.30: ICMP echo reply, id 3, seq 1, length 64
23:34:16.150341 IP 10.0.1.30 > 10.0.1.10: ICMP echo request, id 3, seq 2, length 64
23:34:16.150366 IP 10.0.1.10 > 10.0.1.30: ICMP echo reply, id 3, seq 2, length 64
23:34:17.190302 IP 10.0.1.30 > 10.0.1.10: ICMP echo request, id 3, seq 3, length 64
23:34:17.190327 IP 10.0.1.10 > 10.0.1.30: ICMP echo reply, id 3, seq 3, length 64
まとめ
Multi-VPC ENI Attachmentsで同一CIDRのENIをアタッチした場合、以下の挙動であることが分かりました。
・プライマリENI(host-2のvpc-2のENI)で受信した通信の戻りの通信が後からアタッチしたENI(host-2のvpc-3のENI)から発信されてしまう
・同一CIDRのENIをアタッチしたEC2が通信元である場合はOSのルートテーブルのMetric値に従ってプライマリENI(host-2のvpc-2のENI)から発信される
今回の検証のようなNW構成でシステムを構築・運用することは稀だと思いますが、万が一そうせざるを得ない状況に遭遇したどなたかのためにこの検証の結果が少しでもお役に立てれば幸いです。