rootless无根容器

无根容器的挑战

随着云计算的发展,容器继续变得越来越流行。我们实现容器的方式正在引入新的解决方案和想法。其中一个新想法是无根容器。

无根容器是一个新的容器概念,它不需要root权限即可制定。已经提出了许多解决方案来克服创建具有非特权用户的容器的技术挑战,其中一些仍在开发中,一些已经准备好投入生产。虽然无根容器呈现出一些优势,主要是从安全角度来看,但它们仍处于早期阶段。

在这篇文章中,第42单元研究员Aviv Sasson回顾了无根容器的内部结构。Aviv还提供了他在其中一个名为Slirp的主要无根网络组件中发现的漏洞。运行Prisma Cloud的Palo Alto Networks客户可通过主机和容器漏洞扫描程序保护其免受此漏洞的攻击,该扫描程序会对使用此漏洞运行的软件组件发出警报。

顾名思义,无根容器与传统容器相同,但不同之处在于它们不需要root特权即可形成。

如今,无根容器仍处于早期采用阶段,但已经得到该领域主要参与者的支持。

添加新的安全层。如果容器引擎、运行时或协调器受到危害,攻击者将不会获得主机上的root权限。

Linux内核中的一项新开发使此解决方案成为可能,它允许非特权用户创建新的用户名称空间。当用户创建并输入新的用户名称空间时,他将成为该名称空间上下文中的root用户,并获得生成正常运行的容器所需的大部分权限。

我不会深入研究用户命名空间的技术细节,但是在影响整个系统的区域中,命名空间根没有真正的根拥有特权(例如,命名空间根不能加载或删除内核模块)。这导致了由每个容器引擎以不同方式解决的一些挑战。

为了在容器内实现适当的联网,通常会创建一个虚拟以太网设备(Veth)并负责联网。这给无根容器带来了问题,因为只有真正的root才有权创建这样的设备。提出了许多解决方案来解决该问题-主要的解决方案是Slirp和LXC-User-NIC。

Slirp是一个广为人知的项目,最初主要用于QEMU(又名Quick Emulator)中的联网。经过一些修改后,它被调整为在无根容器中启用网络。它的工作方式是分叉到容器的用户和网络名称空间,并创建一个成为默认路由的分路设备。然后,它将设备的文件描述符传给在默认网络名称空间中运行的父设备,该父设备现在可以与容器和Internet进行通信。

设置网络的另一种方法是运行创建veth设备的setuid二进制文件。尽管它确实启用了容器内部的网络,但它忽略了无根容器的要点,因为它要求容器二进制文件以root权限运行。

实现容器的一个复杂元素是存储管理。默认情况下,容器引擎使用称为Overlay2(或Overlay)的特殊驱动程序来创建空间和性能都很高效的分层文件系统。使用无根容器不能做到这一点,因为大多数Linux发行版不允许在用户名称空间中挂载覆盖文件系统(Ubuntu是个例外)。这个问题驱使无根容器与其他驱动程序和文件系统一起工作。

显而易见的解决方案是使用另一个驱动程序,如VFS存储驱动程序。虽然它起作用了,但它的效率要低得多。更好的解决方案是创建一个新的存储驱动程序来满足无根容器的需要。一个这样的驱动器是FUSE-OverlayFS。它是Overlay的用户空间实现,比VFS更高效,并且可以在用户名称空间内运行。

Linux控制组(Cgroup)特性是实现容器的另一个关键元素,它允许将进程和容器组织成分层的组,然后可以限制和监视各种类型的资源的使用。由于内核的cgroups接口是通过伪文件系统提供的,该伪文件系统通常驻留在“/sys”(根拥有的目录)中,因此非root用户无法访问和使用它。

cgroup的新内核实现,支持将权限委派给非特权用户。缺点是V2不支持为cgroups V1实现的所有控制器(例如,DEVICES、NET_CLS、NET_PRIO等)。

LXC针对该问题的另一个解决方案是安装pam_cgfs.so,这是一个可插拔的身份验证模块(PAM模块),允许非特权用户对cgroup进行身份验证和管理。

Docker Rootless 基本概念

Rootless 模式允许以非 root 用户身份运行 Docker 守护进程(dockerd)和容器,以缓解 Docker 守护进程和容器运行时中潜在的漏洞。Rootless 模式是在 Docker v19.03 版本作为实验性功能引入的,在 Docker v20.10 版本 GA。

Rootless 模式目前对 Cgroups 资源控制,Apparmor 安全配置,Overlay 网络,存储驱动等还有一定的限制,暂时还不能完全取代 “Rootful” Docker。关于 Docker Rootless 的详细信息参见 Docker 官方文档 [ Run the Docker daemon as a non-root user (Rootless mode)] (https://docs.docker.com/engine/security/rootless/#limiting-resources)

Rootless 模式利用 user namespaces 将容器中的 root 用户和 Docker 守护进程(dockerd)用户映射到宿主机的非特权用户范围内。Docker 此前已经提供了 --userns-remap 标志支持了相关能力,提升了容器的安全隔离性。Rootless 模式在此之上,让 Docker 守护进程也运行在重映射的用户名空间中。

实践验证

环境准备

本文使用 Centos 7.5 操作系统的虚拟机进行实验。

[root@demo ~]# cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)
创建用户
useradd rootless
echo 123456 | passwd rootless --stdin
安装依赖

Rootless 模式可以在没有 root 权限的情况下运行 Docker 守护进程和容器, 但是需要安装 newuidmapnewgidmap 工具,以便在用户命名空间下创建从属(subordinate)用户和组的映射(remapping)。通过以下命令安装 newuidmapnewgidmap 工具。

cat <<EOF | sudo sh -x
curl -o /etc/yum.repos.d/vbatts-shadow-utils-newxidmap-epel-7.repo https://copr.fedorainfracloud.org/coprs/vbatts/shadow-utils-newxidmap/repo/epel-7/vbatts-shadow-utils-newxidmap-epel-7.repo
yum install -y shadow-utils46-newxidmap
cat <<EOT >/etc/sysctl.conf
user.max_user_namespaces = 28633
EOT
sysctl --system
EOF
UID/GID 映射配置

从属用户和组的映射由两个配置文件来控制,分别是 /etc/subuid/etc/subgid。使用以下命令为 rootless 用户设置 65536 个从属用户和组的映射。

echo "rootless:100000:65536" | tee /etc/subuid
echo "rootless:100000:65536" | tee /etc/subgid

对于 subuid,这一行记录的含义为:用户 rootless,在当前的 user namespace 中具有 65536 个从属用户,用户 ID 为 100000-165535,在一个子 user namespace 中,这些从属用户被映射成 ID 为 0-65535 的用户。subgid 的含义和 subuid 相同。

比如说用户 rootless 在宿主机上只是一个具有普通权限的用户。我们可以把他的一个从属 ID (比如 100000 )分配给容器所属的 user namespace,并把 ID 100000 映射到该 user namespace 中的 uid 0。此时即便容器中的进程具有 root 权限,但也仅仅是在容器所在的 user namespace 中,一旦到了宿主机中,顶多也就有 rootless 用户的权限而已。

安装 Rootless Docker

切换到 rootless 用户。

su - rootless 

执行以下命令安装 Rootless Docker。

curl -fsSL https://get.docker.com/rootless | sh

安装成功后显示如下内容。

将以下内容添加到 ~/.bashrc 文件中,添加完以后使用 source ~/.bashrc 命令使环境变量生效。

export XDG_RUNTIME_DIR=/home/rootless/.docker/run
export PATH=/home/rootless/bin:$PATH
export DOCKER_HOST=unix:///home/rootless/.docker/run/docker.sock
启动 Docker 守护进程

使用以下命令启动 Docker 守护进程。

dockerd-rootless.sh
运行容器

使用以下命令启动一个 nginx 容器,并将 80 端口映射到宿主机的 8080 端口。

docker run -d -p 8080:80 nginx

查看容器。

[rootless@demo ~]$ docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                                   NAMES
f3b204c97a84   nginx     "/docker-entrypoint.…"   9 minutes ago   Up 9 minutes   0.0.0.0:8080->80/tcp, :::8080->80/tcp   bold_stonebraker

访问容器。

[rootless@demo ~]$ curl http://localhost:8080

# 返回结果 Nginx 欢迎界面
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

--end--

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值