数据包过滤和防火墙
在 Linux 上,Docker 会创建规则并实施网络
隔离、端口发布和筛选。iptables
ip6tables
因为这些规则是 Docker bridge 正常运行所必需的 网络,则不应修改 Docker 创建的规则。
但是,如果您在公开到 Internet 的主机上运行 Docker,您将 可能想要添加 iptables 策略来防止对 容器或其他服务。本页介绍了如何操作 为了实现这一目标,以及您需要注意的注意事项。
注意
Docker 为桥接网络创建规则。
iptables
没有为 或 networking 创建规则。
iptables
ipvlan
macvlan
host
Docker 和 iptables 链
在表中,Docker 将默认策略设置为 ,并创建
以下定制链:filter
DROP
iptables
DOCKER-USER
- 将在规则之前处理的用户定义规则的占位符
在链中。
DOCKER
- 将在规则之前处理的用户定义规则的占位符
在链中。
DOCKER
- 确定不属于已建立的 应根据端口转发配置接受连接 正在运行的容器。
DOCKER-ISOLATION-STAGE-1
和DOCKER-ISOLATION-STAGE-2
- 将 Docker 网络彼此隔离的规则。
在链中,Docker 添加了传递不相关数据包的规则
与这些自定义链建立连接,以及接受的规则
属于已建立连接的数据包。FORWARD
在表中,Docker 创建链并添加要实现的规则
伪装和端口映射。nat
DOCKER
在 Docker 的规则之前添加 iptables 策略
被这些自定义链中的规则接受或拒绝的数据包将不会
被附加到链中的用户定义的规则看到。所以,要添加
要筛选这些数据包的其他规则,请使用 Chain.FORWARD
DOCKER-USER
匹配请求的原始 IP 和端口
当数据包到达链时,它们已经通过
目标网络地址转换 (DNAT) 筛选器。这意味着您使用的标志只能匹配
器皿。DOCKER-USER
iptables
如果要根据网络中的原始 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 --ctorigdst 198.51.100.2 --ctorigdstport 80 -j ACCEPT
重要
使用该扩展可能会导致性能下降。
conntrack
港口发布和映射
默认情况下,对于 IPv4 和 IPv6,守护程序会阻止对未阻止 已发布。已发布的容器端口将映射到主机 IP 地址。 为此,它使用 iptables 来执行网络地址转换 (NAT)、 端口地址转换 (PAT) 和伪装。
例如,创建一个映射
在 Docker 主机上任何地址的端口 8080 与容器的
端口 80。来自容器的传出连接将使用
Docker 主机的 IP 地址。docker run -p 8080:80 [...]
限制与容器的外部连接
默认情况下,允许所有外部源 IP 连接到具有 已发布到 Docker 主机的地址。
要仅允许特定 IP 或网络访问容器,请插入
在过滤器链的顶部否定规则。例如,
以下规则会丢弃来自所有 IP 地址的数据包,但 :DOCKER-USER
192.0.2.2
$ iptables -I DOCKER-USER -i ext_if ! -s 192.0.2.2 -j DROP
您需要进行更改以与您的
host 的实际外部接口。您可以改为允许来自
源子网。以下规则仅允许从子网访问 :ext_if
192.0.2.0/24
$ iptables -I DOCKER-USER -i ext_if ! -s 192.0.2.0/24 -j DROP
最后,您可以使用 (请记住在使用 或 时也要添加) 来接受 IP 地址范围 (请记住,在使用 or 时也要添加):--src-range
-m iprange
--src-range
--dst-range
$ iptables -I DOCKER-USER -m iprange -i ext_if ! --src-range 192.0.2.1-192.0.2.3 -j DROP
您可以将 OR 与 OR 结合使用,以控制两者
源和目标。例如,如果 Docker 主机具有地址 和 ,则可以使规则特定于 并保持开放状态。-s
--src-range
-d
--dst-range
2001:db8:1111::2
2001:db8:2222::2
2001:db8:1111::2
2001:db8:2222::2
iptables
很复杂。Netfilter.org HOWTO 中提供了更多信息。
直接路由
端口映射可确保已发布的端口可在主机的 网络地址,这些地址可能可路由给任何外部 客户。通常不会在主机的网络中为容器设置路由 主机中存在的地址。
但是,特别是对于 IPv6,您可能更愿意避免使用 NAT,而是使用 安排到容器地址的外部路由。
要从 Docker 主机外部访问桥接网络上的容器, 您必须通过 Docker 上的地址设置到桥接网络的路由 主机。这可以使用静态路由、边界网关协议来实现 (BGP) 或适用于您的网络的任何其他方式。
网桥网络驱动程序具有 options 和 。com.docker.network.bridge.gateway_mode_ipv6=<nat|routed>
com.docker.network.bridge.gateway_mode_ipv4=<nat|routed>
默认值为 ,NAT 并为每个 NAT 设置伪装规则
发布 Container Port。使用 mode ,无 NAT 或伪装规则
已设置,但仍会进行设置,以便仅发布容器
端口是可访问的。nat
routed
iptables
在模式下,or 端口映射中的主机端口为
not used,主机地址仅用于决定是否申请
到 IPv4 或 IPv6 的映射。因此,当映射仅适用于模式时,仅允许地址 或 主机端口
不得给予。routed
-p
--publish
routed
0.0.0.0
::1
映射的容器端口 (in 或 mode) 可从
任何远程地址(如果在网络中设置了路由),除非
Docker 主机的防火墙还有其他限制。nat
routed
例
创建适合 IPv6 直接路由的网络,并启用 NAT 对于 IPv4:
$ docker network create --ipv6 --subnet 2001:db8::/64 -o com.docker.network.bridge.gateway_mode_ipv6=routed mynet
创建具有已发布端口的容器:
$ docker run --network=mynet -p 8080:80 myimage
然后:
- 对于 IPv4 和 IPv6,将仅打开容器端口 80。它是可访问的 从任何地方,如果有到容器地址的路由,并访问 未被主机的防火墙阻止。
- 对于 IPv6,使用模式,端口 80 将在容器的 IP 上打开
地址。端口 8080 不会在主机的 IP 地址上打开,并且
传出数据包将使用容器的 IP 地址。
routed
- 对于 IPv4,使用默认模式时,容器的端口 80 将为
可通过主机 IP 地址上的端口 8080 访问,也可以直接访问。
源自容器的连接将使用
host 的 IP 地址。
nat
在 中,此端口映射将显示如下。请注意,
IPv6 没有,因为它正在使用模式:docker inspect
HostPort
routed
$ docker container inspect <id> --format "{{json .NetworkSettings.Ports}}"
{"80/tcp":[{"HostIp":"0.0.0.0","HostPort":"8080"},{"HostIp":"::","HostPort":""}]}
或者,要使映射仅 IPv6,请禁用对
容器的 80 端口,请使用未指定的 IPv6 地址,并且不要
包括主机端口号:[::]
$ docker run --network mynet -p '[::]::80'
设置容器的默认绑定地址
默认情况下,当容器的端口映射时没有任何特定主机
address,Docker 守护进程将已发布的容器端口绑定到所有主机
地址 ( 和 )。0.0.0.0
[::]
例如,以下命令将端口 8080 发布到所有网络 主机上的接口(IPv4 和 IPv6 地址)可能 使它们对外界可用。
docker run -p 8080:80 nginx
您可以更改已发布容器端口的默认绑定地址,以便
默认情况下,它们只能由 Docker 主机访问。为此,您可以
将守护进程配置为使用 loopback address () 来代替。127.0.0.1
警告
同一 L2 Segment 中的主机(例如,连接到同一 网络交换机)可以访问发布到 localhost 的端口。 有关更多信息,请参阅 moby/moby#45610
要为用户定义的桥接网络配置此设置,请使用
驱动程序选项。com.docker.network.bridge.host_binding_ipv4
$ docker network create mybridge \
-o "com.docker.network.bridge.host_binding_ipv4=127.0.0.1"
注意
- 将默认绑定地址设置为 表示没有主机的端口绑定 指定的地址将适用于主机上的任何 IPv6 地址。但是,是指任何 IPv4 或 IPv6 地址。
::
0.0.0.0
- 更改默认绑定地址对 Swarm 服务没有任何影响。 Swarm 服务始终暴露在网络接口上。
0.0.0.0
默认网桥
要为默认桥接网络设置默认绑定,请在配置文件中配置密钥:"ip"
daemon.json
{
"ip": "127.0.0.1"
}
这会将已发布容器的默认绑定地址更改为
默认桥接网络上的端口。
重新启动守护程序以使此更改生效。
或者,您可以在启动守护程序时使用该标志。127.0.0.1
dockerd --ip
路由器上的 Docker
Docker 将链的策略设置为 .这将阻止
您的 Docker 主机充当路由器。FORWARD
DROP
如果您希望您的系统充当路由器,则必须向链中添加显式规则。例如:ACCEPT
DOCKER-USER
$ iptables -I DOCKER-USER -i src_if -o dst_if -j ACCEPT
阻止 Docker 操作 iptables
可以在 daemon 配置中将 或 键设置为 ,但是
此选项不适用于大多数用户。它可能会破裂
Docker Engine 的容器联网。iptables
ip6tables
false
所有容器的所有端口都可以从网络访问,并且没有 将从 Docker 主机 IP 地址映射。
完全阻止 Docker 创建规则是不可能的,事后创建规则非常复杂,甚至超越
这些说明的范围。iptables
与 firewalld 集成
如果运行的 Docker 将选项设置为 ,并且系统上启用了 firewalld,则 Docker
使用 Target 自动创建名为 的区域 。iptables
true
firewalld
docker
ACCEPT
插入 Docker 创建的所有网络接口(例如 )
进入区域。docker0
docker
Docker 还创建了一个名为
从区域转发到区域。docker-forwarding
ANY
docker
Docker 和 ufw
Uncomplicated Firewall (ufw) 是 Debian 和 Ubuntu 附带的前端, 它还允许您管理防火墙规则。Docker 和 ufw 以多种方式使用 iptables 这使得它们彼此不兼容。
当您使用 Docker 发布容器的端口时,进出该端口的流量
容器在通过 UFW 防火墙设置之前被转移。
Docker 在表中路由容器流量,这意味着数据包
在到达 UFW 使用的 和 链之前被转移。
数据包在应用防火墙规则之前被路由,
有效地忽略了您的防火墙配置。nat
INPUT
OUTPUT