使用 Podman 开始使用 Rootless 容器

您是否使用容器部署软件? 你在使用 Podman 吗? 您想通过以尽可能少的权限运行容器来提升您的安全性吗? 男孩,我有一篇文章给你!

什么是 Podman?

波德曼 是一款 Red Hat 产品,旨在替代 Docker。 对于 99% 的任务,它确实是一个真正的 Docker 替代品。 它的一些特性是支持无根容器、使用 fork/exec 模型启动容器、无守护进程等等。

无根容器的优势是显而易见的。 如果可以阻止它以 root 身份运行,则可以在没有 root 权限的情况下运行它。

通过 GIPHY

通过这篇文章,我希望能帮助您消除使用 Podman 部署无根容器时可能出现的一些障碍。

无根执行中的 Podman

如果您是一名经验丰富的 IT 专业人员,您可能犯过以下罪行之一:

  • 运行 docker 命令使用 sudo提升其特权
  • 将您的用户非 root 用户添加到 docker 团体。 大笨蛋

您现在可能已经意识到,这是一种糟糕的安全做法。 您正在授予 Docker 守护程序对您的机器的 root 访问权限。 这暴露了两种利用方法:

  • Docker 守护进程 (dockerd) 以 root 身份运行。 如果 dockerd 存在安全漏洞,您的整个系统都会受到威胁,因为 dockerd 是一个进程拥有 root 用户。
  • 您使用的图像可能存在漏洞。 如果易受攻击的 imgae 被作为 root 用户? 攻击者可以使用易受攻击的图像来访问您的整个系统。

解决方案很简单,即使您信任它,也不要以 root 身份运行所有内容。 记住, 没有什么是 100% 安全的. 我向您介绍 Podman 无需 root 访问即可管理容器的能力。

如果您以非 root 用户身份使用 Podman 启动容器,则该容器不会获得任何额外权限,Podman 也不会要求您提供 sudo 密码。

以下是 Podman 为您提供的好处 无根容器 (没有任何超级用户权限):

  • 您可以为每个本地用户隔离一组公共容器。 (例如,在用户下运行 Nextcloud 和 MariaDB nextcloud_user 以及用户下的容器Gitea和PostgreSQL gitea_user)
  • 即使容器/Podman 受到威胁,它也无法完全控制主机系统,因为执行容器的用户不是 root. 但是,是的,运行被利用容器的用户也可能被视为流氓用户。

无根 Podman 的限制

当您使用 root-full Podman/Docker 时,您将授予 Podman/Docker 超级用户级别的权限。 这当然非常糟糕,但这也意味着所有宣传的功能都按预期工作。

相反,当您在没有 root 权限的情况下运行 Podman 容器时,它有一些限制。 一些主要的如下:

  • 容器镜像不能跨用户共享。 如果 user0 拉’nginx:stable-alpine‘ 图片, user1 将不得不单独拉’nginx:stable-alpine‘ 为他们自己的形象。 不可能 [at least not yet] 允许您在用户之间共享图像。 但是,您可以将图像从一个用户复制到另一个用户, 请参阅 Red Hat 的本指南.
  • 小于 1024 的端口不能直接绑定。 存在一种解决方法。
  • 无根容器可能无法 ping 任何主机。 存在解决方法.
  • 如果您在无根 Podman 容器中指定 UID,则任何未映射到预先存在的容器的 UID 都可能会失败。 最好从现有的用户 shell 执行 Podman。 或者更好的是,创建一个 systemd 服务来自动启动它。

开始使用无根 Podman

在开始无根执行容器之前,需要满足一些先决条件。

确保你有 slirp4netns 已安装

slirp4netns 包用于为非特权网络命名空间提供用户模式网络。 如果您希望您的无根容器与任何类型的网络交互,这是必要的。

您可以安装 slirp4netns 在基于 Debian/Ubuntu 的 Linux 发行版上使用 apt 像这样的包管理器:

sudo apt install slirp4netns

上 Fedora基于 /RHEL 的 Linux 发行版,使用 dnf 要安装的包管理器 slirp4netns 像这样:

sudo dnf install slirp4netns

Arch Linux 用户知道怎样使用 pacman,但无论怎样,以下是您可能正在寻找的命令:

sudo pacman -Sy slirp4netns

确保您的 subuidsubgid 已正确配置

由于无 root 的 Podman 容器由系统上的现有用户运行,因此非 root 用户需要权限才能将无 root 容器作为 UID 运行,而 UID 不是他们自己的 UID。 这也适用于 GID。

每个用户都有一个允许使用的 UID 范围。 这是在 /etc/subuid 文件; 和 /etc/subgid 文件用于允许用户使用的 GID。

该文件的格式如下:

username:initial UID/GID allocated to user:range/size of allowd UIDs/GIDs

所以,让我们说我的用户, pratham 想要 100 个 UID 给自己和 krishna 自己想要 1000 个 UID。 下面是怎样 /etc/subuid 文件看起来像:

pratham:100000:100
krishna:100100:1000

这实际上意味着用户 pratham 可以使用 ‘100000’ 和 ‘100100’ 之间的 UID。 同时,用户 krishna 可以使用 ‘100100’ 和 ‘101100’ 之间的 UID。

通常,这已经为您创建的每个用户设置好了。 通常,此范围设置为“65536”可用的 GID/UID。 但在某些情况下,这需要手动完成。

但是请稍等,如果尚未为您的用户完成此操作,则您无需为每个用户手动执行此操作。 你可以只使用 usermod 为此命令。 以下是执行此操作的命令语法:

sudo usermod --add-subuids START-RANGE --add-subgids START-RANGE USERNAME 

替换字符串 START, RANGEUSERNAME 根据您的需要。

⚠️确保文件的权限 /etc/subuid/etc/subgid 设置为 644 并由 root:root.

想要绑定小于 1024 的端口?

如果您使用 SSL 的反向代理,您将知道端口 80 和 443 需要由证书提供程序访问,例如 让我们加密.

如果您尝试将低于 1024 的端口绑定到 Podman 管理的无根容器,您会注意到这是不可能的。 好吧,这是可能的,但这不是开箱即用的配置。

不允许非 root 用户在小于端口 1024 的端口上绑定任何内容。

那么,怎样在无根 Podman 中绑定低于 1024 的端口? 为此,首先确定您需要的最低端口。 就我而言,要部署 SSL,我需要端口 80 和 443。所以我需要的最低端口是端口 80。

一旦确定,将以下行添加到 /etc/sysctl.conf 文件:

net.ipv4.ip_unprivileged_port_start=YOUR_PORT_NUMBER

本质上,您正在改变 net.ipv4.ip_unprivileged_port_start 到您需要的最低端口。 如果我替换 YOUR_PORT_NUMBER 使用 80,我可以在无根容器中将端口 80 与 Podman 绑定。

我的图像在哪里?

没必要对我大喊大叫,伙计。 我本来要告诉你的,最后…

正如我之前指出的,Podman 的一个限制是它不能在用户之间共享图像。 它们要么需要为每个用户提取,要么从一个用户复制到另一个用户。 这两者都占用 2x/3x/4x 空间(取决于存在多少重复项)。

任何用户的图像都存储在他们的主目录中。 具体来说,它们存储在 ~/.local/share/containers/storage/ 目录。

试试看!

满足所有先决条件后,您可以运行 podman run 从非用户的 shell 命令并启动一个容器。

由于我使用 球童服务器 对于我的 SSL,我将在本教程中使用它。 要使用 Podman 将 Caddy Server 作为无根容器运行,同时将其绑定到低于 1024 的端口,我将简单地运行以下命令:

$ whoami
pratham

$ podman run -d --name=prathams-caddy -p 80:80 -p 443:443 caddy:alpine
e6ed67eb90e6d0f3475d78b287af941bc873f6d62db60d5c13b1106af80dc5ff

$ podman ps
CONTAINER ID  IMAGE                           COMMAND               CREATED        STATUS            PORTS                                     NAMES
e6ed67eb90e6  docker.io/library/caddy:alpine  caddy run --confi...  2 seconds ago  Up 2 seconds ago  0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp  prathams-caddy

$ ps aux | grep caddy
pratham     3022  0.0  0.0  85672  2140 ?        Ssl  06:53   0:00 /usr/bin/conmon --api-version 1 -c e6ed67eb90e6d0f3475d78b287af941bc873f6d62db60d5c13b1106af80dc5ff [...]
pratham     3025  0.1  0.3 753060 32320 ?        Ssl  06:53   0:00 caddy run --config /etc/caddy/Caddyfile --adapter caddyfile

如您所见,用户 pratham 不是 root 而且我没有使用 sudo 提升用户权限的命令 pratham. 我能够使用 Podman 以无 root 权限运行 Caddy Server 容器。

的输出 ps 命令显示 PID 3022 属于进程拥有的 pratham 用户。 这个过程是 Caddy Server 容器(我已经修剪了输出)。 PID 3025 是PID的子进程 3022 这也是在 pratham 用户。

我没有解决你的问题吗?

如果我没有用无根 Podman 容器解决您的问题,我深表歉意。 由于 Podman 是新的(在软件年代),它会有一些意想不到的问题。

不要担心。 我在下面包含了官方的故障排除指南。 有疑问时请参考。 也是会经常更新的。

结论

在本文中,我将演示怎样开始使用 Podman 管理无根容器。 我谈论启用此功能的必要软件。 我将讨论您在使用无根 Podman 容器时可能遇到的常见问题以及怎样缓解这些问题。

我希望它对您有所帮助,如果您需要更多详细信息,请查看官方文档,您可能会在其中获得更多技术故障排除指南。