基于iptables的Docker端口白名单控制

一、需求背景

某项目组采用容器化部署架构,通过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 策略

正确配置方式(推荐两种方法):

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,这样就可以用白名单了
相关推荐
Mikko713 分钟前
Linux 磁盘满了但 du 找不到?LVM 扩容 df 不变?fstab 写错开不了机?三台真机实测磁盘排查
linux·运维·centos
蓝胖的四次元口袋19 分钟前
Jenkins知识梳理(2)
运维·jenkins
yumgpkpm28 分钟前
Acceldata ODP 3.3.6.4 vs CDP Private Cloud Base 7.3.2 对比
大数据·运维·服务器·hadoop·华为·zookeeper·hbase
AIGC大时代31 分钟前
LLM Agent 执行沙箱闸门:失败含义与当天最小实验
docker·沙箱·闸门·bubblewrap·llm agent
Liuqy-0538 分钟前
特殊进程——孤儿、僵尸、守护进程
linux·运维·服务器
考研保研资料分享1 小时前
自动化控制保研经验合辑:上交夏令营、北工大预推免与跨专业面试复盘(2025)
运维·面试·自动化
灯澜忆梦2 小时前
【docker】#2 | 基础命令
docker·容器·eureka
乐维_lwops2 小时前
2026选择运维监控系统时应该重点考察哪些功能?
大数据·运维·人工智能
峥无2 小时前
Linux NPTL线程:创建/终止/等待/分离/栈布局内核原理|线程下篇
linux·运维·线程