我的机器上运行着两个 docker 容器,其中非常严格的 nftables 配置处于活动状态。我想保持这种方式,但将外部对 docker 容器的访问列入白名单。
容器打开端口 80 和 6200。docker 服务在禁用 iptables 的情况下启动。
以下是当前的防火墙配置,包括我的尝试。icmp
、ssh
、http
和https
已经开放。对于 docker,只需要 http 端口 80 和应用程序特定端口 6200。我尝试只允许访问 docker,以192.168.0.0/16
尽可能地限制。
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept
iif eno2 icmp type echo-request accept
iif eno2 ip 192.168.0.0/16 tcp dport 22 accept
iif eno2 ip 192.168.0.0/16 tcp dport { http, https, 6200 } accept
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy drop;
}
}
Run Code Online (Sandbox Code Playgroud)
我尝试为接口添加额外的规则docker0
,但没有成功。我怀疑我必须修改chain forward
?
A.B*_*A.B 32
虽然问题可能看起来很简单,但其实很简单。Docker 的存在总是会给系统中处理网络的其他部分带来一些挑战。一旦nftables得到更广泛的采用并在未来被Docker直接使用,特别是一旦Docker停止使用br_netfilter
得到更广泛的采用并被Docker直接使用,特别是一旦Docker停止使用,事情可能会变得更简单。
如果您认为仍然值得与 Docker 一起使用nftables,我在下面介绍了一种方法,旨在让 Docker 处理其部分,并且不需要在其他防火墙规则发生变化时复制 Docker 设置,就像使用新容器启动新容器一样简单暴露端口,完成。
\niptables
仍然需要目前(2021)Docker 仍然使用iptables并且仅使用iptables(它也可以使用firewalld,但只能使用带有iptables后端的firewalld。无论如何,我不考虑这种情况)。因此,目前使用 Docker 时无法拥有纯粹的nftables系统。iptables可能重要也可能不重要。iptables-legacy
iptables-nft
以下是Docker 和 iptables中的一些相关摘录,对本例有用:
\n\n\nDocker 安装两个名为和\n 的自定义
\niptables
链,并确保传入的数据包始终首先由这两个链检查。DOCKER-USER
DOCKER
\n\n所有 Docker\xe2\x80\x99s iptables 规则都添加到
\nDOCKER
链中。不要手动操作此链。如果您需要添加在 Docker\xe2\x80\x99s 规则之前加载的规则,请将它们添加到链DOCKER-USER
中。这些规则在 Docker 自动创建的任何规则之前应用。
吹毛求疵:实际上 Docker 是-A DOCKER-USER -j RETURN
这样做的,所以应该在启动 docker 之前添加规则,或者更好:插入在所有情况下都有效的规则。
\n\n\n
FORWARD
添加到链中的规则(手动或通过另一个基于 iptables 的防火墙)在这些链之后进行评估。
\n\nDocker 还将链的策略设置
\nFORWARD
为DROP
. 如果您的\nDocker 主机还充当路由器,这将导致该路由器\n不再转发任何流量。
Docker 启用 IP 转发,但默认情况下会对其进行防火墙以用于其他用途。
\n\n\n可以
\niptables
在位于 的 Docker 引擎\xe2\x80\x99s\n配置文件中将密钥设置为 false/etc/docker/daemon.json
,但此选项\n不适合大多数用户。完全阻止\nDocker 创建 iptables 规则是不可能的,事后创建它们\n极其复杂,超出了这些说明的范围。\n将 iptables 设置为 false 很可能会破坏容器\n网络连接码头工人引擎。
无法避免iptables。
\nbr_netfilter
此外,Docker 还加载内核模块br_netfilter
以设置此属性:
# sysctl net.bridge.bridge-nf-call-iptables\nnet.bridge.bridge-nf-call-iptables = 1\n
Run Code Online (Sandbox Code Playgroud)\n因此,桥接帧(这里的 IPv4 类型帧暂时转换为 IPv4数据包)由iptables 和nftables过滤(即使没有明确记录,nftables就像iptables挂钩到 Netfilter 一样,Netfilter 会调用这些挂钩,无论它们是来自iptables或nftables)。
\n这个特性是与 Docker 交互时导致问题的主要原因。如果不了解这一点,人们会想知道为什么同一内部桥接 LAN 中的容器不能再在它们之间进行通信,无论它们是由 Docker 处理还是由 Docker 运行的其他东西(LXC、libvirt/QEMU...)处理。
\n这是Netfilter 和通用网络中的数据包流:
\n\n因此,可以通过两种不同的方式遍历来自 ip/inet 系列中的iptables或nftables的单个链:从通常的路由路径(绿色网络层字段内的绿色框)以及桥接路径(蓝色链路层字段内的绿色框)。该文档还告诉我们:
\n\n\n桥接数据包绝不会进入第 1 层(链路\n层)之上的任何网络代码。因此,桥接的 IP 数据包/帧永远不会输入 IP 代码。
\n
因此,可以保证数据包不会在同一条链上遍历两次,这让人松了口气。
\n由于目标是使用nftables,因此必须知道如何一起使用它们。
\n以下是我对此问题的回答:
\n\n总结一下:
\nip/inet 系列中的nftables规则应避免在桥接路径中执行任何操作。如果没有 Docker 激活,br_netfilter
就根本不需要考虑这个问题。检测是否处于 ip/inet 系列的桥接路径中应留给iptables,以避免让nftables处理此问题并保持通用性,无论是否安装 Docker。使用iptables比使用ip/inet 系列中的nftables更容易做到这一点,因为有特定的iptables -m physdev --physdev-is-bridged
测试:
\n\n\n
[!] --physdev-is-bridged
如果数据包正在桥接,因此未进行路由,则匹配。这仅在 FORWARD 和 POSTROUTING 链中有用。
\n
br_netfilter
请注意,如果 Docker 尚未完成此操作,则此匹配取决于并加载:需要解决由br_netfilter
,引起的问题!br_netfilter
这个想法是使用标记将来自iptables 的消息传递到nftables,以区分情况:
\n规则评估发生在桥接路径而不是路由路径中
\n总是接受这样的情况。
\n数据包已被 Docker 接受
\n可以添加进一步的限制,但大多数都接受这种情况。
\n数据包被 Docker 忽略
\n使用普通的nftables规则,不必考虑 Docker 的存在。
\n数据包因任何原因在iptables中被 DROP-ed
\n这是一个没有实际意义的案例,nftables不会看到这个数据包,并且对此没有任何必要或可以做的事情。
\n如果在 Docker 启动之前完成,请创建过滤器链DOCKER-USER
:
iptables -N DOCKER-USER\n
Run Code Online (Sandbox Code Playgroud)\n如果之后完成,Docker 将创建它。
\n添加一条规则,在链中的 Docker 评估之前标记数据包,该数据包DOCKER
被桥接路径检测案例覆盖,并使用不同的标记(如前所述将它们插入此处,但对它们进行编号以保留自然顺序,这在这里很重要):
iptables -I DOCKER-USER 1 -j MARK --set-mark 0xd0cca5e\niptables -I DOCKER-USER 2 -m physdev --physdev-is-bridged -j MARK --set-mark 0x10ca1\n
Run Code Online (Sandbox Code Playgroud)\n0x10ca1 和 0xd0cca5e 是任意选择的值。
\n附加(在 Docker 运行之前或之后,效果是相同的,因为 Docker 总是DOCKER
在之前插入其链)一条最终规则,仅当它是临时 Docker 评估标记时才重置数据包的标记,并添加一条最终ACCEPT
规则来覆盖Docker链DROP
上设置的默认FORWARD
策略:想法是推迟对nftables对与 Docker 无关的数据包进行进一步评估。
iptables -A FORWARD -m mark --mark 0xd0cca5e -j MARK --set-mark 0\niptables -A FORWARD -j ACCEPT\n
Run Code Online (Sandbox Code Playgroud)\n将优先级值更改inet filter forward
为略大于NF_IP_PRI_FILTER
(0) 的值,例如 10,以确保nftables的前向链发生在iptables filter/FORWARD
之后,以遵守此时间顺序。OP 规则集中的基本链线应更改为:
\n\nRun Code Online (Sandbox Code Playgroud)\nchain forward {\n type filter hook forward priority 0; policy drop;\n
到:
\n chain forward {\n type filter hook forward priority 10; policy drop;\n
Run Code Online (Sandbox Code Playgroud)\n通过检查数据包上的标记,可以在nftables中检测到前面描述的 4 种情况。添加counter
表达式以帮助调试。
标记0x10ca1:桥接路径
\n添加桥接路径透传规则:
\nnft add rule inet filter forward meta mark 0x10ca1 counter accept\n
Run Code Online (Sandbox Code Playgroud)\n标记 0xd0cca5e:Docker 案例
\n创建一个常规/用户链来处理 Docker 情况并添加一条调用它的规则:
\nnft add chain inet filter dockercase\nnft add rule inet filter forward meta mark 0xd0cca5e counter jump dockercase\n
Run Code Online (Sandbox Code Playgroud)\n添加有关 Docker 的附加限制,但默认接受
\n例如,限制来自eno2接口的传入数据包仅在来自 192.168.0.0/16 内的私有地址时才被接受:
\nnft add rule inet filter dockercase iif eno2 ip saddr != 192.168.0.0/16 counter drop\nnft add rule inet filter dockercase counter accept\n
Run Code Online (Sandbox Code Playgroud)\n无标记:与 Docker 无关的一般情况
\n添加无需考虑 Docker 的存在即可完成的任何操作,包括什么都不包含并具有默认的删除策略,否则可能会从通常的方式开始ct state related,established accept
(无数据包:在iptables中丢弃,非大小写)
\n上面的例子变成:
\n...\n chain forward {\n type filter hook forward priority 10; policy drop;\n meta mark 0x10ca1 counter accept\n meta mark 0xd0cca5e counter jump dockercase\n }\n\n chain dockercase {\n iif eno2 ip saddr != 192.168.0.0/16 counter drop\n counter accept\n }\n...\n
Run Code Online (Sandbox Code Playgroud)\n端口 80 和 6200 不必再出现在nftables规则中。如果需要使用 Docker 命令添加需要公开新端口的新容器,则无需在nftables中执行任何操作:由于标记,它已经得到处理。
\n仍然由于br_netfilter
\ 的影响,如果任何其他基础nftables链具有该属性hook forward
或hook postrouting
包含删除规则或更有用,更改规则(nat ...)而不使用图 7b 下面的上一个链接中描述的技巧,则相同类型的安排必须要做的:
它的优先级值应该高于iptables的等效链优先级
\n这样的iptables等效链(除非filter/FORWARD
已经在 中完成DOCKER-USER
)应该接收:
iptables -t foo -I BAR -m physdev --physdev-is-bridged -j MARK --set-mark 0x10ca1
\n与foo
之间raw
, mangle
, 或nat
以及BAR
之间PREROUTING
或POSTROUTING
视情况而定
nftables链的第一条规则应该是:
\nmeta mark 0x10ca1 accept\n
Run Code Online (Sandbox Code Playgroud)\n如果链的策略再次是,drop
它可能应该再次包含使用 0xd0cca5e 标记的规则的用户/常规链跳转,如之前所做的那样。
对于hook prerouting
,有关的文档--physdev-is-bridged
告诉这可能不适用于PREROUTING
:永远不要在那里使用默认的删除策略。无论如何,对于hook prerouting
情况,还不能有任何0xd0cca5e
继承的标记,但仅使用iptablesfilter/FORWARD
也是如此:PREROUTING 无法预见稍后会发生什么。
如果你真的想在桥接级别做一些事情,只需在桥接系列中使用nftables,不要依赖从桥接路径调用的 ip/inet 系列的这种特殊情况,因为br_netfilter
.
现在使用标记来处理这个问题,同时使用标记来处理其他事情变得更加困难,但只要小心一点也不是不可能。例如,通过使用按位运算和带有这些标记的掩码。这在iptables和nftables中可用。甚至ip rule
当使用标记作为选择器时
Docker 添加了nat规则以使用 iptables 的DNAT目标进行端口转发。最后,所有暴露/发布的端口都被路由到容器,而不是被主机接收。这意味着他们将使用上面所示的iptables链filter/FORWARD
以及(使用 OP 的规则集)nftables inet filter forward
链,并且不会使用INPUT
/input
。
还缺少阻止主机正确连接的规则。
\ninet filter input
输入路径根本不会用于 Docker 的容器,除了docker-proxy情况,它通常用于本地主机的访问,但 OP 已经接受了iif lo accept
,所以它没有在这个答案中进一步处理。关于 Docker 的任何内容都不应该出现在这里:对容器端口 80 和 6200 的引用变得毫无用处,应该删除。
然后,与 Docker 无关,输入链错过了一条有状态的规则。如果没有它,则从主机的输出返回流量(DNS 查询回复、ping回复、下载升级...)将会失败。用这个:
\n chain input {\n type filter hook input priority 0; policy drop;\n ct state related,established accept\n iif lo accept\n iif eno2 icmp type echo-request accept\n iif eno2 ip 192.168.0.0/16 tcp dport 22 accept\n iif eno2 ip 192.168.0.0/16 tcp dport 443 accept\n }\n
Run Code Online (Sandbox Code Playgroud)\n输入路径仍然需要Docker 本身(而不是其容器)的附加规则:可能需要规则来允许远程访问 Docker API(如果安全考虑允许)或Docker swarm使用的 VxLAN 等各种功能使用的 VxLAN 。
\ninet filter output
同样,OP 链的inet filter output
丢弃策略会终止主机连接(无法启动DNS查询、ping请求或下载等)。应该有policy accept
,或者应该添加来自主机本身的所需传出流量的例外。该链至少应该包括这样的内容:
chain output {\n type filter hook output priority 0; policy drop;\n ct state related,established accept\n oif lo accept\n udp dport { 53, 123 } accept\n tcp dport { 53, 80, 443 } accept\n icmp type echo-request accept\n }\n
Run Code Online (Sandbox Code Playgroud)\n容器的数据包不是由这些链评估的,而是由forward
链评估的,并且不会受到限制。
在未正确启用 ICMPv6 的情况下使用inet系列会阻止任何 IPv6 连接,因为 IPv6 不依赖(几乎从不防火墙)ARP,而是依赖 ICMPv6 来实现链路本地连接。要么使用系列(并使用表的过滤器ip
以外的其他名称以避免与iptables-nft发生任何冲突),要么正确处理 ICMPv6:全部接受或检查正确的SLAAC中和方向上所需的内容(NDP:RS, RA、NS、NA ……)、ping……处理。input
output
归档时间: |
|
查看次数: |
12552 次 |
最近记录: |