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