我打算使用 LXC 容器来隔离大部分面向网络的服务。
根据我的理解,我主要有两种方法来做到这一点:
创建 root 拥有的非特权容器。在这种情况下,根将拥有一大组子 UID 和子 GID,并且该范围的不同子集将受到每个容器的影响(没有容器会彼此共享任何子 UID 或子 GID),
创建非特权系统帐户拥有的非特权容器。在这种情况下,每个帐户将拥有一个容器以及该容器所需的从属 UID 和 GID。
从可用性的角度来看,前者要好得多:更容易设置和维护。
然而,从安全角度来看,两者有什么区别吗?
例如:
与属于不同用户并因此属于不同池(不同行)的 ID 相比,属于
/etc/subuid
和中定义的同一池(同一行)的 ID 之间是否存在某种链接或水平关系?/etc/subgid
从属 ID 与其所有者帐户之间是否存在某种链接或垂直关系? root 拥有的从属 ID 是否可以比非特权用户拥有的从属 ID 获得更高的权限?从属 ID 能否以比升级到任何其他任意 ID 更简单的方式升级到其所有者 ID?
由 root 拥有意味着管理容器的所有命令都将以主机的 root 权限启动。这是否构成弱点,或者是否所有特权都被提前放弃?
ETC。
换句话说: root 拥有的非特权容器可能比标准帐户拥有的容器“更少非特权”吗?
答案1
换句话说: root 拥有的非特权容器可能比标准帐户拥有的容器“更少非特权”吗?
我不这么认为。重要的是/proc/$PID/uid_map
容器的用户命名空间中的进程中有什么,而不是/etc/subuid
.假设您从以下位置执行以下命令初始用户命名空间(即,不是来自容器)$PID
容器中运行的进程的:
$ cat /proc/$PID/uid_map
0 200000 1000
这意味着[0-1000)
进程 $PID 的 UID 范围将映射到[200000-201000)
其(容器的)用户命名空间之外的 UID 范围。超出范围的 UID[200000-201000)
将映射到$(cat /proc/sys/kernel/overflowuid)
容器中的 65534 ( )。例如,如果您不创建新的 PID 命名空间,则可能会发生这种情况。在这种情况下,容器中的进程将看到外部进程,但它们的 UID 将为 65534。
因此,通过正确的 UID 映射,即使容器由 root 启动,其进程也会在其外部拥有非特权 UID。
内部的从属 UID/etc/subuid
不以任何方式链接到外部的单个 UID。该文件的目的是允许非特权用户启动使用多个 UID 的容器(大多数 Linux 操作系统都是这种情况)。默认情况下,如果您是非特权用户,则只能映射您的 UID。也就是说,如果你的UID是1000并且$PID
引用容器中的一个进程,你只能这样做
echo "$N 1000 1" >/proc/$PID/uid_map
对于任何$N
非特权用户。其他一切都是不允许的。如果你可以绘制更远的范围,即
echo "$N 1000 50" >/proc/$PID/uid_map
[1000-1050)
您可以通过容器访问容器外部的 UID 。当然,如果您可以更改外部 UID 范围的开始,您就可以轻松获得 root 权限。因此/etc/subuid
定义了您可以使用的外部范围。该文件由newuidmap
setuid root使用。
$ cat /etc/subuid
woky:200000:50
$ echo '0 200000 50' >/proc/$PID/uid_map
-bash: echo: write error: Operation not permitted
$ newuidmap $PID 0 200000 50
$ # success
细节要复杂得多,我可能不是解释它的合适人选,但我想最好没有答案。 :-) 您可能想查看手册页user_namespaces(7)
和newuidmap(1)
我自己的研究新的 Linux 用户命名空间中的第一个进程需要调用 setuid()?。不幸的是,我不完全确定 LXC 如何使用这个文件。