基于iptables的Docker端口白名单控制实现
作者:遇见火星
本文主要介绍了通过iptables为Docker Compose部署的容器设置宿主机端口IP白名单,强调规则顺序与持久化配置,提供单端口和multiport两种实现方式,感兴趣的可以了解一下
一、需求背景
某项目组采用容器化部署架构,通过docker-compose
对服务进行编排管理。为确保核心服务安全性,需对以下三个暴露的宿主机端口实施IP白名单访问控制:
服务名称 | 宿主机IP | 宿主机端口 | 容器内部端口 |
---|---|---|---|
apollo-configservice | 172.22.33.204 | 10002 | 8080 |
apollo-adminservice | 172.22.33.204 | 10003 | 8090 |
apollo-portal | 172.22.33.204 | 10004 | 8070 |
- 允许访问的IP白名单地址 172.16.200.200,允许访问apollo 全资源
- apollo docker-compose 文件
version: '3' services: apollo-configservice: container_name: apollo-configservice image: docker.cnb.cool/srebro/apollo:apollo-configservice-2.3.0 volumes: - ./logs:/opt/logs - /etc/localtime:/etc/localtime:ro ports: - "10002:8080" environment: - SPRING_DATASOURCE_URL=jdbc:mysql://172.22.33.201:3306/ApolloConfigDB?characterEncoding=utf8 - SPRING_DATASOURCE_USERNAME=srebro - SPRING_DATASOURCE_PASSWORD=srebro@2025 - EUREKA_INSTANCE_HOME_PAGE_URL=http://172.22.33.204:10002 - EUREKA_INSTANCE_IP_ADDRESS=172.22.33.204 - TZ=Asia/Shanghai restart: always networks: - srebro apollo-adminservice: depends_on: - apollo-configservice container_name: apollo-adminservice image: docker.cnb.cool/srebro/apollo:apollo-adminservice-2.3.0 volumes: - ./logs:/opt/logs - /etc/localtime:/etc/localtime:ro ports: - "10003:8090" environment: - SPRING_DATASOURCE_URL=jdbc:mysql://172.22.33.201:3306/ApolloConfigDB?characterEncoding=utf8 - SPRING_DATASOURCE_USERNAME=srebro - SPRING_DATASOURCE_PASSWORD=srebro@2025 - EUREKA_INSTANCE_HOME_PAGE_URL=http://172.22.33.204:10003 - EUREKA_INSTANCE_IP_ADDRESS=172.22.33.204 - TZ=Asia/Shanghai restart: always networks: - srebro apollo-portal: depends_on: - apollo-adminservice container_name: apollo-portal image: docker.cnb.cool/srebro/apollo:apollo-portal-2.3.0 volumes: - ./logs:/opt/logs - /etc/localtime:/etc/localtime:ro ports: - "10004:8070" environment: - SPRING_DATASOURCE_URL=jdbc:mysql://172.22.33.201:3306/ApolloPortalDB?characterEncoding=utf8 - SPRING_DATASOURCE_USERNAME=srebro - SPRING_DATASOURCE_PASSWORD=srebro@2025 - APOLLO_PORTAL_ENVS=baseline - baseline_META=http://172.22.33.204:10002 - TZ=Asia/Shanghai restart: always networks: - srebro networks: srebro: external: true
二、分析
- 🚫 使用iptables的方式进行限制。
- 配置后的策略需要持久化,系统或者容器重启后 策略还在。
- 查看docker 官方文档,有关于Docker 为网桥网络创建
iptables
规则的说明 - 默认情况下,允许所有外部源 IP 连接到已发布到 Docker 主机地址的端口;要仅允许特定 IP 或网络访问容器,需要在 DOCKER-USER 过滤器链的顶部插入一条否定规则。
- 以下规则会丢弃来自除 192.0.2.2 之外的所有 IP 地址的数据包。被这些自定义链中的规则接受或拒绝的数据包将不会被附加到 FORWARD 链的用户定义规则看到。因此,要添加其他规则来筛选这些数据包,使用 DOCKER-USER 链。
三、实现方式
只允许17216.200.200 访问apollo 暴露在宿主机上的 10002,10003,10004 端口
配置iptables 策略
- ⚠️ 需要注意 ,--dport 指的是容器的端口,而不是宿主机的映射后的端口,网上查看很多资料都是写的宿主机的端口都是不对的,这边只在docker 的论坛看到一个关于--dport 的说明
正确配置方式(推荐两种方法):
iptables -I 是插入到链的最前面,确保每个端口的 ACCEPT 规则在 DROP 规则之前。
方法一:为每个端口单独设置规则(清晰直观)
# 先添加拒绝规则 iptables -I DOCKER-USER -p tcp --dport 8080 -j DROP iptables -I DOCKER-USER -p tcp --dport 8090 -j DROP iptables -I DOCKER-USER -p tcp --dport 8070 -j DROP # 再添加允许规则(它们会被插入到链的顶部) iptables -I DOCKER-USER -p tcp --dport 8080 -s 172.16.200.200 -j ACCEPT iptables -I DOCKER-USER -p tcp --dport 8090 -s 172.16.200.200 -j ACCEPT iptables -I DOCKER-USER -p tcp --dport 8070 -s 172.16.200.200 -j ACCEPT
方法二:使用 multiport
模块合并规则(更高效)
# 先添加拒绝规则 iptables -I DOCKER-USER -p tcp -m multiport --dports 8080,8090,8070 -j DROP # 再添加允许规则(它会被插入到链的顶部) iptables -I DOCKER-USER -p tcp -s 172.16.200.200 -m multiport --dports 8080,8090,8070 -j ACCEPT
验证规则顺序
执行以下命令检查规则顺序,确保 ACCEPT 规则在 DROP 规则之上:
[root@localhost apollo]# iptables -L DOCKER-USER -n --line-numbers Chain DOCKER-USER (1 references) num target prot opt source destination 1 ACCEPT tcp -- 172.16.200.200 0.0.0.0/0 tcp dpt:8080 2 ACCEPT tcp -- 172.16.200.200 0.0.0.0/0 tcp dpt:8090 3 ACCEPT tcp -- 172.16.200.200 0.0.0.0/0 tcp dpt:8070 4 DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 5 DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8090 6 DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8070 7 RETURN all -- 0.0.0.0/0 0.0.0.0/0
访问测试
iptables 规则持久化保存
[root@localhost apollo]# service iptables save iptables: Saving firewall rules to /etc/sysconfig/iptables: [ OK ]
四、其他
docker 多容器端口相同,怎么限制?
上面的案例,阐述的是,docker 容器里的端口分别是不同的端口,如果我们容器内的端口都是8080,那应该怎么限制呢,典型的场景就是所有微服务的容器端口都是相同的,只是暴露的端口不同
服务名称 | 宿主机IP | 宿主机端口 | 容器内部端口 |
---|---|---|---|
apollo-configservice | 172.22.33.204 | 10002 | 8080 |
apollo-adminservice | 172.22.33.204 | 10003 | 8080 |
apollo-portal | 172.22.33.204 | 10004 | 8080 |
使用iptables 限制访问的目的地址
需要提前创建好docker 的网桥,指定容器的网络, ipv4_address: xx.xx.xx.xx
docker-compose.yaml
version: '3' services: apollo-configservice: container_name: apollo-configservice image: docker.cnb.cool/srebro/apollo:apollo-configservice-2.3.0 volumes: - ./logs:/opt/logs - /etc/localtime:/etc/localtime:ro ports: - "10002:8080" environment: - SPRING_DATASOURCE_URL=jdbc:mysql://172.22.33.201:3306/ApolloConfigDB?characterEncoding=utf8 - SPRING_DATASOURCE_USERNAME=srebro - SPRING_DATASOURCE_PASSWORD=srebro@2025 - EUREKA_INSTANCE_HOME_PAGE_URL=http://172.22.33.204:10002 - EUREKA_INSTANCE_IP_ADDRESS=172.22.33.204 - TZ=Asia/Shanghai restart: always networks: srebro: ipv4_address: 10.22.33.66 apollo-adminservice: depends_on: - apollo-configservice container_name: apollo-adminservice image: docker.cnb.cool/srebro/apollo:apollo-adminservice-2.3.0 volumes: - ./logs:/opt/logs - /etc/localtime:/etc/localtime:ro ports: - "10003:8080" environment: - SPRING_DATASOURCE_URL=jdbc:mysql://172.22.33.201:3306/ApolloConfigDB?characterEncoding=utf8 - SPRING_DATASOURCE_USERNAME=srebro - SPRING_DATASOURCE_PASSWORD=srebro@2025 - EUREKA_INSTANCE_HOME_PAGE_URL=http://172.22.33.204:10003 - EUREKA_INSTANCE_IP_ADDRESS=172.22.33.204 - TZ=Asia/Shanghai restart: always networks: srebro: ipv4_address: 10.22.33.67 apollo-portal: depends_on: - apollo-adminservice container_name: apollo-portal image: docker.cnb.cool/srebro/apollo:apollo-portal-2.3.0 volumes: - ./logs:/opt/logs - /etc/localtime:/etc/localtime:ro ports: - "10004:8080" environment: - SPRING_DATASOURCE_URL=jdbc:mysql://172.22.33.201:3306/ApolloPortalDB?characterEncoding=utf8 - SPRING_DATASOURCE_USERNAME=srebro - SPRING_DATASOURCE_PASSWORD=srebro@2025 - APOLLO_PORTAL_ENVS=baseline - baseline_META=http://172.22.33.204:10002 - TZ=Asia/Shanghai restart: always networks: srebro: ipv4_address: 10.22.33.68 networks: srebro: external: true
配置方式
- 只允许白名单地址
172.16.200.200
可以访问apollo 的10002
和10004
端口,也就是可以访问apollo-configservice
和apollo-portal
服务,其他都不允许访问。 - 这里的
10.22.33.66
,10.22.33.67
,10.22.33.68
三个IP 是容器的IP地址,8080
是容器的端口。三个IP 分别对应apollo-configservice
,apollo-adminservice
和apollo-portal
服务。
#先添加拒绝规则 iptables -I DOCKER-USER -p tcp --dport 8080 -j DROP # 再添加允许规则(它们会被插入到链的顶部) iptables -I DOCKER-USER -p tcp -s 172.16.200.200 -d 10.22.33.66 --dport 8080 -j ACCEPT iptables -I DOCKER-USER -p tcp -s 172.16.200.200 -d 10.22.33.68 --dport 8080 -j ACCEPT
验证规则顺序
执行以下命令检查规则顺序,确保 ACCEPT 规则在 DROP 规则之上:
[root@localhost apollo]# iptables -L DOCKER-USER -n --line-numbers Chain DOCKER-USER (1 references) num target prot opt source destination 1 ACCEPT tcp -- 172.16.200.200 10.22.33.68 tcp dpt:8080 2 ACCEPT tcp -- 172.16.200.200 10.22.33.66 tcp dpt:8080 3 DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 4 RETURN all -- 0.0.0.0/0 0.0.0.0/0
访问测试
iptables 规则持久化保存
[root@localhost apollo]# service iptables save iptables: Saving firewall rules to /etc/sysconfig/iptables: [ OK ]
其他方式🚫 限制docker外部IP 访问
1、docker运行在宿主机模式上,直接走宿主机的防火墙或者iptables管理
2、docker 的外部暴露地址监听在 127.0.0.1 上 , 本地再运行一个NGINX 做代理,设置NGINX 白名单
K8S 场景下,怎么限制外部的IP 访问
- 用clusterip,内部访问没问题,外部走访问nginx的nodeport或者ingress,这样就可以用白名单了
到此这篇关于基于iptables的Docker端口白名单控制实现的文章就介绍到这了,更多相关Docker iptables端口白名单内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:
- 解决docker安装完成报:bridge-nf-call-iptables is disabled问题
- 在Docker容器中使用iptables时的最小权限的开启方法
- Docker中iptables规则在iptables重启后丢失的完整过程
- 详解Docker使用Linux iptables 和 Interfaces管理容器网络
- Docker与iptables及实现bridge方式网络隔离与通信操作
- iptables使用及docker的iptables规则
- iptables如何限制宿主机跟Docker IP和端口访问(安全整改)
- docker的iptables策略详解和用户自定义策略的添加方式
- Docker iptables的错误解决
- docker的WARNING:bridge-nf-call-iptables is disabled的解决方案