为什么某个端口虽然不在 centos 7 上的防火墙开放端口中,但是却可以从外部访问它?

为什么某个端口虽然不在 centos 7 上的防火墙开放端口中,但是却可以从外部访问它?

我有一个使用 CentOS 7 的远程 vps,相关firewalld信息如下,firewalld正在积极运行。

[root@doer mydir]# firewall-cmd --get-zone-of-interface=eth0
no zone
[root@ doer mydir]# firewall-cmd --list-ports
You're performing an operation over default zone ('public'),
but your connections/interfaces are in zone 'home' (see --get-active-zones)
You most likely need to use --zone=home option.

3306/tcp

我运行一个 Docker 容器,其中有一个 Spring Boot 程序监听 8080 端口,该端口映射到主机的 9182,9182 不在开放端口列表中,但我仍然可以通过http://主机 IP:9182, 怎么了?


我已添加eth0到公共区域

firewall-cmd --permanent --zone=home --add-interface=eth0

现在

[root@ doer mydir]#  firewall-cmd --get-zone-of-interface=eth0
public


[root@ doer mydir]#  firewall-cmd --list-ports
3306/tcp

我仍然可以通过以下方式访问网络服务器http://主机 IP:9182

    #  firewall-cmd --list-all-zones
    block
      target: %%REJECT%%
      icmp-block-inversion: no
      interfaces:
      sources:
      services:
      ports:
      protocols:
      masquerade: no
      forward-ports:
      source-ports:
      icmp-blocks:
      rich rules:


    dmz
      target: default
      icmp-block-inversion: no
      interfaces:
      sources:
      services: ssh
      ports:
      protocols:
      masquerade: no
      forward-ports:
      source-ports:
      icmp-blocks:
      rich rules:


    drop
      target: DROP
      icmp-block-inversion: no
      interfaces:
      sources:
      services:
      ports:
      protocols:
      masquerade: no
      forward-ports:
      source-ports:
      icmp-blocks:
      rich rules:


    external
      target: default
      icmp-block-inversion: no
      interfaces:
      sources:
      services: ssh
      ports:
      protocols:
      masquerade: yes
      forward-ports:
      source-ports:
      icmp-blocks:
      rich rules:


    home (active)
      target: default
      icmp-block-inversion: no
      interfaces: eth1
      sources:
      services: dhcpv6-client mdns samba-client ssh
      ports:
      protocols:
      masquerade: no
      forward-ports:
      source-ports:
      icmp-blocks:
      rich rules:


    internal
      target: default
      icmp-block-inversion: no
      interfaces:
      sources:
      services: dhcpv6-client mdns samba-client ssh
      ports:
      protocols:
      masquerade: no
      forward-ports:
      source-ports:
      icmp-blocks:
      rich rules:

答案1

Docker 在发布端口时直接将自己的防火墙规则安装到主机服务器的内核中,而无需使用用户友好的防火墙管理工具(如firewalld 脚注 1和相关工具firewall-cmd(或类似地ufw或 Shorewall 等))提供的抽象层。

由于 docker 不使用它们 当你仅使用这些工具检查防火墙时,docker 创建的任何规则通常都不会显示

要查看 Docker(或任何其他创建自己的规则的应用程序)在防火墙中实际创建的规则,您需要使用更低级别的命令iptables和/或iptables-save将显示内核中的实际实时配置的命令。

尝试

 [sudo] iptables -L -v -n --line-numbers 

[sudo] iptables -L -v -n -t nat --line-numbers

或使用

[sudo] iptables-save

通常,Docker 创建的防火墙规则会具有先例,因为它们插入到用户友好的防火墙管理工具管理的规则之前。

我运行一个docker,里面有一个springboot程序监听8080端口,该端口映射到宿主机的9182,9182不在开放端口列表中,但是我仍然可以通过访问web服务器http://<HOST_MACHINE_IP>:9182,哪里出了问题?

没有什么是错的。

这正是您在创建已发布端口时指示 Docker 执行的操作:

已发布的端口
默认情况下,当您创建容器时,它不会向外界发布任何端口。要使端口可供 Docker 之外的服务或未连接到容器网络的 Docker 容器使用,请使用 --publish 或 -p 标志。这将创建防火墙规则将容器端口映射到 Docker 主机上的端口。

https://docs.docker.com/config/containers/container-networking/

要在 Docker 发布的端口上添加更多访问控制,需要在DOCKER-USERiptables 链中创建自己的规则,如下所示:https://docs.docker.com/network/iptables/


脚注 1从 docker 20.10.0 开始,docker 应该根据此处的文档与firewalld 集成:https://docs.docker.com/network/iptables/#integration-with-firewalld

答案2

所有答案均无法解释真正原因。

正如 HermanB 所说,Docker 创建了自己的规则......但不是任何地方!

有两个链中的过滤表对于输入流量很重要INPUTFORWARD

  • Firewalld 使用 INPUT 过滤表作为其规则。

  • PREROUTINGDocker 在链表中创建路由DNAT。这会导致将数据包路由到FORWARD链而不是INPUT链。

因此,所有应该由 Docker 容器使用的流量都会“绕过”防火墙。

在 serverfault 上搜索“firewalld docker”会出现数十个类似的问题。

解决方案:

必须手动添加iptables规则违背了防火墙。很遗憾 Docker 无法与 Firewalld 正常协作。不过,我相信我们可以做一些更简洁的事情,通过告诉 Firewalld 在 FORWARD 链中应用相同的规则并放置 Firewalld 的自定义链Docker 的链。

目前,Firewalld 自定义链 ( FORWARD_direct, FORWARD_IN_ZONES, FORWARD_OUT_ZONES) 位于 Docker 自定义链 ( DOCKER-USER, DOCKER-ISOLATION-STAGE-1, DOCKER) 之后。

答案3

使用firewall-cmd --list-all-zone,查看“home”区域,你的接口连接到该区域。如果你有其他问题,请发布完整的结果。

答案4

我遇到过类似的问题 - 可以从外部接口 eth0 访问 docker 容器的开放端口 8000,但我需要它仅通过 Nginx 作为代理可见。

深入研究后iptables -L -v -n发现,DOCKER 规则链是从 FORWARD 链运行的,而添加防火墙命令 rich-rules(和直接规则)则转到 INPUT 链,因此它不能按我预期的方式工作。

以下命令解决了该问题: firewall-cmd --direct --add-rule ipv4 filter DOCKER 0 -i eth0 -d 172.22.0.0/24 -j DROP

其中 172.22.0.0/24 是带有 docker 容器的子网。

相关内容