简介
在不断发展的容器技术领域,Podman 的最新版本 v4.6.0 包含一项有望改变游戏规则的功能:Podmansh。这是一个利用 Podman 强大的容器管理功能的登录 Shell。Podmansh 旨在重新定义用户与系统交互的方式,同时确保管理员拥有最大的安全性 和控制权。
为什么要使用 Podmansh?
管理对资源的访问是系统管理员的一项重要任务。越来越需要一种机制来允许将用户限制在预定义的边界内。`podmansh` 命令通过使系统管理员能够在容器中执行用户 Shell 来解决此问题,无论用户何时登录系统。
工作原理
管理员将系统上的用户配置为使用 `/usr/bin/podmansh` 命令而不是正常的 Shell 命令(如 `/bin/bash`)。当用户登录以这种方式设置的系统时,Podmansh 命令将在一个名为 `podmansh` 的无根容器中执行用户的会话。Podman 容器 `podmansh` 由 systemd 在用户会话启动时自动启动,并在所有用户会话退出之前继续运行。
用户登录的容器通过 Quadlet 文件定义。管理员可以通过卷(在 Quadlet 文件中为其指定)来控制容器中主机系统的可见性。管理员还可以通过 Quadlet 设置来限制已登录用户的访问权限、安全特权以及资源限制。
管理员在 /etc/containers/systemd/users 目录中创建 Quadlet 文件。然后,systemd 会在登录时为所有用户初始化它。例如,管理员可以创建一个名为 `Podmansh` 的特定 Quadlet,并允许用户使用登录 Shell /usr/bin/podmansh。这些用户登录 Shell 将通过 Podman 自动在 Podmansh 容器中执行。
为了更细粒度的控制,管理员可以在 /etc/containers/systemd/users/${USER_ID} 目录中为每个用户放置 Quadlet 文件。因此,只有指定的 USER_ID 在该用户登录时才会执行这些 Quadlet 服务。
设置
首先,使用 useradd 创建用户登录会话,同时以 root 身份运行,然后在 /etc/containers/systemd/users/${USER_ID} 中创建 Quadlet 文件。
示例 1: 完全锁定容器,无法访问主机操作系统。
# useradd -s /usr/bin/podmansh lockedu # grep lockedu /etc/passwd lockedu:x:4008:4008::/home/lockedu:/usr/bin/podmansh # USER_ID=$(id -u lockedu) # mkdir -p /etc/containers/systemd/users/${USER_ID} # cat > /etc/containers/systemd/users/${USER_ID}/podmansh.container << _EOF [Unit] Description=The Podmansh container After=local-fs.target [Container] Image=registry.fedoraproject.org/fedora ContainerName=podmansh RemapUsers=keep-id RunInit=yes DropCapability=all NoNewPrivileges=true Exec=sleep infinity [Install] RequiredBy=default.target _EOF |
请注意 Quadlet 文件中 [Container] 部分的几个字段。
- Image=registry.fedoraproject.org/fedora
此选项告诉 Podman 下载 fedora 镜像以在其中运行容器。管理员可以选择特定的容器镜像来启动用户,这些镜像可能与主机系统不同。 - ContainerName=podmansh
容器名称必须为 `podmansh`,因为 /usr/bin/podmansh 始终对 `podmansh` 容器执行 `podman exec`。 - RemapUsers=keep-id
此选项将用户的 USER_ID 映射为容器内的自身。如果没有此字段,用户将以用户命名空间的 root 身份登录。 - RunInit=yes
这告诉 podman 在容器内启动一个 init 进程,该进程将清理容器内的任何僵尸进程。 - DropCapability=all
此选项告诉 Podman 删除容器内的所有功能,并防止容器进程获得系统上的任何功能,即使它找到了逃离容器的方法。
- NoNewPrivileges=true
此选项更进一步,除了功能之外,还防止容器获得任何新的特权。 - Exec=sleep infinity
最后一个要查看的字段是 Exec 命令。大多数情况下,我们建议用户的会话在 Podmansh 容器中休眠。这将防止会话使用系统上的资源。由于用户会话被执行到容器中,因此它们将在容器镜像内运行默认的 /bin/sh。
如果你真的想将用户锁定在容器中,你甚至可以添加一个标志,例如
Network=none。此选项将从容器内的进程中删除所有网络访问权限。这意味着容器进程无法通过网络访问其他节点,从它的角度来看,盒子上没有网络。你还可以将容器设置为 ReadOnly=true,这将阻止用户写入除 `/run` 和 `/tmp` 中的 tmpfs 目录之外的任何地方。
当用户会话退出时,Quadlet 容器将从系统中删除,这意味着用户写入容器镜像的任何内容都将在用户会话终止时删除。
下一个示例将允许用户在其主目录中保存内容。
示例 2: 或者,以 root 身份运行时,创建一个 Quadlet,其中允许用户在用户命名空间内成为 root。他们还可以从其主目录永久读取/写入内容,该目录是从实际主机用户的帐户中挂载的卷,而不是位于容器内。
# useradd -s /usr/bin/podmansh confinedu # grep confinedu /etc/passwd confinedu:x:4009:4009::/home/confinedu:/usr/bin/podmansh # USER_ID=$(id -u confinedu) # mkdir -p /etc/containers/systemd/users/${USER_ID} # cat > /etc/containers/systemd/users/${USER_ID}/podmansh.container << _EOF [Unit] Description=The Podmansh container After=local-fs.target [Container] Image=registry.fedoraproject.org/fedora ContainerName=podmansh RemapUsers=keep-id RunInit=yes Volume=%h/data:%h:Z Exec=sleep infinity [Service] ExecStartPre=/usr/bin/mkdir -p %h/data [Install] RequiredBy=default.target _EOF |
请注意,在此示例中,[Container] 结构中的前四个字段与前一个示例相同。Exec 命令仍然是 `sleep infinity`。但是我们删除了 DropCapabilties 和 NoNewPrivileges 的安全锁定。没有这些限制,用户会话可以在其用户命名空间内成为 root,并可以执行某些特权活动,例如安装软件包(即使它们目前不会持久存在)。请注意,这是一个无根容器,这意味着用户进程实际上不是主机系统上的 root (uid=0)。
在 Quadlet 中添加了几行。
- Volume=%h/data:%h:Z
此行告诉 Podman 将用户主目录中的 data 目录挂载到容器中的其主目录。:Z 告诉 SELinux 系统为 data 目录标记与容器标记匹配的标签。%h 告诉 systemd 在调用 Podman 时将此字段扩展为用户的主目录。由于 `data` 目录被挂载到容器中,因此它将在用户下次登录系统时在容器之外继续存在。 - [Service]
ExecStartPre=/usr/bin/mkdir -p %h/data
此部分告诉 systemd 在启动容器之前预先创建用户主目录中的 data 目录。
示例 3: 或者,以 root 身份运行时,创建一个 Quadlet,其中允许用户在用户命名空间内成为 root。他们还可以从其主目录永久读取/写入内容,该目录是从实际主机用户的帐户中挂载的卷,而不是位于容器内。
# useradd -s /usr/bin/podmansh volumeu # grep volumeu /etc/passwd volumeu:x:4010:4010::/home/volumeu:/usr/bin/podmansh # USER_ID=$(id -u volumeu) # mkdir -p /etc/containers/systemd/users/${USER_ID} # cat > /etc/containers/systemd/users/${USER_ID}/podmansh.container << _EOF [Unit] Description=The Podmansh container After=local-fs.target [Container] Image=registry.access.redhat.com/ubi9 ContainerName=podmansh RemapUsers=keep-id RunInit=yes Device=/dev/nvidia123Volume=/secret/data:/secret:ro Exec=sleep infinity [Install] RequiredBy=default.target _EOF |
请注意,在最后一个示例中,添加了两个字段以允许对主机上的特定卷进行只读访问,并且向容器添加了 nVidia 设备。镜像已更改为 ubi9,以突出显示你可以有多个 Podmansh Quadlet,每个用户一个,并且这些 Quadlet 可以使用不同的镜像。
在 Quadlet 中添加了几行。
- Device=/dev/nvidia123
设备行将把此设备添加到容器中,供用户会话使用。
- Volume=/secret/data:/secret:ro
此行告诉 Podman 将 /secret/data 目录作为 /secret 挂载到容器中,作为只读挂载。这里的想法是允许容器镜像内的应用程序使用该设备来处理 /secret 目录中的数据。
最后一个示例将允许管理员根据用户的安全级别向不同的用户公开系统的不同部分。
安全和机密性
用户被限制在其容器环境中,并具有所有安全机制,包括 SELinux。在容器内变得可用的任何系统信息严格限制为挂载到容器中的卷,确保高水平的安全性和隔离。
无缝操作
用户会话启动后,systemd 会自动创建关联的容器。当所有与用户会话的连接被移除时,systemd 会关闭容器。这意味着用户可以多次登录系统,每个会话连接到同一个容器,提供无缝的用户体验。
此外,管理员可以通过卷将主机系统中的特定主机数据公开给用户。这可以在不将用户暴露于系统的其他部分的情况下完成,从而维护整个系统的完整性和安全性。
总结
总之,Podman v4.6 的新功能 Podmansh 有望彻底改变系统管理员管理用户访问和控制的方式,同时保持令人印象深刻的安全性和机密性水平。这是容器技术领域的突破性一步,为用户提供了与系统交互的新方式。
发表评论