AWS ECS Iptables允许源和目标是相同的IP地址

时间:2018-01-31 22:36:05

标签: amazon-web-services amazon-ecs nlb

目前,由于AWS ECS与内部NLB相结合,因此无法进行系统间通信。意义容器1(在实例1上) - >内部NLB - >容器2(实例1)。由于源IP地址不会更改并且与目标地址保持相同,因此ECS实例会丢弃此流量。

我在AWS论坛上找到了一个帖子https://forums.aws.amazon.com/message.jspa?messageID=806936#806936来解释我的问题。

我已经联系了AWS支持部门,他们表示要修复他们的路线图,但是他们无法告诉我什么时候会修复,所以我正在寻找解决方法,直到AWS永久修复它。

必须通过更改ECS iptables来修复它,但我没有足够的知识来完全阅读他们的iptables设置并了解需要更改以解决此问题。

iptabels-save output:

:DOCKER - [0:0]
:DOCKER-ISOLATION - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER -d 172.17.0.3/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 5000 -j ACCEPT
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 5000 -j ACCEPT
-A DOCKER -d 172.17.0.5/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8086 -j ACCEPT
-A DOCKER-ISOLATION -j RETURN
-A DOCKER-USER -j RETURN
COMMIT
# Completed on Wed Jan 31 22:19:47 2018
# Generated by iptables-save v1.4.18 on Wed Jan 31 22:19:47 2018
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [38:2974]
:POSTROUTING ACCEPT [7147:429514]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A PREROUTING -d 169.254.170.2/32 -p tcp -m tcp --dport 80 -j DNAT --to-destination 127.0.0.1:51679
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT -d 169.254.170.2/32 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 51679
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s 172.17.0.3/32 -d 172.17.0.3/32 -p tcp -m tcp --dport 5000 -j MASQUERADE
-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 5000 -j MASQUERADE
-A POSTROUTING -s 172.17.0.5/32 -d 172.17.0.5/32 -p tcp -m tcp --dport 8086 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 32769 -j DNAT --to-destination 172.17.0.3:5000
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 32777 -j DNAT --to-destination 172.17.0.2:5000
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 32792 -j DNAT --to-destination 172.17.0.5:8086
COMMIT
# Completed on Wed Jan 31 22:19:47 2018

ip a:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
   valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
   valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 0a:b4:86:0b:c0:c4 brd ff:ff:ff:ff:ff:ff
    inet 10.12.80.181/26 brd 10.12.80.191 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::8b4:86ff:fe0b:c0c4/64 scope link
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ca:cf:36:ae brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:caff:fecf:36ae/64 scope link
       valid_lft forever preferred_lft forever
7: vethbd1da82@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    link/ether 36:6d:d6:bd:d5:d8 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::346d:d6ff:febd:d5d8/64 scope link
       valid_lft forever preferred_lft forever
27: vethc65a98f@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    link/ether e6:cf:79:d4:aa:7a brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::e4cf:79ff:fed4:aa7a/64 scope link
       valid_lft forever preferred_lft forever
57: veth714e7ab@if56: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    link/ether 1e:c2:a5:02:f6:ee brd ff:ff:ff:ff:ff:ff link-netnsid 3
    inet6 fe80::1cc2:a5ff:fe02:f6ee/64 scope link
       valid_lft forever preferred_lft forever

1 个答案:

答案 0 :(得分:2)

我没有关于即将推出的解决方案的信息,但我怀疑任何解决方法都会涉及阻止实例连接到自身,而是始终连接到不同的实例...或者可能使用平衡器的源地址进行发夹连接而不是源自地址。

基本问题是:平衡器通过与网络基础设施集成,进行网络地址转换,在出路时更改原始目标地址以及返回途中的源地址来工作,以便实例在目标组看到客户端的真实源地址,但不是相反...但这与非对称路由不兼容。当实例最终与自己交谈时,路线非常不对称。

假设平衡器为172.30.1.100,实例为172.30.2.200。

TCP连接从172.30.2.200(实例)启动到172.30.1.100(平衡器)。端口并不重要,但我们假设源端口为49152(临时),平衡器目标端口为80,实例目标端口为8080。

172.30.2.200:49152 > 172.30.1.100:80 SYN

NLB是一个NAT设备,因此翻译成了:

172.30.2.200:49152 > 172.30.2.200:8080 SYN

将其发送回实例。

这已经没有意义,因为实例只是从外部获取了一个传入请求,即使它没有提出请求。

假设它响应,而不是删除已经是无意义的数据包,现在你有了这个:

172.30.2.200:8080 > 172.30.2.200:49152 SYN+ACK

如果172.30.2.200:49152实际上已经将数据包发送到172.20.2.200:8080,它将以ACK响应并建立连接。

但事实并非如此。

接下来发生的事情应该是这样的:

172.30.2.200:49152 > 172.30.2.200:8080 RST

与此同时,172.30.2.200:49152从172.30.1.100:80没有听到任何消息,所以它会重试然后最终放弃:Connection timed out

当源和目标机器不同时,NLB可以工作,因为它不是像ELB / ALB提供的那样的真实(虚拟)机器 - 它是由网络本身完成的。这是唯一可能的解释,因为具有已转换地址的那些数据包确实会使其返回到原始机器,而NAT发生在相反方向,并且只有在VPC网络保留这些连接的状态表并翻译它们时才会发生这种情况。

请注意,在VPC中,默认网关不是真实的。实际上,子网并不真实。以太网不是真实的。 (这一切都不是批评。这里有一些非常出色的工程证明。)所有这些都是由VPC网络基础设施中的软件模拟的。当同一子网上的两台机器直接相互通信时...好吧,他们没有.¹他们正在通过软件定义的网络进行交谈。因此,即使机器在同一子网上,网络也可以看到这些数据包并进行NLB所需的转换。

但是当机器正在与自己交谈时,不会发生这种情况,因为当这种情况发生时,流量永远不会出现在线路上 - 它仍然存在于单个虚拟机内部,超出了VPC网络基础设施的范围。

我不相信基于实例的解决方法是可行的。

¹他们没有。这是一个非常有趣的例子,用Wireshark监控同一子网上两个实例的流量。打开安全组,然后从另一个实例ping一个实例。源计算机发送ARP请求并且似乎从目标获得ARP响应...但是目标上没有此ARP交互的证据。那是因为它没有发生。网络处理目标实例的ARP响应。这是为什么不可能从另一个实例中欺骗一个实例的部分原因 - 伪造的数据包不会被网络转发,因为它们显然无效,并且网络知道它。发生ARP后,ping是正常的。流量似乎直接从实例转移到实例,基于第2层标头,但这不是实际发生的情况。