,

用户命名空间和功能之间的交互

用户命名空间和功能是使容器安全的重要的内核功能。它们允许更好地隔离容器并限制容器可能具有的权限。不久前,一位用户报告了一个错误,其中当容器之间共享命名空间时,发现了一些奇怪的行为,这可能导致安全问题。让我们仔细看看如果你没有意识到这种行为,会发生什么问题。

首先,让我们构建一个包含安装了 nftables 的容器镜像

$ cat Containerfile 
FROM fedora
RUN dnf install -y nftables
$ podman build -t testimg .

现在我们已经在镜像中安装了 nft 并可以使用它。nft 管理防火墙,因此它需要 CAP_NET_ADMIN 功能才能工作,否则它会报错。因此,当我们运行

$ podman run --rm testimg nft list ruleset
Operation not permitted (you must be root)
netlink: Error: cache initialization failed: Operation not permitted
$ podman run --rm --cap-add CAP_NET_ADMIN testimg nft list ruleset
<Results omitted for brevity>

只有第二个命令有效,因为 CAP_NET_ADMIN 默认情况下不会提供给容器。请注意,该命令没有返回任何输出,因为没有规则。

现在假设我们运行两个容器,并且想要在它们之间共享网络,这可以通过使用--network container:<name>选项来完成。在第一个终端中运行

$ podman run --rm --name test -it testimg 
[root@a6a4ddc4a7c8 /]# nft list ruleset
Operation not permitted (you must be root)
netlink: Error: cache initialization failed: Operation not permitted
[root@a6a4ddc4a7c8 /]#

在第二个终端中运行

$ podman run --rm --network container:test -it testimg
[root@6d4b196e75be /]# nft list ruleset
Operation not permitted (you must be root)
netlink: Error: cache initialization failed: Operation not permitted

在这两种情况下,我们都无法按预期修改命名空间。

让我们再次运行这些命令,但这次对第一个容器使用--userns keep-id

# terminal 1
$ podman run --rm --name test --userns keep-id --user 0:0 -it testimg 
[root@91896ef2fac8 /]# nft list ruleset
Operation not permitted (you must be root)
netlink: Error: cache initialization failed: Operation not permitted
[root@91896ef2fac8 /]#

# terminal 2
 podman run --rm --network container:test -it testimg
[root@59ad31cb4de1 /]# nft list ruleset
[root@59ad31cb4de1 /]#

现在,即使我们没有给第二个容器 CAP_NET_ADMIN,它仍然可以修改网络。这对大多数人来说是不可预期的,因此如果你这样做并且没有意识到这一点,可能会造成安全问题。

现在让我们最后一次运行它,但对第二个容器使用--userns keep-id

# terminal 1
$ podman run --rm --name test -it testimg 
[root@8860d6004a8d /]# nft list ruleset
Operation not permitted (you must be root)
netlink: Error: cache initialization failed: Operation not permitted
[root@8860d6004a8d /]# 

# terminal 2
$ podman run --rm --network container:test --userns keep-id --user 0:0 -it testimg
[root@10cb690d5b93 /]# nft list ruleset
Operation not permitted (you must be root)
netlink: Error: cache initialization failed: Operation not permitted
[root@10cb690d5b93 /]#

现在,两个容器都无法修改网络。你甚至可以向第二个容器添加--cap-add CAP_NET_ADMIN,它仍然无法工作。

发生了什么?

这种行为乍看起来似乎是不可预期的和错误的,但它完全按照内核安全检查的设计工作。功能总是按用户命名空间分配的,当创建新的用户命名空间时,进程将在新命名空间中获得所有功能,但会删除父命名空间中的所有功能。同样重要的是要知道,内核始终根据创建其他命名空间的用户命名空间来检查命名空间的权限。如果命名空间是从任何父用户命名空间创建的,那么内核将不允许你修改它,你基本上对它们没有权限。另一方面,对于由子用户命名空间创建的命名空间,它始终具有所有功能,即使进程删除了它们。

这正是第二种情况下发生的情况。OCI 运行时首先创建子用户命名空间,然后在其中创建新的网络命名空间。然后,第二个容器位于父用户命名空间中,因此它始终对共享的网络命名空间拥有所有功能。

在第三种情况下,情况正好相反,第二个容器是用户命名空间的一部分,因此是子命名空间,因此它永远无法修改由父用户命名空间创建的网络命名空间。

要解决此问题,最好在容器之间共享用户命名空间,只要两个容器都是同一个用户命名空间的一部分,你就会获得预期的行为,其中给定的功能得到尊重。让我们再次尝试第二种情况,但这次对第二个容器也使用 --userns container:

# terminal 1
$ podman run --rm --name test --userns keep-id --user 0:0 -it testimg 
[root@198c6101c2cd /]# nft list ruleset
Operation not permitted (you must be root)
netlink: Error: cache initialization failed: Operation not permitted
[root@198c6101c2cd /]#

# terminal 2
$ podman run --rm --network container:test --userns container:test  -it testimg
[root@43644d997e2d /]# nft list ruleset
Operation not permitted (you must be root)
netlink: Error: cache initialization failed: Operation not permitted
[root@43644d997e2d /]# 

网络命名空间只是一个示例,该规则也适用于其他命名空间。你可以在user_namespaces(7)手册页中阅读有关此行为的更多信息。有了这些知识,你可以避免意外地为容器赋予超出其应有权限的权限。

发表评论

订阅

使用你的电子邮件地址注册,以便从此网站接收电子邮件更新。


类别


搜索