数据包过滤和防火墙
在 Linux 上,Docker 操纵iptables
规则来提供网络隔离。虽然这是一个实现细节,您不应该修改 Docker 插入到您的策略中的规则iptables
,但如果您除了 Docker 管理的策略之外还想要拥有自己的策略,它确实会对您需要执行的操作产生一些影响。
如果您在暴露于 Internet 的主机上运行 Docker,您可能需要制定 iptables 策略来防止对主机上运行的容器或其他服务进行未经授权的访问。本页介绍了如何实现这一目标,以及您需要注意的注意事项。
在 Docker 规则之前添加 iptables 策略
Docker 安装了两个名为和的自定义iptables
链,它确保传入的数据包始终首先由这两个链检查。这些链条是链条的一部分。DOCKER-USER
DOCKER
FORWARD
Docker 的所有iptables
规则都添加到DOCKER
链中。请勿手动操作该链条。如果您需要添加在 Docker 规则之前加载的规则,请将它们添加到DOCKER-USER
链中。这些规则在 Docker 自动创建任何规则之前应用。
添加到链中的其他规则(手动或通过另一个基于 iptables 的防火墙)在和链FORWARD
之后进行评估。这意味着,如果您通过 Docker 发布端口,则无论您的防火墙配置了什么规则,该端口都会被发布。如果您希望即使在通过 Docker 发布端口时也应用规则,则必须将这些规则添加到链中。DOCKER-USER
DOCKER
DOCKER-USER
匹配请求的原始IP和端口
当数据包到达DOCKER-USER
链时,它们已经通过了目标网络地址转换 (DNAT) 过滤器。这意味着
iptables
您使用的标志只能匹配容器的内部 IP 地址和端口。
如果要根据网络请求中的原始IP和端口来匹配流量,则必须使用
conntrack
iptables 扩展。例如:
$ 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
您可以将-s
or--src-range
与-d
或组合起来--dst-range
来控制源和目标。例如,如果 Docker 守护进程同时侦听
192.168.1.99
和10.1.2.3
,您可以制定特定于 和 的规则10.1.2.3
并保持
192.168.1.99
打开状态。
iptables
很复杂,更复杂的规则超出了本主题的范围。
有关更多信息,请参阅
Netfilter.org HOWTO 。
路由器上的 Docker
Docker 还将链的策略设置FORWARD
为DROP
.如果您的 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.json
iptables
iptables
false
对于希望将 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
数据包在应用防火墙规则之前进行路由,从而有效地忽略您的防火墙配置。