Bootstrap

防火墙控制Docker端口开放与关闭

问题描述

docker下的oracle数据库服务存在漏洞,解决难度较高,于是通过firewalld限制高危端口开放,只允许本机访问。发现即使配置规则firewalld把oracle 1521漏洞端口不开放出去,但其他服务器依然能访问这给服务器的1521端口,也就是说firewalld配置的规则失效。

第一种方案

docker容器在创建时会在iptables的INPUT表的DOCKER链下自动创建规则放行端口,为了保证docker启动的每一个容器都能被外界访问(自私!),所以导致firewalld不放行端口也能被外界访问。

Firewalld服务启动时,会将iptables上的规则全部清空,并把firewalld上的防火墙策略规则写入到iptables中,此时docker因为防火墙规则被删除就会不正常,需要重启systemctl restart docker服务来重新刷写防火墙规则到iptables上,所以我们在管理Docker端口时,应该使用iptables防火墙而不是firewalld防火墙服务

首先在docker容器启动时不让它自动在iptables上船舰规则,在docker配置文件中添加 “iptables”: false

[root@localhost ~]#  vi /etc/docker/daemon.json 
{ 
"data-root": "/opt/docker",
 "iptables": false
 }

#重启生效
[root@localhost ~]#  systemctl daemon-reload
[root@localhost ~]#  systemctl restart docker

此时我们就可以随便关闭我们不想放行的端口了,做到使用iptables管理Docker容器端口。

引发问题

发现以上做法可以屏蔽端口了,但是出现容器不能与宿主机其他服务器通讯,原因是加入了 “iptables”: false后,不能在iptables添加任何规则了,正常来说docker启动时不止是添加几条容器端口开放这么简单,docker容器启动时还需要在nat表添加-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE这些规则,这些规则是处理docker的SNAT地址伪装用的,直白来说就是用来容器内部访问外部网络的。具体含义是将容器网络网段发送到外部的数据包(! -o docker0)伪装成宿主机的ip,就是将数据包的原来的容器ip换成了宿主机ip做了一次snat,没经过源IP地址转换是不能正常通讯的。

#网络不通
[root@localhost ~]# docker exec  -it tomcat bash 
root@b287f29a1b60:/usr/local/tomcat# ping 172.21.36.43    #另一台宿主机IP
PING 172.21.36.43 (172.21.36.43) 56(84) bytes of data.
^C
--- 172.21.36.43 ping statistics ---
8 packets transmitted, 0 received, 100% packet loss, time 9ms

#iptables规则消失
[root@localhost ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

解决方法:
在docker启动配置中加入配置

vi /etc/systemd/system/docker.service
[Service]
ExecStartPre=/usr/sbin/iptables -t nat -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
ExecStopPost=/usr/sbin/iptables -t nat -D POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE

#加载并重启docker
systemctl daemon-reload
systemctl restart docker

#172.17.0.0/16 IP为容器的IP网段,查看容器的IP网段,需要查看容器的网络模式,没指定的话一般为bridge
在这里插入图片描述
在这里插入图片描述
如果容器里使用了不同的网络,每个网络都要开放,没有开放的网络不能与外网通讯
在这里插入图片描述
问题解决,
不过iptables -I INPUT -p tcp --dport 1521 -j DROP
加入这条规制,本地也无法通过IP访问,所以容器内部要么通过容器名相互访问,要么再加一条允许本地IP访问策略
iptables -I INPUT -s 172.21.36.67 -t tcp -j ACCEPT

第二种方案

以至于后来我才发现第二种解决办法,看了第二种方案你就会觉得第一种方案有多傻,我们要实现防火墙管理Docker端口,只需要在iptables的filter表的DOCKER-USER链下添加规则即可。

#只允许10.108.11.178访问容器的1521端口
[root@data dciproject]# iptables -I DOCKER-USER  !  -s  10.108.11.178  -p tcp --dport 1521 -j DROP
[root@data dciproject]# iptables -nL  
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:9090
ACCEPT     tcp  --  10.108.11.178        0.0.0.0/0            tcp dpt:1521
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8091
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8085
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:9695
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:7001
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8086
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8083
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8089
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:19080
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8088
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:6379
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:445
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:139
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:22223
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:3306
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:7443
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:7010
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:10020
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:10010
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:6443
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:6080
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:5432
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:9011
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8082
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8081
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:22
DROP       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:1521

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
DOCKER-USER  all  --  0.0.0.0/0            0.0.0.0/0           
DOCKER-ISOLATION-STAGE-1  all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain DOCKER (5 references)
target     prot opt source               destination         
ACCEPT     tcp  --  0.0.0.0/0            10.1.1.2             tcp dpt:8080
ACCEPT     tcp  --  0.0.0.0/0            192.168.0.2          tcp dpt:5000
ACCEPT     tcp  --  0.0.0.0/0            10.1.0.2             tcp dpt:9090
ACCEPT     tcp  --  0.0.0.0/0            10.1.3.2             tcp dpt:5432
ACCEPT     tcp  --  0.0.0.0/0            10.1.1.3             tcp dpt:8080
ACCEPT     tcp  --  0.0.0.0/0            10.1.1.3             tcp dpt:1521
ACCEPT     tcp  --  0.0.0.0/0            10.1.0.3             tcp dpt:8080
ACCEPT     tcp  --  0.0.0.0/0            192.168.0.3          tcp dpt:8085
ACCEPT     tcp  --  0.0.0.0/0            192.168.0.3          tcp dpt:80
ACCEPT     tcp  --  0.0.0.0/0            10.1.0.4             tcp dpt:5432
ACCEPT     tcp  --  0.0.0.0/0            10.1.1.4             tcp dpt:15675
ACCEPT     tcp  --  0.0.0.0/0            10.1.1.4             tcp dpt:15672
ACCEPT     tcp  --  0.0.0.0/0            10.1.1.4             tcp dpt:5672
ACCEPT     tcp  --  0.0.0.0/0            10.1.1.4             tcp dpt:1883
ACCEPT     tcp  --  0.0.0.0/0            10.1.1.5             tcp dpt:6379
ACCEPT     tcp  --  0.0.0.0/0            10.1.1.6             tcp dpt:8080
ACCEPT     tcp  --  0.0.0.0/0            10.1.0.6             tcp dpt:8080
ACCEPT     tcp  --  0.0.0.0/0            10.1.1.7             tcp dpt:8080
ACCEPT     tcp  --  0.0.0.0/0            10.1.1.8             tcp dpt:19080
ACCEPT     tcp  --  0.0.0.0/0            10.1.0.8             tcp dpt:9191
ACCEPT     tcp  --  0.0.0.0/0            10.1.0.8             tcp dpt:8080
ACCEPT     tcp  --  0.0.0.0/0            10.1.1.9             tcp dpt:27017
ACCEPT     tcp  --  0.0.0.0/0            10.1.0.9             tcp dpt:8080
ACCEPT     tcp  --  0.0.0.0/0            10.1.0.11            tcp dpt:8000
ACCEPT     tcp  --  0.0.0.0/0            10.1.0.12            tcp dpt:8080
ACCEPT     tcp  --  0.0.0.0/0            10.1.0.13            tcp dpt:5432

Chain DOCKER-ISOLATION-STAGE-1 (1 references)
target     prot opt source               destination         
DOCKER-ISOLATION-STAGE-2  all  --  0.0.0.0/0            0.0.0.0/0           
DOCKER-ISOLATION-STAGE-2  all  --  0.0.0.0/0            0.0.0.0/0           
DOCKER-ISOLATION-STAGE-2  all  --  0.0.0.0/0            0.0.0.0/0           
DOCKER-ISOLATION-STAGE-2  all  --  0.0.0.0/0            0.0.0.0/0           
DOCKER-ISOLATION-STAGE-2  all  --  0.0.0.0/0            0.0.0.0/0           
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-ISOLATION-STAGE-2 (5 references)
target     prot opt source               destination         
DROP       all  --  0.0.0.0/0            0.0.0.0/0           
DROP       all  --  0.0.0.0/0            0.0.0.0/0           
DROP       all  --  0.0.0.0/0            0.0.0.0/0           
DROP       all  --  0.0.0.0/0            0.0.0.0/0           
DROP       all  --  0.0.0.0/0            0.0.0.0/0           
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-USER (1 references)
target     prot opt source               destination         
DROP       tcp  -- !10.108.11.178        0.0.0.0/0            tcp dpt:1521
RETURN     all  --  0.0.0.0/0            0.0.0.0/0                 

Chain l (0 references)
target     prot opt source               destination         
[root@data dciproject]#
#永久保存iptables规则
[root@data dciproject]# yum install iptables -y && yum install iptables-services -y
[root@data dciproject]# systemctl start iptables.service && systemctl enable iptables.service
[root@data dciproject]#  service iptables save

在docjer启动的时创建的众多链中,DOCKER-USER链优先级最高,用于自定义转发规则,可以限制进入容器的源IP地址:
iptables -I DOCKER-USER ! -s 10.108.11.178 -p tcp --dport 1521 -j DROP

其他记录点:docker在启动时是会在iptables上添加规则的,而firewalld服务启动时,会将iptables上的规则全部清空,并把firewalld上的防火墙策略规则写入到iptables中,此时docker因为防火墙规则被删除就会不正常,需要重启systemctl restart docker服务来重新刷写防火墙规则到iptables上,所以我们在管理Docker端口时,应该使用iptables防火墙而不是firewalld防火墙服务。
参考地址:https://blog.csdn.net/m0_49946916/article/details/109277325

又引发新的问题

按照第二种方案处理后,确实实现了iptables对docker容器的管理,实现了只允许特定IP访问特定容器端口,但又引发新的问题,容器内部之间也无法通过防火墙,这个是我没想到的,还要手动将容器的网段地址添加到DOCKER-USER链中去,才能保证容器内部相互通讯。
进入容器内部测试,发现网络不通
在这里插入图片描述
添加docker容器的网段

[root@localhost ~]# docker network ls 
NETWORK ID     NAME                     DRIVER    SCOPE
4ac677e2fd2f   bridge                   bridge    local
f28591fefa67   docker-project_default   bridge    local
f32fea4be351   host                     host      local
dc907d235925   none                     null      local
[root@localhost ~]# 
[root@localhost ~]# docker inspect docker-project_default | grep Subnet 
                    "Subnet": "172.18.0.0/16",            #所有docker使用docker-project_default  bridge的网段
[root@localhost ~]# 

放行容器网段访问所有端口

[root@localhost ~]# iptables -I DOCKER-USER  -p tcp  -s 172.18.0.12/16  -j ACCEPT
[root@localhost ~]# iptables -n -L  DOCKER-USER
Chain DOCKER-USER (1 references)
target     prot opt source               destination         
ACCEPT     tcp  --  172.18.0.0/16        0.0.0.0/0       #确保容器网络规则在第一位
DROP       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:5432
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           

测试容器访问其他容器端口,成功

[root@localhost ~]# docker exec  -it tomcat bash 
root@2aedfa874301:/usr/local/tomcat# telnet  postgres 5432
Trying 172.18.0.2...
Connected to postgres.
Escape character is '^]'.

三.Iptables基础命令

关闭特定端口

iptables -A INPUT -p tcp --dport 1521 -j ACCEPT

允许特定IP访问所有端口

iptables -I INPUT -s 10.108.11.178 -j ACCEPT

允许特定IP访问特定端口

iptables -I DOCKER-USER !  -s  10.108.11.178  -p tcp --dport 1521 -j DROP

删除规则

iptables  -t filter -nL --line-number
iptables -D INPUT 1

清空所有规则

iptables -F
iptables -X
iptables -Z

永久保存规则

#第一种方案
yum install iptables  iptables-services -y 
systemctl start iptables.service && systemctl enable iptables.service
service iptables save
#第二种方案
保存
iptables-save > /etc/iptables.rules
恢复
iptables–restore < /etc/iptables.rules
;