阻止外部访问Docker容器

3
我希望阻止外部直接访问docker容器。我使用haproxy,只想允许对端口80、443的访问。
我添加了以下规则到iptables,但我仍然可以通过其他端口访问docker容器。
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
COMMIT

这可能是由于DOCKER链所致。
# iptables -L
Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
ACCEPT     icmp --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
ACCEPT     tcp  --  anywhere             anywhere             state NEW tcp dpt:ssh
ACCEPT     tcp  --  anywhere             anywhere             state NEW tcp dpt:http
ACCEPT     tcp  --  anywhere             anywhere             state NEW tcp dpt:https

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
DOCKER-ISOLATION  all  --  anywhere             anywhere
DOCKER     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
DOCKER     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
DOCKER     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
DOCKER     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain DOCKER (4 references)
target     prot opt source               destination
ACCEPT     tcp  --  anywhere             172.18.0.2           tcp dpt:http

Chain DOCKER-ISOLATION (1 references)
target     prot opt source               destination
DROP       all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere
RETURN     all  --  anywhere             anywhere

我需要创建哪些规则来阻止直接访问?


你是在测试来自外部机器的连接吗?否则,主机上的本地路由表将按设计直接连接到容器网络。请参见 netstat -nr - BMitch
是的,我正在通过互联网从另一台机器进行测试。 - Chris
4个回答

5
不要使用IP表来操作,你可以使用docker network create NETWORK命令创建一个网络,将你的应用程序和代理连接起来。同时不要在任何端口暴露应用程序。唯一应该暴露的容器是你的代理。从代理中,你可以通过容器名称作为主机名来路由流量。同一网络中的每个容器都可以被其他容器访问。
例如:
- 我有一个名为my-service的容器A,在3000端口上运行服务,并且没有向主机发布任何端口。 - 容器B是一个代理,在80端口上运行,已发布到主机。我的代理可以将请求传递到http://my-service:3000,并将流量路由到容器。 - 如果我尝试访问http://mydomain:3000,这将不起作用,因为端口没有暴露,唯一访问应用程序的方式是通过80端口的代理。
建议阅读https://docs.docker.com/engine/userguide/networking/work-with-networks/了解如何开始使用网络。
完整披露:我在自己的VPS上运行这种设置,不能直接通过端口访问我的容器。使用内置的Docker网络会比操作IP表更好。
希望对你有所帮助。
Dylan

我猜你的解决方案只有在 haproxy 也在 Docker 容器内运行时才有效? - Chris
是的,我猜这对你来说可能不是一个选项?我喜欢这种方法,因为它使应用程序/服务升级更容易,并且提供了额外的安全性,而无需处理操作系统防火墙。 - Dylan Scott
我会尝试一下。 - Chris

4
I realize I'm responding to an old thread, but I've spent most of a morning frustrated by this problem. This post shows at the top of a google search, but I feel the accepted answer does not answer the OP's question, but instead offers a different design as a way of avoiding the problem stated in the original question. That solution requires standing up a new docker image to act as a gateway to the original docker.
It is possible the following information was not available at the time of the original question, but what I found from Docker.com is this link https://docs.docker.com/network/iptables/ which appears to answer the original question when it states:
"默认情况下,所有外部源IP都可以连接到Docker守护程序。要允许仅特定IP或网络访问容器,请在DOCKER过滤器链的顶部插入一个否定规则。例如,以下规则限制对所有IP地址的外部访问,除了192.168.1.1:$ iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.1 -j DROP"

"如果您需要添加在Docker规则之前加载的规则,请将它们添加到DOCKER-USER链中。"

但遗憾的是,我已经尝试过这个解决方案,但在docker版本17.05.0-ce上似乎也无法工作。


3
正如@dpg所指出的,如果你需要从新手角度解决这个问题,那么这个问题会让人沮丧。
对我来说(我也试图解决@dpg回答中的问题),主要问题在于Docker文档在两个涉及此问题的页面(link1link2)上存在混淆。
总结一下,为了节省时间,如果你对Docker和iptables不是很了解,那么答案就在那里,只是他们错过了这一点:其中ext_if是提供主机外部连接的接口的名称。 相反,在“理解容器通信”链接中,确实有一小段文字准确地指出ext_if应该是网络接口。

因此,如果我想限制对 Docker 暴露的端口(例如:6782)的访问(这意味着需要修改 DOCKER-USER 而不是常规 INPUT 链),只允许某个 IP(例如:192.27.27.90)访问并限制其他所有人,则需要执行以下操作,这在我的情况下有效

sudo iptables -I DOCKER-USER -p tcp -i eth0 ! -s 192.27.27.90 --dport 6782 -j REJECT

(这里假设与外界通信的网络接口是eth0,而你想用REJECT代替DROP)。

如果需要更多的澄清,我很乐意提供帮助。


2

针对@Ezarate11的评论(由于我的声望不够,无法进行评论),请确保--dport是转发到的端口,而不是暴露的端口。

例如,如果您的配置是0.0.0.0:64743->80,则需要执行以下操作:

sudo iptables -I DOCKER-USER -p tcp -i eth0 ! -s 192.27.27.90 --dport 80 -j REJECT

这个细节让我花了一些时间才搞明白,我没有在其他地方看到过提到这点。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接