基于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 的1000210004 端口,也就是可以访问 apollo-configserviceapollo-portal服务,其他都不允许访问。

  • 这里的10.22.33.6610.22.33.6710.22.33.68 三个IP 是容器的IP地址, 8080 是容器的端口。三个IP 分别对应 apollo-configserviceapollo-adminserviceapollo-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,这样就可以用白名单了
相关推荐
李狗蛋儿啊1 小时前
zero自动化框架搭建---Git安装详解
运维·git·自动化
小金的学习笔记2 小时前
如何在本地和服务器新建mysql用户和密码
运维·服务器·mysql
s_fox_2 小时前
nginx ngx_http_module(7) 指令详解
运维·nginx·http
EasyNVR2 小时前
EasyRTC智能硬件:实时畅联、沉浸互动、消音护航
运维·服务器·网络·安全·音视频·webrtc·p2p
CarryBest2 小时前
Jenkins 环境搭建---基于 Docker
运维·jenkins
若云止水3 小时前
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_process_options
运维·nginx
s_fox_3 小时前
nginx ngx_http_module(9) 指令详解
运维·nginx·http
_院长大人_4 小时前
Docker Mysql 数据迁移
mysql·adb·docker
xing.yu.CTF5 小时前
Web入侵实战分析-常见web攻击类应急处置实验2
运维·服务器·windows·web安全·apache·php漏洞·phpstudy后门漏洞
我们的五年5 小时前
【Linux网络】TCP/IP地址的有机结合(有能力VS100%???),IP地址的介绍
linux·运维·网络·tcp/ip