数据包过滤和防火墙

在 Linux 上,Docker 操纵iptables规则来提供网络隔离。虽然这是一个实现细节,您不应该修改 Docker 插入到您的策略中的规则iptables,但如果您除了 Docker 管理的策略之外还想要拥有自己的策略,它确实会对您需要执行的操作产生一些影响。

如果您在暴露于 Internet 的主机上运行 Docker,您可能需要制定 iptables 策略来防止对主机上运行的容器或其他服务进行未经授权的访问。本页介绍了如何实现这一目标,以及您需要注意的注意事项。

在 Docker 规则之前添加 iptables 策略

Docker 安装了两个名为和的自定义iptables链,它确保传入的数据包始终首先由这两个链检查。这些链条是链条的一部分。DOCKER-USERDOCKERFORWARD

Docker 的所有iptables规则都添加到DOCKER链中。请勿手动操作该链条。如果您需要添加在 Docker 规则之前加载的规则,请将它们添加到DOCKER-USER链中。这些规则在 Docker 自动创建任何规则之前应用。

添加到链中的其他规则(手动或通过另一个基于 iptables 的防火墙)在和链FORWARD之后进行评估。这意味着,如果您通过 Docker 发布端口,则无论您的防火墙配置了什么规则,该端口都会被发布。如果您希望即使在通过 Docker 发布端口时也应用规则,则必须将这些规则添加到链中。DOCKER-USERDOCKERDOCKER-USER

匹配请求的原始IP和端口

当数据包到达DOCKER-USER链时,它们已经通过了目标网络地址转换 (DNAT) 过滤器。这意味着 iptables您使用的标志只能匹配容器的内部 IP 地址和端口。

如果要根据网络请求中的原始IP和端口来匹配流量,则必须使用 conntrackiptables 扩展。例如:

$ sudo iptables -I DOCKER-USER -p tcp -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
$ sudo iptables -I DOCKER-USER -p tcp -m conntrack --ctorigsrc 1.2.3.4 --ctorigdstport 80 -j ACCEPT

重要的

使用conntrack扩展可能会导致性能下降。

限制与 Docker 主机的连接

默认情况下,允许所有外部源 IP 连接到 Docker 主机。要仅允许特定 IP 或网络访问容器,请在过滤器链的顶部插入否定规则DOCKER-USER。例如,以下规则限制来自除 之外的所有 IP 地址的外部访问192.168.1.1

$ iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.1 -j DROP

您需要进行更改ext_if以符合主机的实际外部接口。您可以改为允许来自源子网的连接。以下规则仅允许来自子网的访问192.168.1.0/24

$ iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.0/24 -j DROP

最后,您可以使用指定接受的 IP 地址范围--src-range (请记住-m iprange在使用--src-range或 时也添加--dst-range):

$ iptables -I DOCKER-USER -m iprange -i ext_if ! --src-range 192.168.1.1-192.168.1.3 -j DROP

您可以将-sor--src-range-d或组合起来--dst-range来控制源和目标。例如,如果 Docker 守护进程同时侦听 192.168.1.9910.1.2.3,您可以制定特定于 和 的规则10.1.2.3并保持 192.168.1.99打开状态。

iptables很复杂,更复杂的规则超出了本主题的范围。 有关更多信息,请参阅 Netfilter.org HOWTO 。

路由器上的 Docker

Docker 还将链的策略设置FORWARDDROP.如果您的 Docker 主机还充当路由器,这将导致该路由器不再转发任何流量。如果您希望系统继续充当路由器,您可以ACCEPT向链添加明确的规则DOCKER-USER以允许它:

$ iptables -I DOCKER-USER -i src_if -o dst_if -j ACCEPT

防止 Docker 操纵 iptables

可以在 Docker 引擎的配置文件中将iptables密钥设置为,但此选项不适合大多数用户。完全阻止 Docker 创建规则是不可能的,事后创建规则非常复杂,超出了这些说明的范围。设置为很可能会破坏 Docker 引擎的容器网络。false/etc/docker/daemon.jsoniptablesiptablesfalse

对于希望将 Docker 运行时构建到其他应用程序中的系统集成商,请探索该 moby项目

设置容器的默认绑定地址

默认情况下,Docker 守护进程将已发布的容器端口绑定到该0.0.0.0 地址。当您按如下方式发布容器的端口时:

docker run -p 8080:80 nginx

这会将端口 8080 发布到主机上的所有网络接口,从而可能使它们可供外界使用。除非您在内核级别禁用了 IPv6,否则该端口将在 IPv4 和 IPv6 上发布。

您可以更改已发布容器端口的默认绑定地址,以便默认情况下它们只能由 Docker 主机访问。为此,您可以将守护程序配置为使用环回地址 ( 127.0.0.1)。为此,请"ip"daemon.json配置文件中配置密钥:

{
  "ip": "127.0.0.1"
}

这会将默认绑定地址更改为127.0.0.1默认桥接网络上已发布容器端口的默认绑定地址。重新启动守护程序以使此更改生效。或者,您可以dockerd --ip在启动守护程序时使用该标志。

笔记

更改默认绑定地址不会对 Swarm 服务产生任何影响。 Swarm 服务始终暴露在0.0.0.0网络接口上。

要为用户定义的桥接网络配置此设置,请在创建网络时使用com.docker.network.bridge.host_binding_ipv4 驱动程序选项。

$ docker network create mybridge \
  -o "com.docker.network.bridge.host_binding_ipv4=127.0.0.1"

与firewalld集成

如果您运行 Docker 时将iptables选项设置为true,并且 在系统上启用了firewalldfirewalld ,则 Docker 会自动创建一个名为 的区域docker,并将其创建的所有网络接口(例如docker0)插入到该docker区域中以允许无缝联网。

Docker 和 ufw

Uncomplicated Firewall (ufw) 是 Debian 和 Ubuntu 附带的前端,它允许您管理防火墙规则。 Docker 和 ufw 使用 iptables 的方式使它们彼此不兼容。

当您使用 Docker 发布容器的端口时,进出该容器的流量在通过 ufw 防火墙设置之前会被转移。 Docker 在表中路由容器流量nat,这意味着数据包在到达ufw 使用的链INPUT之前会被转移。OUTPUT数据包在应用防火墙规则之前进行路由,从而有效地忽略您的防火墙配置。