问题
这个问题已经存在很长时间了。
在Docker中禁用iptables会带来其他问题。
先回滚更改
如果您已根据我们在Internet上找到的当前解决方案修改了服务器,请首先回滚这些更改,包括:
- 启用Docker的iptables功能。删除所有类似的更改
--iptables=false
,包括配置文件/etc/docker/daemon.json
。
- UFW的默认FORWARD规则改回默认设置,
DROP
而不是ACCEPT
。
- 在UFW配置文件中删除与Docker网络相关的规则
/etc/ufw/after.rules
。
- 如果您已修改Docker配置文件,请首先重新启动Docker。稍后我们将修改UFW配置,然后可以重新启动它。
解决UFW和Docker问题
该解决方案仅需修改一个UFW配置文件,所有Docker配置和选项均保持默认。不需要禁用docker iptables功能。
修改UFW配置文件,/etc/ufw/after.rules
并在文件末尾添加以下规则:
# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
-A DOCKER-USER -j ufw-user-forward
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
-A DOCKER-USER -j RETURN
COMMIT
# END UFW AND DOCKER
sudo systemctl restart ufw
更改文件后,使用命令重新启动UFW。现在,公共网络无法访问任何已发布的docker端口,容器和专用网络可以定期相互访问,并且容器还可以从内部访问外部网络。
例如,如果要允许公共网络访问Docker容器提供的服务,则容器的服务端口为80
。运行以下命令以允许公共网络访问此服务:
ufw route allow proto tcp from any to any port 80
该命令允许公用网络访问容器端口为80的所有已发布端口。
注意:如果使用选项发布端口-p 8080:80
,则应使用容器端口80
,而不是主机端口8080
。
如果有多个容器的服务端口为80,但是我们只希望外部网络访问特定的容器。例如,如果容器的专用地址是172.17.0.2,请使用以下命令:
ufw route allow proto tcp from any to 172.17.0.2 port 80
如果服务的网络协议是UDP,例如DNS服务,则可以使用以下命令允许外部网络访问所有已发布的DNS服务:
ufw route allow proto udp from any to any port 53
同样,如果仅针对特定容器,例如IP地址172.17.0.2:
ufw route allow proto udp from any to 172.17.0.2 port 53
这个怎么运作?
以下规则允许专用网络能够相互访问。通常,专用网络比公用网络更受信任。
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
以下规则允许UFW管理是否允许公共网络访问Docker容器提供的服务。这样我们就可以在一个地方管理所有防火墙规则。
-A DOCKER-USER -j ufw-user-forward
以下规则阻止所有公共网络发起的连接请求,但允许内部网络访问外部网络。对于TCP协议,它会阻止从公共网络主动建立TCP连接。对于UDP协议,将阻止所有对小于32767的端口的访问。为什么是这个港口?由于UDP协议是无状态的,因此不可能像TCP一样阻塞发起连接请求的握手信号。对于GNU / Linux,我们可以在文件中找到本地端口范围/proc/sys/net/ipv4/ip_local_port_range
。默认范围是32768 60999
。从正在运行的容器访问UDP协议服务时,将从端口范围中随机选择一个本地端口,服务器会将数据返回到该随机端口。因此,我们可以假定所有容器中UDP协议的侦听端口都小于32768。这就是我们不希望公共网络访问小于32768的UDP端口的原因。
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
-A DOCKER-USER -j RETURN
更多
https://github.com/chaifeng/ufw-docker
sudo wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
chmod +x /usr/local/bin/ufw-docker
用法
ufw-docker help
ufw-docker install
ufw-docker status
ufw-docker allow webapp
ufw-docker allow webapp 80
ufw-docker allow webapp 53/udp
ufw-docker list webapp
ufw-docker delete allow webapp 80/tcp
ufw-docker delete allow webapp
更新时间:2018-09-10
选择的原因ufw-user-forward
,不是ufw-user-input
使用 ufw-user-input
优点:
易于使用和理解,支持旧版本的Ubuntu。
例如,要允许公众访问容器端口为的已发布端口8080
,请使用以下命令:
ufw allow 8080
缺点:
它不仅公开容器的端口,而且公开主机的端口。
例如,如果服务正在主机上运行,并且端口为8080
。该命令ufw allow 8080
允许公共网络访问服务以及容器端口为的所有已发布端口8080
。但是我们只想公开运行在主机上的服务,或者只公开运行在容器内的服务,而不是同时公开两者。
为避免此问题,我们可能需要对所有容器使用类似于以下命令:
ufw allow proto tcp from any to 172.16.0.3 port 8080
使用 ufw-user-forward
优点:
无法通过同一命令公开同时在主机和容器上运行的服务。
例如,如果我们要发布8080
容器的端口,请使用以下命令:
ufw route allow 8080
公用网络可以访问其容器端口为的所有已发布端口8080
。
但是8080
主机的端口仍然不能被公共网络访问。如果要这样做,请执行以下命令以允许公共用户单独访问主机上的端口:
ufw allow 8080
缺点:
不支持旧版本的Ubuntu,命令更加复杂。但是您可以使用我的脚本https://github.com/chaifeng/ufw-docker。
结论
如果我们使用的是旧版本的Ubuntu,则可以使用ufw-user-input
chain。但是请小心避免暴露不应公开的服务。
如果我们正在使用支持ufw route
子命令的较新版本的Ubuntu,则最好使用ufw-user-forward
chain,并使用ufw route
命令来管理容器的防火墙规则。
更新:2018年10月6日
脚本ufw- docker现在支持Docker Swarm。请查看最新代码以获取更多信息,https://github.com/chaifeng/ufw-docker
以Docker Swarm模式安装
在以Swarm模式使用时,我们只能在管理器节点上使用此脚本来管理防火墙规则。
- 修改所有
after.rules
节点上的所有文件,包括管理人员和工作人员
- 在管理器节点上部署此脚本
在Docker Swarm模式下运行,此脚本将添加全局服务ufw-docker-agent
。图像chaifeng / ufw-docker-agent也从该项目中自动构建。
iptables -N DOCKER
用该名称启动一个新链...也许您可以保持iptables启用(我的意思是不删除--iptables=false
,然后就可以为链启动运行“ post命令”。我没有最佳实践的答案o_O