AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / server / 问题 / 963759
Accepted
Laurent
Laurent
Asked: 2019-04-19 17:38:49 +0800 CST2019-04-19 17:38:49 +0800 CST 2019-04-19 17:38:49 +0800 CST

Docker 破坏 libvirt 桥接网络

  • 772

这个问题快把我逼疯了。我运行全新安装的 Ubuntu 18.04,其中:

  • ufw 管理防火墙
  • br0 桥
  • lxd 和 libvirt (KVM)

我尝试了股票 docker.io 包和包形成 docker 自己的 deb 存储库。

我希望能够部署 docker 容器,选择 ip 来绑定其端口(例如 -p 10.58.26.6:98800:98800),然后使用 UFW 打开端口。

但 docker 似乎创建了扰乱 br0 桥的 iptables 规则(例如,主机无法 ping libvirt 来宾)

我环顾四周,找不到好的安全意识解决方案。

手动iptables -I FORWARD -i br0 -o br0 -j ACCEPT操作似乎使一切正常。

docker daemon 的设置也"iptables": false允许网桥正常运行,但会破坏 docker 的容器出口网络。

通过编辑单个 UFW 的文件https://stackoverflow.com/a/51741599/1091772 ,我发现这个解决方案看起来很简单,但它根本不起作用。

永久解决这个问题的最佳实践和安全方法是什么,在重新启动后幸存下来?

编辑: 我最终-A ufw-before-forward -i br0 -o br0 -j ACCEPT在/etc/ufw/before.rules提交之前添加。我可以将其视为解决方案还是不会引发一些问题?

iptables
  • 2 2 个回答
  • 9724 Views

2 个回答

  • Voted
  1. Best Answer
    A.B
    2019-04-25T17:41:45+08:002019-04-25T17:41:45+08:00

    问题,其实是一个特性:br_netfilter

    从描述中,我相信唯一合乎逻辑的解释是启用了网桥 netfilter 代码:用于有状态网桥防火墙或利用iptables的匹配和来自网桥路径的目标,而不必(或能够)复制它们在ebtables中。完全不考虑网络分层,网络第 2 层的以太网桥代码现在调用在 IP 级别(即网络第 3 层)工作的iptables。它只能在全局范围内启用:对于主机和每个容器,或者没有。一旦了解了正在发生的事情并知道要寻找什么,就可以做出适当的选择。

    netfilter 项目描述了启用br_netfilter时的各种ebtables/iptables交互。尤其令人感兴趣的是第 7 节解释了为什么有时需要一些没有明显效果的规则来避免桥接路径的意外影响,例如使用:

    iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -d 172.16.1.0/24 -j ACCEPT
    iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -j MASQUERADE
    

    避免同一 LAN 上的两个系统被网桥 NAT(参见下面的示例)。

    你有几个选择来避免你的问题,但是如果你不想知道所有的细节,也不想验证某些 iptables 规则(有时隐藏在其他命名空间中)是否会被破坏,那么你所做的选择可能是最好的:

    • 永久阻止加载br_netfilter模块。通常blacklist是不够的,install必须使用。对于依赖br_netfilter的应用程序来说,这是一个容易出现问题的选择:显然是 Docker、Kubernetes、...

      echo install br_netfilter /bin/true > /etc/modprobe.d/disable-br-netfilter.conf
      
    • 加载模块,但禁用其效果。对于iptables的效果是:

      sysctl -w net.bridge.bridge-nf-call-iptables=0
      

      如果将其放在启动时,则应首先加载模块,否则此切换将不存在。

    这两个先前的选择肯定会破坏iptables匹配-m physdev:xt_physdev模块在自身加载时会自动加载br_netfilter模块(即使从容器添加的规则触发了加载也会发生这种情况)。现在br_netfilter不会被加载,-m physdev可能永远不会匹配。

    • 在需要时解决 br_netfilter 的效果,例如 OP:如第 7 节所述,在各种链(PREROUTING、FORWARD、POSTROUTING)中添加那些明显的无操作规则。例如:

      iptables -t nat -A POSTROUTING -s 172.18.0.0/16 -d 172.18.0.0/16 -j ACCEPT
      
      iptables -A FORWARD -i br0 -o br0 -j ACCEPT
      

      这些规则永远不应该匹配,因为同一 IP LAN 中的流量不会被路由,除了一些罕见的 DNAT 设置。但是多亏了br_netfilter,它们确实匹配,因为它们首先被调用用于穿越桥的交换帧(“升级”为 IP 数据包) 。然后再次调用它们以获取通过路由器到达不相关接口的路由数据包(但不会匹配)。

    • 不要将 IP 放在网桥上:将该 IP 放在veth接口的一端,另一端放在网桥上:这应该确保网桥不会与路由交互,但这不是大多数容器/VM 所做的常见的产品。

    • 您甚至可以将网桥隐藏在其自己的隔离网络名称空间中(这只有在这次想要与其他ebtables规则隔离时才有用)。

    • 将所有内容都切换到nftables,其中规定的目标将避免这些桥梁交互问题。目前,桥接防火墙没有可用的状态支持,它仍然是WIP,但承诺在可用时会更干净,因为不会有任何“upcall”。

    您应该搜索触发br_netfilter加载的原因(例如:) -m physdev,看看您是否可以避免它,以选择如何继续。


    网络命名空间示例

    让我们使用网络命名空间重现一些效果。请注意,任何地方都不会使用任何ebtables规则。另请注意,此示例依赖于通常的 legacy iptables,而不是Debian buster 默认启用的iptables over nftables 。

    让我们重现一个与许多容器使用类似的简单案例:路由器 192.168.0.1/192.0.2.100 执行 NAT,后面有两个主机:192.168.0.101 和 192.168.0.102,与路由器上的网桥相连。两台主机可以通过网桥在同一个 LAN 上直接通信。

    #!/bin/sh
    
    for ns in host1 host2 router; do
        ip netns del $ns 2>/dev/null || :
        ip netns add $ns
        ip -n $ns link set lo up
    done
    
    ip netns exec router sysctl -q -w net.ipv4.conf.default.forwarding=1
    
    ip -n router link add bridge0 type bridge
    ip -n router link set bridge0 up
    ip -n router address add 192.168.0.1/24 dev bridge0
    
    for i in 1 2; do
        ip -n host$i link add eth0 type veth peer netns router port$i
        ip -n host$i link set eth0 up
        ip -n host$i address add 192.168.0.10$i/24 dev eth0
        ip -n host$i route add default via 192.168.0.1
        ip -n router link set port$i up master bridge0
    done
    
    #to mimic a standard NAT router, iptables rule voluntarily made as it is to show the last "effect"
    ip -n router link add name eth0 type dummy
    ip -n router link set eth0 up
    ip -n router address add 192.0.2.100/24 dev eth0
    ip -n router route add default via 192.0.2.1
    ip netns exec router iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j MASQUERADE
    

    让我们加载内核模块br_netfilter(以确保它不会稍后)并使用(非每个命名空间)切换bridge-nf-call-iptables禁用它的效果,仅在初始命名空间中可用:

    modprobe br_netfilter
    sysctl -w net.bridge.bridge-nf-call-iptables=0
    

    警告:同样,这可能会破坏iptables规则,例如-m physdev主机上的任何位置或依赖于加载和启用br_netfilter的容器中的任何位置。

    让我们添加一些 icmp ping 流量计数器。

    ip netns exec router iptables -A FORWARD -p icmp --icmp-type echo-request
    ip netns exec router iptables -A FORWARD -p icmp --icmp-type echo-reply
    

    让我们ping:

    # ip netns exec host1 ping -n -c2 192.168.0.102
    PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data.
    64 bytes from 192.168.0.102: icmp_seq=1 ttl=64 time=0.047 ms
    64 bytes from 192.168.0.102: icmp_seq=2 ttl=64 time=0.058 ms
    
    --- 192.168.0.102 ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1017ms
    rtt min/avg/max/mdev = 0.047/0.052/0.058/0.009 ms
    

    计数器不匹配:

    # ip netns exec router iptables -v -S FORWARD
    -P FORWARD ACCEPT -c 0 0
    -A FORWARD -p icmp -m icmp --icmp-type 8 -c 0 0
    -A FORWARD -p icmp -m icmp --icmp-type 0 -c 0 0
    

    让我们启用bridge-nf-call-iptables并再次 ping:

    # sysctl -w net.bridge.bridge-nf-call-iptables=1
    net.bridge.bridge-nf-call-iptables = 1
    # ip netns exec host1 ping -n -c2 192.168.0.102
    PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data.
    64 bytes from 192.168.0.102: icmp_seq=1 ttl=64 time=0.094 ms
    64 bytes from 192.168.0.102: icmp_seq=2 ttl=64 time=0.163 ms
    
    --- 192.168.0.102 ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1006ms
    rtt min/avg/max/mdev = 0.094/0.128/0.163/0.036 ms
    

    这次交换的数据包在 iptables 的过滤器/转发链中得到了匹配:

    # ip netns exec router iptables -v -S FORWARD
    -P FORWARD ACCEPT -c 4 336
    -A FORWARD -p icmp -m icmp --icmp-type 8 -c 2 168
    -A FORWARD -p icmp -m icmp --icmp-type 0 -c 2 168
    

    让我们设置一个 DROP 策略(将默认计数器归零)并再试一次:

    # ip netns exec host1 ping -n -c2 192.168.0.102
    PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data.
    
    --- 192.168.0.102 ping statistics ---
    2 packets transmitted, 0 received, 100% packet loss, time 1008ms
    
    # ip netns exec router iptables -v -S FORWARD
    -P FORWARD DROP -c 2 168
    -A FORWARD -p icmp -m icmp --icmp-type 8 -c 4 336
    -A FORWARD -p icmp -m icmp --icmp-type 0 -c 2 168
    

    桥接代码通过 iptables 过滤交换的帧/数据包。让我们像在 OP 中一样添加绕过规则(这将使默认计数器再次归零),然后再试一次:

    # ip netns exec router iptables -A FORWARD -i bridge0 -o bridge0 -j ACCEPT
    # ip netns exec host1 ping -n -c2 192.168.0.102
    PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data.
    64 bytes from 192.168.0.102: icmp_seq=1 ttl=64 time=0.132 ms
    64 bytes from 192.168.0.102: icmp_seq=2 ttl=64 time=0.123 ms
    
    --- 192.168.0.102 ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1024ms
    rtt min/avg/max/mdev = 0.123/0.127/0.132/0.012 ms
    
    # ip netns exec router iptables -v -S FORWARD
    -P FORWARD DROP -c 0 0
    -A FORWARD -p icmp -m icmp --icmp-type 8 -c 6 504
    -A FORWARD -p icmp -m icmp --icmp-type 0 -c 4 336
    -A FORWARD -i bridge0 -o bridge0 -c 4 336 -j ACCEPT
    

    让我们看看在来自 host1 的 ping 期间在 host2 上实际收到的内容:

    # ip netns exec host2 tcpdump -l -n -s0 -i eth0 -p icmp
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
    02:16:11.068795 IP 192.168.0.1 > 192.168.0.102: ICMP echo request, id 9496, seq 1, length 64
    02:16:11.068817 IP 192.168.0.102 > 192.168.0.1: ICMP echo reply, id 9496, seq 1, length 64
    02:16:12.088002 IP 192.168.0.1 > 192.168.0.102: ICMP echo request, id 9496, seq 2, length 64
    02:16:12.088063 IP 192.168.0.102 > 192.168.0.1: ICMP echo reply, id 9496, seq 2, length 64
    

    ...而不是源 192.168.0.101。MASQUERADE 规则也从桥接路径中调用。为避免这种情况,请在之前添加(如第 7 节的示例中所述)异常规则,或声明一个非网桥传出接口,如果可能的话(现在它可用,-m physdev如果它必须是网桥,您甚至可以使用它.. .)。


    随机相关:

    LKML/netfilter-dev: br_netfilter: 在非初始 netns中启用:这将有助于在每个命名空间而不是全局启用此功能,从而限制主机和容器之间的交互。

    netfilter-dev: netfilter: physdev: 放松 br_netfilter 依赖:仅仅试图删除一个不存在的physdev规则可能会产生问题。

    netfilter-dev:对网桥的连接跟踪支持:WIP 网桥 netfilter 代码使用 nftables 准备有状态的网桥防火墙,这一次更优雅。我认为摆脱 iptables (的内核端 API)的最后步骤之一。

    • 19
  2. Vincent P
    2019-06-18T22:50:07+08:002019-06-18T22:50:07+08:00

    如果上述威胁无法解决您的问题,以下是我在 Debian Stretch 上解决问题的方法。

    • 1、保存你当前的 iptables

      iptables-save > your-current-iptables.rules
      
    • 2、删除所有Docker 创建的规则

      iptables -D <DOCKER-CHAIN-RULES> <target-line-number>
      
    • 3、添加itpables规则以接受任何到INPUT、FORWARD和OUTPUT的流量

      iptables -I INPUT -j ACCEPT
      iptables -I FORWARD -j ACCEPT
      iptables -I OUTPUT -j ACCEPT
      
    • 4、重启你的Docker

      service docker restart
      

    完成第 3 步后,您可以从另一台 PC ping 被阻止的 libvert KVM 主机,您将看到 ICMP 响应。

    重新启动 Docker 还将其所需的 iptables 规则添加回您的计算机,但它不会再阻止您的桥接 KVM 主机。

    如果上述解决方案不适合您,您可以使用以下命令恢复 iptables:

    • 恢复 iptables

      iptables-restore < your-current-iptables.rules
      
    • 3

相关问题

  • OpenVPN 的 Linux IP 转发 - 正确的防火墙设置?

  • iptables 单个规则中的多个源 IP

  • 存储 iptables 规则的规范方法是什么

  • 使用 iptables 和 dhcpd 进行端口转发

  • 根据 Apache 日志数据自动修改 iptables 以阻止行为不良的客户端

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    新安装后 postgres 的默认超级用户用户名/密码是什么?

    • 5 个回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve