原文地址:https://opensource.com/article/18/3/just-say-no-root-containers
原文作者: Daniel J Walsh (Red Hat)
我经常被问到有什么安全措施能用来控制容器进程在操作系统上的行为。在Opensource.com之前的文章中我介绍了大部分内容:
上面所列的文章都是关于在容器中特权进程在系统中能做什么。例如:在容器中怎么样运行root权限而不允许它突破。
用户命名空间就是容器中特权进程,如果它们突破,在容器外它们不在是一个特权进程。例如:在容器中,我的UID是0,但是在容器外边我的UID是5000。由于缺少文件系统的支持的问题,到目前为止,命名空间并不是突破容器的有效手段。
OpenShift是基于Kubernetes,Linux红帽企业版,OCI容器所创建容器平台,它具有很好的安全特性。默认情况下,容器是不允许以root权限来运行。管理员可以修改这个配置,否则,所有用户容器不能以root权限运行。这在多租户的OpenShift Kubernetes集群中非常重要,因为单集群可能服务于多个应用程序以及多个开发团队。对管理员来说为每个使用者提供相互隔离的集群环境是不切实际的甚至是不可取的。遗憾的是,对于OpenShift来说,使用者们最大的抱怨就是不能很方便的使用docker.io社区版本的容器镜像。这是因为当今世界上绝大部分的容器都需要root权限。
为什么所有的镜像都需要root权限?
如果你实际上检查root权限的原因,在系统上,是十分有限的。
修改主机的系统
在系统中使用root权限的一个主要原因是改变系统的默认配置,比如修改内核的配置。
在 Fedora, CentOS, 以及红帽企业版的linux系统中,我们有系统容器的概念,允许使用atomic命令在系统上安装具有特权的容器。它们拥有充分的特权,被允许修改系统和内核。在系统容器情况下,我们使用容器镜像作为内容传递系统,并不是真正需要容器的隔离。系统容器更适合于操作系统宿主机服务,而不是大多数容器运行的用户应用程序服务。
在应用程序容器中,我们几乎从不希望容器内的进程修改内核。默认情况下,这绝对不是必需的。
Uninx/Linux的传统:
操作系统供应商和开发者知道以root权限长时间运行进程是危险的,因此内核增加了许多Linux的功能,允许进程以root权限启动,然后尽快去删除特权。大部分UID和GID功能允许像Web服务的进程以root权限启动,然后变成非root权限。这样做事未来绑定到1024以下的端口(稍后会详细介绍)。
容器运行时可以以非root权限启动应用程序。众所周知,系统化也是如此,但过去20年来构建的大多数软件都假设它是以root身份启动并删除权限。
绑定小于1024的端口
在1960年-1970年时候,当计算机很少,非root用户无法绑定小于1024的端口是出于一种安全性考虑。只有管理员能做这个,所以你相信这些应用程序去监听这些端口。大于1024的端口能被任何使用者绑定,所以它们不能被信任。这种做法带来的安全性已经消失了,但是我们依然存在这样的限制。
这种限制的最大问题是人们喜欢它们的Web服务去监听服务器的80端口。这意味着apache或者nginx开始以root权限运行原因是它们能绑定80端口,然后变成非root权限。
容器采用的是端口映射机制,可以解决这个问题。你可以启动容器去监听任何网络端口,然后去把端口映射到主机的80端口。
这个命令,podman(容器运行环境)将在你的主机上运行一个监听80端口的apacge_unpriv的容器,在容器中的Apache进程并不是root用户,而是一个 apache的普通用户,并且监听8080端口。
podman run -d -p 80:8080 -u apache apache_unpriv
或者:
docker run -d -p 80:8080 -u apache apache_unpriv
在容器镜像中安装软件
- 当使用docker build命令创建容器镜像时,容器中的内容只是用于分发的标准的打包软件。软件通过rpm包或者Debin包提供。然而,发行版本包软件能通过root权限来安装。一个安装包希望做一些事情像操作 /etc/passwd 文件增加用户,并且使用不同的UID/GODs权限在文件系统上放置一些文件。许多软件也希望通过系统初始化进程(systemd)启动并且作为root权限启动,然后在启动后删除root权限。
- 不幸的是,容器化变革已经五年之久了,这些状况一直没有得到改善,几年前,我试图修改httpd包,使得非root用户何时安装它并具有不同的配置。但是我失败了。我需要让打包器以及包管理系统理解启动时候能识别这种差异,然后可以制作运行良好而不需要root权限的容器。
- 我们现在能解决的一个问题是如何隔离构建的系统从安装的系统中。我对#nobigfatdaemons的一个问题是,Docker守护程序导致容器运行时使用相同的权限来运行容器,就像构建容器映像一样。
- 如果我们更改系统或使用不同的工具,比如Buildah,用于构建具有更宽松约束的容器和用于在生产中运行容器的 CRI-O / Kubernetes / OpenShift,那么我们可以使用提升的权限进行构建,但随后运行容器更严格的约束,或者希望作为非root用户。
结果
在你容器中运行的应用程序几乎都不需要root权限,你的web应用程序,数据库,负载均衡,数据处理等等都不需要以root权限启动。当我们开始构建不需要root权限的容器镜像,而其他人制作镜像也基于非root特权的镜像时,我们会看到容器安全性的巨大飞跃。
在容器中运行root时,仍需要很多的很多的培训和学习,没有良好的训练,聪明的管理员也会做出错误的决定。