前言
在Linux上docker映射了端口,想着对服务端口进行限制指定IP访问,发现在filter表的INPUT链
限制无效。
[root@ext100 ~]# iptables -L -nv --line-numbers
Chain INPUT (policy ACCEPT 200K packets, 8397K bytes)
num pkts bytes target prot opt in out source destination
1 0 0 DROP tcp -- * * 192.168.4.200 0.0.0.0/0 tcp dpt:443
分析Docker容器启动防火墙上的变动
如果暴露本机端口,在nat表的DOCKER链上增加一条规则
DNAT tcp -- !<docker-network> 0.0.0.0/0 0.0.0.0/0 tcp dpt:<dest port> to:<new address>:<new port>
可以通过命令sudo iptables -t nat -nvL DOCKER查看。通过在nat表增加规则来drop掉所有访问容器暴露端口的连接
最后处理结果如下:
[root@ext100 ~]# iptables -L -nv --line-numbers
Chain DOCKER (2 references)
num pkts bytes target prot opt in out source destination
1 0 0 DROP tcp -- * * 192.168.4.202 0.0.0.0/0 tcp
2 3 180 DROP tcp -- * * 192.168.4.200 0.0.0.0/0 tcp
3 2 120 DROP tcp -- * * 192.168.4.200 0.0.0.0/0 tcp dpt:443
4 0 0 ACCEPT tcp -- !br-9c0d36154c4e br-9c0d36154c4e 0.0.0.0/0 172.18.0.11 tcp dpt:6379
知识
Configure the daemon and containers 在Linux上,Docker操纵iptables提供网络隔离的规则。虽然这是一个实现细节,您不应该修改Docker插入到您的iptables政策,如果你想在Docker管理的政策之外拥有自己的政策,它确实对你需要做的事情有一些影响。
如果您在一台暴露于互联网的主机上运行Docker,那么您可能希望有iptables策略来防止对容器或其他在您的主机上运行的服务的未授权访问。
在Docker规则之前添加iptables策略
Docker安装了两个定制的iptables链,名为DOCKER-USER和DOCKER
,它确保传入的数据包总是首先由这两个链检查。
Docker的所有iptables规则都被添加到Docker链中。不要手动操作该链条。如果您需要添加在Docker规则之前加载的规则,请将它们添加到DOCKER-USER链中。这些规则是在Docker自动创建任何规则之前应用的。
添加到转发链中的规则——无论是手动添加的,还是由另一个基于iptables的防火墙添加的——都会在这些链之后进行评估。这意味着如果您通过Docker暴露一个端口,无论您的防火墙配置了什么规则,该端口都会被暴露。如果您希望这些规则即使在端口通过Docker暴露时也适用,那么您必须将这些规则添加到DOCKER-USER链中。
限制与Docker主机的连接
默认情况下,允许所有外部源IP连接到Docker主机。要仅允许特定的IP或网络访问容器,请在DOCKER-USER过滤器链的顶部插入一个否定的规则。例如以下规则限制除192.168.1.1之外的所有IP地址的外部访问:
iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.1 -j DROP
请注意,您将需要更改ext_if以符合您的主机的实际外部接口。您可以允许来自源子网的连接。以下规则仅允许来自子网192.168.1.0/24的访问:
iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.0/24 -j DROP
最后,可以使用 --src-range 指定要接受的IP地址范围(请记住,在使用 --src-range或 --dst-range时。还要添加-m iprange):
iptables -I DOCKER-USER -m iprange -i ext_if ! --src-range 192.168.1.1-192.168.1.3 -j DROP
您可以将 -s/--src-range
与 -d/--dst-range
结合使用来控制源和目标。例如如果Docker守护进程监听192.168.1.99和10.1.2.3,您可以制定特定于10.1.2.3的规则,并保持192.168.1.99开放。Linux 2.4操作指南
Docker on a router
Docker还设置丢弃转发链的策略。如果您的Docker主机也充当路由器,这将导致该路由器不再转发任何流量。如果您希望您的系统继续充当路由器,您可以向DOCKER-USER链添加显式接受规则以允许它:
iptables -I DOCKER-USER -i src_if -o dst_if -j ACCEPT
防止Docker操纵iptables
可以在Docker引擎的配置文件/etc/docker/daemon.json
中将iptables键设置为false,但是该选项不适合大多数用户。完全阻止Docker创建iptables规则是不可能的,而且事后创建iptables规则非常复杂,超出了这些说明的范围。将iptables设置为false很可能会中断Docker引擎的容器网络。 对于希望将Docker运行时构建到其他应用程序中的系统集成商,可以探索moby项目。
为容器设置默认绑定地址
默认情况下Docker守护程序将暴露0.0.0.0地址上的端口,即主机上的任何地址。如果您想更改这种行为,只暴露内部ip地址上的端口,您可以使用 --ip 选项来指定不同的IP地址。但是设置- ip只会更改默认值,而不会将服务限制到该ip。
与防火墙的集成d
如果您运行的是docker版本20.10.0或更高版本,并且在系统上启用了firewalld并启用了iptables,则docker会自动创建一个名为Docker的firewalld区域,并将其创建的所有网络接口(例如docker0)插入到Docker区域中,以实现无缝联网。
考虑运行以下firewalld命令,从区域中删除docker接口。
# 请替换适当的区域和docker接口
firewall-cmd --zone=trusted --remove-interface=docker0 --permanent
firewall-cmd --reload
重新启动docker守护程序会将接口插入docker区域。
iptables规则永久生效
#1、安装iptables软件
yum install iptables -y && yum install iptables-services -y
systemctl start iptables.service && systemctl enable iptables.service
systemctl stop firewalld.service && systemctl mask firewalld.service
#2、在DOCKER-USER链上配置规则
iptables -I DOCKER-USER -m iprange -i ens33 ! --src-range 192.168.1.11-192.168.1.13 -j DROP
[root@master ~]# iptables -L DOCKER-USER -n
Chain DOCKER-USER (1 references)
target prot opt source destination
DROP all -- 0.0.0.0/0 0.0.0.0/0 source IP range ! 192.168.1.11-192.168.1.13
RETURN all -- 0.0.0.0/0 0.0.0.0/0
#3、将我们配置好的规则保存到备份配置文件中
service iptables save
iptables: Saving firewall rules to /etc/sysconfig/iptables:[ 确定 ]
如果安装了iptables软件,则必须设置开机自启,否则即使保存了iptables的配置文件,重启服务器后之前在DOCKER-USER链上配置的规则也会失效。原因分析:
服务器重启后,iptables服务先启动启动后会去加载备份的配置文件,但是此时docker服务还未启动,DOCKER规则链还未创建,所以虽然iptables有加载我们备份的配置,但他没法加载DOCKER规则链上的内容,从而导致我们写的DOCKER规则链上的规则没有成功加载,而docker启动后,DOCKER规则链就存在了,这时不管是手动让iptables加载配置文件还是直接重启iptables让他自己再读一遍配置,我们备份的DOCKER规则就都能成功加载了。
iptables-restore < /etc/sysconfig/iptables
实例
[root@master ~]# docker run -itd -p 80:80 --name qq httpd bash
启动docker后,在防火墙上nat表上会自动生成如下配置:
# 查看DOCKER链规则
[root@master ~]# iptables -S -t nat
-A DOCKER -i docker0 -j RETURN
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.0.2:80
[root@master ~]# iptables -L -nv --line-numbers -t nat
Chain PREROUTING (policy ACCEPT 4 packets, 281 bytes)
num pkts bytes target prot opt in out source destination
1 2 1472 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT 4 packets, 281 bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 30 packets, 2368 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT 30 packets, 2368 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
2 0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80
Chain DOCKER (2 references)
num pkts bytes target prot opt in out source destination
1 0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
2 0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.2:80
将docker 80端口映射到本机80端口,现在需要对80端口进行限制端口访问
在filter表中指定DOCKER 链,端口指定为在docker中的端口
-t filter -I DOCKER -s 192.168.1.1 -p tcp -m tcp --dport 80 -j DROP #拒绝特定端口
-t filter -I DOCKER -s 192.168.1.1 -p tcp -m tcp -j DROP #拒绝所有tcp端口
[root@master ~]# iptables -L -nv --line-numbers -t filter
Chain DOCKER (1 references)
num pkts bytes target prot opt in out source destination
1 0 0 DROP tcp -- * * 192.168.1.1 0.0.0.0/0 tcp dpt:80
2 0 0 ACCEPT tcp -- !docker0 docker0 0.0.0.0/0 172.17.0.2 tcp dpt:80
限制其他机器访问本地所有端口
(常用):
iptables -t filter -I INPUT -m iprange --src-range 192.168.3.5-192.168.3.100 -j DROP
iptables -t filter -I DOCKER-USER -m iprange --dst-range 192.168.3.5-192.168.3.100 -j DROP
When you can overcome that, be unstoppable!