我们有一个从传统服务迁移到docker的系统。我们只想在生产环境中使用防火墙,因此我们希望iptables配置只在服务器中,而不是在docker的配置中。
我们有以下要求:
- 服务器之间可以互相通信。
- 您可以 ping 服务器
- 你可以通过 SSH
- 您可以通过某些端口访问服务器的某些网络服务。
经过几个小时/几天的阅读后,我得到了以下配置:
# Delete old entries if any
iptables -F INPUT
iptables -F DOCKER-USER
iptables -F OUTPUT
# Set firewall
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # Allow established connections
iptables -A INPUT -i lo -j ACCEPT # Allow localhost communication
iptables -A OUTPUT -o lo -j ACCEPT # Allow output to the internet from localhost
iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT # Allow ICMP
iptables -A INPUT -p tcp --dport 22 -j ACCEPT # Allow SSH
iptables -A INPUT -j DROP # Drop eveything else
# Docker specific, allow connections to the ports of the web services:
iptables -A DOCKER-USER -i ens192 -s 192.168.69.0/24 -p tcp -m conntrack --ctorigdstport 8080 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i ens192 -s 192.168.69.0/24 -p tcp -m conntrack --ctorigdstport 9000 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i ens192 -s 192.168.69.0/24 -p tcp -m conntrack --ctorigdstport 19900 --ctdir ORIGINAL -j ACCEPT
iptables -A DOCKER-USER -i docker0 -j ACCEPT # Allow input from other containers
iptables -A DOCKER-USER -i ens192 -j DROP # Drop all access to the containers through default interface
在此刻:
- 如果我不在该子网中,我就无法访问网络服务。
- 我可以 ping 通并且可以通过 ssh 连接。
- 容器之间可以互相通信。因此,大多数要求都得到了满足。
但是现在当我们尝试从容器访问互联网时,它无法访问。(例如 ping 到 google 或本地网络)。但是从本地主机可以访问。
我尝试了很多选项,例如以下多种组合:
iptables -A DOCKER-USER -o docker0 -j ACCEPT
iptables -A OUTPUT -o docker0 -j ACCEPT
iptables -A DOCKER-USER -o ens192 -j ACCEPT
但它们似乎都不允许我从 docker 容器中 ping 东西。
答案1
我认为你想得太多了,因为docker
它带有一些合理的默认配置,并且还会自动管理。例如,在默认设置中,容器无法通过外部网络访问,但它们可以自己连接到互联网。
因此你应该EXPOSE
将容器的相关端口绑定到主机的外部 IP 上,或者绑定到主机的环回接口,然后将容器视为在主机上运行的普通服务!
例如,如果您正在运行 Web 服务并将docker
其绑定到相应的主机端口:
docker run -p 80:80 -p 443:443 ...
然后配置您的iptables
以将所需端口和DROP
其他所有内容列入白名单:
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # Allow established connections
iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT # Allow ICMP
iptables -A INPUT -p tcp --dport 22 -j ACCEPT # Allow SSH
iptables -A INPUT -p tcp --dport 80 -j ACCEPT # Allow HTTP
iptables -A INPUT -p tcp --dport 443 -j ACCEPT # Allow HTTPS
iptables -A INPUT -j DROP # Drop eveything else
关于内部网络设置、允许/阻止来自/到容器的连接以及转发暴露端口的所有其他事情都docker
已经为您处理好了。
这尤其意味着你绝对不应该做是为了弄乱DOCKER
链条,iptables
因为这些链条是由守护进程自动管理的docker
!
如上所述,在大多数情况下,默认值已经是你想要的。如果你需要更多的控制自定义配置,你需要禁用iptables
管理docker
并手动管理网络配置 - 通常这不是您想要做的。
您可以在docker
网络文档。
答案2
我认为我找到了一个可行的解决方案,但我不确定是否还有更好的方法。
通过我尝试的方法,我还必须声明为 DOCKER-USER 集建立的连接,与我的问题相比,添加了这两行:
iptables -A DOCKER-USER -i docker0 -j ACCEPT
> iptables -A DOCKER-USER -o docker0 -j ACCEPT
> iptables -A DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A DOCKER-USER -i ens192 -j DROP
答案3
根据您的问题,我假设这些 iptables 规则应该安装在 docker-host 上。
您在这里遗漏了一个中心点:防火墙规则仅对主机本身有效,对容器无效!
假设您的 docker0 接口的 IP 范围为 172.16.0.0/16。主机接口地址为 172.16.0.1,您的第一个容器的地址可能是 172.16.0.2。
但是,从容器到互联网的任何传出流量都需要从主机的主网络接口(即 ens192)发出。因此,任何用于容器的防火墙规则都必须位于 FORWARD 链内!(并且不要忘记为主机启用 ip_forwarding)