前言
在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策略来防止对容器或其他在您的主机上运行的服务的未授权访问。

iptable docker iptable docker-user_iptable docker

在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!