悠米是只猫

悠米是只猫

Docker与iptables:网络隔离与防火墙配置指南

2025-04-03

Docker网络隔离基础

在Linux系统上,Docker使用iptablesip6tables规则来实现网络隔离、端口发布和过滤功能。

重要提示:

  • 这些规则是Docker桥接网络正常运行所必需的,不应修改Docker创建的规则

  • 如果Docker主机暴露在互联网上,应该添加iptables策略来防止对容器或主机上其他服务的未授权访问

  • Docker仅为桥接网络创建iptables规则,不会为ipvlan、macvlan或主机网络创建规则

Docker的iptables链结构

在filter表中,Docker将默认策略设置为DROP,并创建以下自定义iptables链:

  • DOCKER-USER:用户定义规则的占位符,会在DOCKER-FORWARD和DOCKER链之前处理

  • DOCKER-FORWARD:Docker网络处理的第一阶段

  • DOCKER:决定是否应接受非已建立连接的包

  • DOCKER-ISOLATION-STAGE-1/2:隔离不同Docker网络的规则

  • DOCKER-INGRESS:与Swarm网络相关的规则

在FORWARD链中,Docker添加无条件跳转到DOCKER-USER、DOCKER-FORWARD和DOCKER-INGRESS链的规则。

在nat表中,Docker创建DOCKER链并添加规则来实现伪装和端口映射。

在Docker规则前添加iptables策略

要过滤这些数据包,应在DOCKER-USER链中添加额外规则,因为:

  • 被这些自定义链接受或拒绝的数据包不会被附加到FORWARD链的用户定义规则看到

  • 附加到FORWARD链的规则会在Docker规则之后处理

匹配原始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 --ctorigdst 198.51.100.2 --ctorigdstport 80 -j ACCEPT

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

端口发布与映射

默认情况下,守护程序会阻止访问未发布的端口。发布的容器端口会映射到主机IP地址,Docker使用iptables执行:

  • 网络地址转换(NAT)

  • 端口地址转换(PAT)

  • 伪装

例如,docker run -p 8080:80 [...]会在Docker主机的任何地址上的8080端口与容器的80端口之间创建映射。

限制容器外部连接

默认情况下,允许所有外部源IP连接到已发布到Docker主机地址的端口。

要限制访问,可在DOCKER-USER过滤器链顶部插入否定规则:

  1. 只允许特定IP(192.0.2.2)访问:

iptables -I DOCKER-USER -i ext_if ! -s 192.0.2.2 -j DROP
  1. 只允许子网(192.0.2.0/24)访问:

iptables -I DOCKER-USER -i ext_if ! -s 192.0.2.0/24 -j DROP
  1. 使用IP范围:

iptables -I DOCKER-USER -m iprange -i ext_if ! --src-range 192.0.2.1-192.0.2.3 -j DROP

直接路由

端口映射确保发布的端口可在主机的网络地址上访问。但特别是对于IPv6,您可能希望避免使用NAT,而是为容器地址设置外部路由("直接路由")。

要从Docker主机外部访问桥接网络上的容器,必须通过Docker主机上的地址设置到桥接网络的路由。

网关模式

桥接网络驱动程序有以下选项:

  • com.docker.network.bridge.gateway_mode_ipv6

  • com.docker.network.bridge.gateway_mode_ipv4

每种模式可设置为以下之一:

  • nat(默认):为每个发布的容器端口设置NAT和伪装规则

  • nat-unprotected:未发布的容器端口也可通过直接路由访问

  • routed:不设置NAT或伪装规则,但iptables仍设置为仅可访问发布的容器端口

  • isolated:只能与--internal标志一起使用

设置容器默认绑定地址

默认情况下,当映射容器端口而未指定特定主机地址时,Docker守护程序会将发布的容器端口绑定到所有主机地址(0.0.0.0和[::])。

要更改默认绑定地址,可以配置守护程序使用环回地址(127.0.0.1):

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

对于默认桥接网络,在daemon.json中配置:

{
  "ip": "127.0.0.1"
}

路由器上的Docker

在Linux上,Docker需要主机启用"IP转发"。因此,如果未启用,它会在启动时启用net.ipv4.ip_forwardnet.ipv6.conf.all.forwarding sysctl设置。

要防止Docker将FORWARD链的策略设置为DROP,可以在/etc/docker/daemon.json中包含"ip-forward-no-drop": true,或者向dockerd命令行添加--ip-forward-no-drop选项。

防止Docker操作iptables

可以将daemon配置中的iptables或ip6tables键设置为false,但此选项不适合大多数用户,因为它可能会破坏Docker引擎的容器网络。

与firewalld集成

如果在iptables选项设置为true的情况下运行Docker,并且系统上启用了firewalld,Docker会自动创建一个名为docker的firewalld区域,目标为ACCEPT。

Docker与ufw

Uncomplicated Firewall(ufw)是Debian和Ubuntu附带的前端,可让您管理防火墙规则。Docker和ufw以不兼容的方式使用iptables。

当您使用Docker发布容器端口时,进出该容器的流量会在通过ufw防火墙设置之前被转移。