もう一度ENIについて考えてみた(Linux編)
Amazon Linux AMI 2012.09より、複数のENIを使用した際の自動設定が非常に賢くなっているので、もう一度追加ENIについて考えてみた。
Amazon Linux AMIを使用した検証
論より証拠。まずは動かしてみましょう。
VPCを作成します。
- VPC: 10.0.0.0/16
- Subnet1: 10.0.1.0/24
- Subnet2: 10.0.2.0/24
- Subnet3: 10.0.254.0/24
- Subnet1&2 共通RouteTable
- 10.0.0.0/16 local
- 0.0.0.0/0 igw-xxxxxxxx
Amazon Linux AMI (2012.09バージョン)を起動します。
- AMI: amzn-ami-pv-2012.09.0.x86_64-ebs (ami-4e6cd34f)
- ENI: 1つだけ (10.0.1.4のIPアドレスを指定) ※起動時には追加のENIを設定しない
- SecurityGroup:
起動後にElasticIPアドレスを付けsshできる事を確認してください。
別途ENIを作成します(10.0.2.4)。そのENIをこのインスタンスにアタッチすると...
$ ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 02:d0:61:a1:e7:54 brd ff:ff:ff:ff:ff:ff inet 10.0.1.4/24 brd 10.0.1.255 scope global eth0 inet6 fe80::d0:61ff:fea1:e754/64 scope link valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 02:d0:61:84:4f:4a brd ff:ff:ff:ff:ff:ff inet 10.0.2.4/24 brd 10.0.2.255 scope global eth1 inet6 fe80::d0:61ff:fe84:4f4a/64 scope link valid_lft forever preferred_lft forever
自動的にIPアドレスが設定されています。さらにElasticIPアドレスをeth1側にも付けてあげると、このアドレスに対してもpingもsshも出来ます。また元々付いていたeth0のElasticIPアドレスに対してもpingやsshの疎通があります。あまりに普通に動いてしまうので伝わらないかもしれませんが、大きな進歩なのです。
同じ事をCentOS6でやってみると...
eth0(10.0.1.5)を付けて起動した後、eth1(10.0.2.5)を付けていくら待ってもeth1はupしません。
/etc/sysconfig/network-scripts/ifcfg-eth1をifcfg-eth0を元にDEVICE名だけを変えて、./ifup eth1してみるとeth0経由で繋いでいたコンソールが切れてしまうと思います。eth1にEIPを付けてあげれば、そのIPアドレスに対しては通信できるようになっています。
# /sbin/route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 10.0.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 10.0.2.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1 169.254.0.0 0.0.0.0 255.255.0.0 U 1002 0 0 eth0 169.254.0.0 0.0.0.0 255.255.0.0 U 1003 0 0 eth1 0.0.0.0 10.0.2.1 0.0.0.0 UG 0 0 0 eth1
defaulte gatewayがeth1側のsubnetのgatewayに書き変わってしまっているので、当然ですね。rebootをしてもeth0 -> eth1とifupしていくでしょうから、この状況は変わらないと思います。両方のIPにpingを打ちつつ見ていると、先にeth0側からreplyがあり、数秒後に途絶えて、代わりにeth1からはreplyが返ってくる状況になります。これは/etc/sysconfig/network-scripts/ifcfg-eth1に
DEVICE=eth1 BOOTPROTO=dhcp ONBOOT=on DEFROUTE=no
とDEFROUTE=noを指定する事で、eth1側のgatewayをdefault gatewayとして使用する事を抑制できます。
再びeth0側で通信できる状態にはなりましたが、eth1側は疎通が出来なくなります。10.0.254.0/24にインスタンスを立ててeth1側にpingを打ってみると
[ec2-user@ip-10-0-254-4 ~]$ ping -c 1 10.0.1.5 PING 10.0.1.5 (10.0.1.5) 56(84) bytes of data. 64 bytes from 10.0.1.5: icmp_seq=1 ttl=64 time=0.322 ms --- 10.0.1.5 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.322/0.322/0.322/0.000 ms [ec2-user@ip-10-0-254-4 ~]$ ping -c 1 10.0.2.5 PING 10.0.2.5 (10.0.2.5) 56(84) bytes of data. ^C --- 10.0.2.5 ping statistics --- 1 packets transmitted, 0 received, 100% packet loss, time 4883ms
eth1側にpingが飛びません。eth1のインターフェースでicmpをtcpdumpしてみると、
# tcpdump -i eth1 icmp tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth1, link-type EN10MB (Ethernet), capture size 65535 bytes 16:32:19.772456 IP 10.0.254.4 > 10.0.2.5: ICMP echo request, id 54276, seq 1, length 64 16:32:20.771503 IP 10.0.254.4 > 10.0.2.5: ICMP echo request, id 54276, seq 2, length 64 16:32:21.771512 IP 10.0.254.4 > 10.0.2.5: ICMP echo request, id 54276, seq 3, length 64 16:32:22.771610 IP 10.0.254.4 > 10.0.2.5: ICMP echo request, id 54276, seq 4, length 64
echo requestパケットは来ているものの、echo replyパケットが返っていない事が分かります。これはOS上のdefault gatewayがeth0ですので、戻りのパケットがeth0から出て行こうとしてしまうからです(そしてrp_filterによってパケットが落とされる)。
どうしたらよいのか
Linux Route Hacksを参考に、Policy Based Routingを設定してみます。
ENI毎に、対象のsubnetに対してrouting tableを作成します。
ip route flush table 1000 ip route add table 1000 to 10.0.1.0/24 dev eth0 ip route add table 1000 to default via 10.0.1.1 dev eth0 ip rule add from 10.0.1.0/24 table 1000 priority 1000 ip route flush table 1001 ip route add table 1001 to 10.0.2.0/24 dev eth1 ip route add table 1001 to default via 10.0.2.1 dev eth1 ip rule add from 10.0.2.0/24 table 1001 priority 1001 ip route flush cache
すると、どちらのインターフェースからも疎通が取れるようになりました。
[ec2-user@ip-10-0-254-4 ~]$ ping -c 1 10.0.1.5 PING 10.0.1.5 (10.0.1.5) 56(84) bytes of data. 64 bytes from 10.0.1.5: icmp_seq=1 ttl=64 time=0.319 ms --- 10.0.1.5 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.319/0.319/0.319/0.000 ms [ec2-user@ip-10-0-254-4 ~]$ ping -c 1 10.0.2.5 PING 10.0.2.5 (10.0.2.5) 56(84) bytes of data. 64 bytes from 10.0.2.5: icmp_seq=1 ttl=64 time=0.313 ms --- 10.0.2.5 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.313/0.313/0.313/0.000 ms
スクリプト化
ENIの情報をmeta-dataから取得してrouteの設定を行うスクリプトを作成しました→adding policy based route for each ENI · GitHub(要perl)。
例えば/usr/local/sbin/add_policy_route.shのように置いて、/etc/rc.local などから起動します。
さいごに
@suz_labさんもsuz-lab.com - このウェブサイトは販売用です! - suz-lab リソースおよび情報でおっしゃってますが、複数ENIを使用するべきかどうか(≒厳格なENI毎のSecurityGroup設定やNetwork ACLを活用したセキュリティ設定が必要かどうか)をきちんと判断した上で使用するのがよいと思います。ENI分けたけどSubnet間のNACLは普通に許可されている、というのではあまり意味がなくなってしまいます。