使用“-p <port>:<port>”时,Docker忽略iptable规则

时间:2015-06-11 00:57:12

标签: docker iptables

几天前刚刚意识到Docker似乎绕过了我的iptable规则。我对Docker和iptables的体验并不令人难以置信。在最后的日子里尝试了很多不同的事情。还看到最近的docker版本有一个很大的变化,特殊的DOCKER链应该允许我这样做。但是不确定我做错了什么,但它永远不会做我期望它做的事。

所以我想要的很简单。我希望它表现得像预期的那样。如果我有一个ACCEPT-Rule要通过,如果没有它被阻止。

我的iptable最初看起来像那样(所以在我多次尝试失败之前):

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [779:162776]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -s 1.2.3.4 -p tcp -m tcp --dport 123 -j ACCEPT
-A INPUT -j DROP
COMMIT

希望它完全符合我的要求。只允许访问端口22和80,并允许来自ip 1.2.3.4的端口123。但是,如果我使用“-p 123:123”创建容器,则每个人都可以访问它。任何人都可以帮助我并告诉我如何更改上述文件?

谢谢!

Docker-Version:1.6.2

编辑:

离开我最初的不同尝试不会使问题过于复杂。但是,添加其中至少一个可能会有所帮助。

*nat
:PREROUTING ACCEPT [319:17164]
:INPUT ACCEPT [8:436]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [16:960]
:DOCKER - [0:0]
COMMIT


*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [779:162776]
:DOCKER - [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A DOCKER -s 1.2.3.4 -p tcp -m tcp --dport 123 -j ACCEPT
-A DOCKER -j DROP
-A INPUT -j DROP
COMMIT

以上的作品。然而,还有很多其他问题。例如,我遇到容器链接问题,DNS不再工作,等等。因此,最后添加了许多额外的规则来解决这些问题,但我从未进入正常运行的状态。所以我想那里有更好更简单的解决方案。

解决方案:

完全或多或少地做了larsks所说的话。只是没有将它添加到FORWARD链中,我将其添加到DOCKER链中。 FORWARD链的问题在于Docker在第一个位置重新启动时会在其中添加它的东西。这导致我的规则被压低而没有任何影响。但是对于DOCKER链,似乎Docker只附加了额外的规则,因此我的工作仍然有效。因此,当我保存规则然后重新启动服务器时,一切仍然正常。

所以现在看起来或多或少是这样的:

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [779:162776]
:DOCKER - [0:0]
# That I can access from IP 1.2.3.4
-A DOCKER -s 1.2.3.4/32 -p tcp -m tcp --dport 123 -j ACCEPT
# That I can access from other Docker containers
-A DOCKER -o docker0 -p tcp -m tcp --dport 123 -j ACCEPT
# Does not allow it for anything else
-A DOCKER -p tcp --dport 123 -j DROP

-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -j DROP
COMMIT

5 个答案:

答案 0 :(得分:7)

我不是iptables的专家,但我知道如果你使用-p 127.0.0.1:123:123运行容器,那么端口不会在所有接口上公开,只是在环回上。

答案 1 :(得分:4)

你的iptables配置现在看起来有点破,好像你在某些时候清除了它而没有重新启动Docker。例如,DOCKERfilter表中都有nat链,但没有引用它的规则,因此放在该链中的规则不会产生任何影响。

通常,如果要实现影响Docker容器的iptables规则,则需要将它们放在FORWARD表的filter链中。每个容器都有自己的 IP地址,这意味着您的主机只是接受数据包,然后FORWARD将它们添加到容器地址。

INPUT链中的规则仅适用于主机全局网络命名空间中接口上具有地址的最终目的地的数据包。

但是,我不确定iptables实际上是你的问题。

如果您尝试在容器中公开服务以使其可供其他系统使用,则需要使用-p标记将这些端口发布到docker run。您可以阅读更多相关信息 在文档的this section中。

如果您想使用您要完成的具体示例来更新您的问题,我可以提供更具针对性的答案。

<强>更新

当您使用-p发布容器端口时,它通常可用于任何源IP地址。要限制对已发布端口的访问,您需要向FORWARD链添加新规则。例如,如果我启动Web服务器:

docker run --name web -p 80:8080 larsks/mini-httpd

容器中的Web服务器现在可在我的主机上的端口8080上使用。如果我想阻止访问此端口,我需要在FORWARD链中插入一条规则,阻止访问容器ip上的端口80。所以首先我需要容器ip地址:

$ web_ip=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' web)
$ echo $web_ip
172.17.0.5

我在FORWARD链中创建的规则需要在 docker创建的规则之前,所以我需要指定一个明确的位置:

iptables -I FORWARD 1 -d $web_ip -p tcp --dport 80 \! -s 192.168.1.10 -j DROP

这将阻止来自192.168.1.10以外的主机的所有流量。

如果您希望将规则应用于所有容器而不是特定容器,则可以将其绑定到docker0接口而不是特定的IP地址:

-A FORWARD -o docker0 -p tcp --dport 80 \! -s 192.168.1.10 -j DROP

这将禁止访问任何容器上的端口80。

答案 2 :(得分:2)

  

完全或多或少地做了larsks所说的话。只是没有添加   它转发到FORWARD链,我将它添加到DOCKER链中。

我在文档中发现了相同内容:https://docs.docker.com/v1.5/articles/networking/#the-world

  

Docker不会从中删除或修改任何预先存在的规则   DOCKER过滤链。此允许用户提前创建   进一步限制对容器的访问所需的规则。

     

Docker的转发规则默认允许所有外部源IP。 要   只允许特定的IP或网络访问容器,插入一个   否定了DOCKER过滤器链顶部的规则。例如,到   限制外部访问,以便只有源IP 8.8.8.8可以访问   容器,可以添加以下规则:

$ iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP

答案 3 :(得分:1)

要在来自 docker 容器的已发布端口上使用 iptables,您需要综合考虑:

  • DOCKER-USER 表:docker 将此表用于影响容器的 iptables 规则,并专门为用户提供的规则保留,docker 引擎在重新启动时不会覆盖这些规则。
  • conntrack:端口转发可以在一个端口上发布并转发到容器中的另一个端口。您可以让多个容器都侦听端口 80,并在主机上使用不同的已发布端口。

要使用这些,生成的 iptables 规则如下所示:

Select [Date].[1].[1].[2014], [Date].[1].[1].[2015], [Date].[1].[2].[2014], [Date].[1].[2].[2015] 

这会处理对已发布端口 8080/tcp(在主机上,容器可能正在侦听 80 或任何其他端口)的请求,并且只接受来自 10.0.0.0/24 子网的请求。该子网之外的所有内容都将被丢弃。

请注意,DOCKER-USER 表有一个默认规则可以立即返回,因此所有更改都应在表中该默认规则之前插入。

答案 4 :(得分:0)

我需要从多个子网通过主机端口1234访问docker容器,并使用以下命令(Debian Stretch,docker 18.06):

iptables -I DOCKER-USER                  -p tcp --dport 1234 -j REJECT
iptables -I DOCKER-USER -s 18.204.0.0/16 -p tcp --dport 1234 -j RETURN
iptables -I DOCKER-USER -s 34.192.0.0/16 -p tcp --dport 1234 -j RETURN
iptables -I DOCKER-USER -s 35.153.0.0/16 -p tcp --dport 1234 -j RETURN
iptables -I DOCKER-USER -s 13.56.63.0/24 -p tcp --dport 1234 -j RETURN

结果:

iptables -L DOCKER-USER -n -v --line-numbers

Chain DOCKER-USER (1 references)
pkts bytes target     prot opt in     out     source               destination
0     0 RETURN     tcp  --  *      *       13.56.63.0/24        0.0.0.0/0            tcp dpt:1234
0     0 RETURN     tcp  --  *      *       35.153.0.0/16        0.0.0.0/0            tcp dpt:1234
0     0 RETURN     tcp  --  *      *       34.192.0.0/16        0.0.0.0/0            tcp dpt:1234
0     0 RETURN     tcp  --  *      *       18.204.0.0/16        0.0.0.0/0            tcp dpt:1234
0     0 REJECT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:1234 reject-with icmp-port-unreachable

背景:

所有规则均按照当前Docker文档的建议添加到链DOCKER-USER中。

第一个规则的目标是REJECT,最后将成为最后一个规则,因为其他规则被添加到顶部(没有位置编号的选项-I对应于在位置1添加一个规则)。所有目标端口为1234的软件包都将被拒绝。

其他规则以RETURN为目标,即,目标端口为1234且来自给定子网之一的源IP的数据包将返回到调用链,即FORWARD链。

iptables -L FORWARD -n -v
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in     out     source               destination
16471 4568K DOCKER-USER  all  --  *      *       0.0.0.0/0            0.0.0.0/0
16413 4565K DOCKER-ISOLATION-STAGE-1  all  --  *      *       0.0.0.0/0            0.0.0.0/0
7173 2060K ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
45  2340 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0

FORWARD链中,它将由DOCKER链进行处理,在我的情况下,它将根据需要转发到Docker容器:

iptables -L DOCKER -n -v
Chain DOCKER (1 references)
pkts bytes target     prot opt in     out     source               destination
45  2340 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.2           tcp dpt:1234