selinux 标签
最近,我通过电子邮件回答了有关SELinux和容器运行时的问题。 之后,我意识到其他人可能会对同一个主题感到疑惑,所以我决定将答案变成一篇针对Opensource.com的文章,希望我可以帮助其他有相同问题的人。 电子邮件开始了:
“ Dan,几年前您很乐意回答我的SELinux问题,我希望您仍然在从事这个行业。”
尽管我现在是Red Hat的容器团队的负责人,并且不再担任SELinux团队的工作,但是由于我一直在努力使SELinux和容器能够很好地协同工作,因此我仍然在很多方面仍然参与SELinux。 SELinux和容器技术是完美的结合。
电子邮件继续:
“我刚刚开始处理一些通过Docker容器化的软件,并且通常只能在Ubuntu上运行。自然地,这意味着没有人考虑过如何与SELinux进行交互。
“我知道容器默认情况下会获得一对随机选择的MCS [Multi-Category Security]标签,并且它们创建的文件显然具有相同的类别。但是,当需要重建或升级容器时,这些文件现在无法访问,因为新容器具有不同的类别对。
“我们应该使用新的类别重新标记这些文件吗?还是我们必须自己选择类别,然后在运行容器时使用Docker的
--security-opt
选项?我们如何做到这一点而又不会冒其他容器的风险最终具有相同的类别?”
关于第一个问题,当像Docker这样的容器运行时以及我们一直在研究的一些新运行时(如podman , CRI-O和Buildah)创建容器时,它们会选择一个随机的MCS标签来运行该容器。 MCS标签由两个介于0和1,023之间的随机数组成,并且必须是唯一的。 它们以c
或类别为前缀。 SELinux还需要一个敏感度等级s0
。
s0:c1,c2
。
注意s0:c2,c1
是同一件事。
另外,两个数字可能不相同;
SELinux会将s0:c1,c1
为s0:c1
。
这为我们提供了大约(1024 * 1024) /2 -1024
类别-主机上约有500,000个唯一容器。
我们最初在2008年为虚拟机创建了MCS标签,通常将其称为sVirt。 我们认为,在一台机器上运行50万个VM几年后不会发生。 使用集装箱,数量可能最终会受到威胁。 但是,尽管算法变得更加复杂,但我们始终可以为每个标签进入三个或更多类别。
SELinux不仅仅是MCS标签。 该过程和内容也被分配了SELinux“类型”。 进程通常使用container_t
类型运行,而内容使用container_file_t
类型创建。
Process | system_u:system_r:container_t:s0:c1,c2 |
Content | system_u:object_r:container_file_t:s0:c1,c2 |
注意:我编写了SELinux / MCS golang绑定,以本地实现SELinux接口来设置标签。 这些约束条件是对开放容器倡议(OCI)的贡献。
问题的第二部分询问磁盘上容器创建的内容。 作者是正确的,卷上的内容将使用内容标签system_u:object_r:container_file_t:s0:c1,c2
标签。
但是他做出了错误的假设,即容器重新启动时,它将选择其他MCS标签,因此将不再能够读取内容。 当容器中的进程停止时,容器运行时不会破坏“容器”。 它们记录有关如何运行容器的信息,包括用于运行容器的SELinux标签。 因此,在停止和启动容器时,它将始终使用相同的MCS标签运行。 不仅如此,容器运行时还可以在启动时读取其数据库或现有容器,保留已使用的MCS标签,因此它们可以保证所有新容器都不会与已保留的MCS标签冲突。
您可以覆盖此行为。 如果要创建另一个容器,该容器能够访问第一个容器创建的数据,则可以告诉容器运行时使用相同的MCS标签。
# podman run -ti -v /var/lib/previouscontainer:/var/lib/db --security-
opt label=level:s0:c1,c2 fedora sh
# docker run -ti -v /var/lib/previouscontainer:/var/lib/db --security-
opt label=level:s0:c1,c2 fedora sh
现在,如果您从容器运行时中删除一个容器并将内容保留在磁盘上,则有可能重新使用标签。 对此内容最好的做法是在删除容器时更改内容的类型。 命令restorecon -rF /var/lib/previouscontainer
将强制内容标签重新回到容器无法读取/写入的标签。
阅读我的回复后,电子邮件作者回答了另一个问题:
“哦,如果我要同时由Docker和libvirt创建容器呢?”
我可以用两种不同的方式解释这个问题。 一种可能是,他担心通过Docker创建的容器和libvirt创建的VM。 这个问题的简单答案是:即使两个标签都使用相同的MCS范围,但它们使用的类型却不同。 Libvirt使用svirt_t
(进程)和svirt_image_t
(文件),并且SELinux将根据类型强制实施保持分离。
但是查看问题的另一种方法是查看libvirt-lxc,它也创建了容器。 使用容器-selinux的其他工具链包括我们的新工具链CRI-O,podman和Buildah,以及RKT和Systemd-nspawn,甚至lxc工具也可以利用这一点。
Docker不与其他任何工具共享MCS数据存储,因此最好不要在同一台计算机上同时运行它们,或者最好使用OpenShift或Kubernetes等更高级别的工具来选择SELinux / MCS标签以在容器中运行,以确保其唯一性。 (有关更多详细信息,请参见此OpenShift示例 。)
我们新的容器运行时工具CRI-O,Buildah和podman都共享同一数据库。 您可以在同一主机上同时运行所有这三个文件,而不必担心冲突。
底线
SELinux为您的容器运行时提供了很好的文件系统分隔,但是在同一台计算机上同时运行多个容器运行时时,请务必小心,并且在删除容器时,请清除所有留在主机上的内容。
翻译自: https://opensource.com/article/18/2/understanding-selinux-labels-container-runtimes
selinux 标签