为什么 Podman 比 Docker 更安全(一)

admin 2025年1月9日15:18:29评论12 views字数 3804阅读12分40秒阅读模式

0x00 前言

今天,我们将从日志审计的角度探讨:为什么 Podman 比 Docker 更安全?

  1. 首先,我们需要了解 Linux 的 audit 日志审计功能和 loginuid 的基础知识;
  2. 然后,我们将分别使用 Podman 和 Docker 启动容器,分析容器中 loginuid 的变化及其原因;
  3. 最后,我们将通过真实攻击场景,展示 loginuid 的变化如何影响安全防护;

本文所有的验证都在 ubuntu 22.04 之上进行,且登录用户为 yaney

为什么 Podman 比 Docker 更安全(一)
图1:操作环境

0x01 Linux 的基础知识

unsetunset1.1 audit 审计功能unsetunset

在讨论 Podman[1] 和 Docker 的安全性之前,我们需要了解一些关于 Linux audit 审计功能的基础知识。

Linux 内核有一个名为 audit 的安全功能,管理员可以通过该功能监视系统上的安全事件,并记录在本地的 audit.log 文件中。此外,audit 日志还可以远程存储在其他主机上,以防攻击者试图掩盖其入侵的痕迹。

我们以审计 /etc/shadow 文件上的操作为例进行说明。/etc/shadow 文件是一个常见的安全文件,攻击者可以向其中增加记录,从而重新获得系统的访问权限。

为什么 Podman 比 Docker 更安全(一)
图2: 通过 audit 审计 /etc/shadow,并对 /etc/shadow 进行操作
  1. 如上图所示,左边图我们安装了 auditd 软件包,并通过 auditctl 写入规则,开始审计 /etc/shadow 文件。

    sudo auditctl -w /etc/shadow
  2. 右边的图,我们切换到 root 用户身份,并通过下面命令,对目标文件进行操作。

    cat /etc/shadow
  3. 最后,我们使用 audit 所提供的工具 ausearch 来搜索近期与 /etc/shadow 文件相关的事件。

    ausearch -f /etc/shadow -i -ts recent

一会儿时间,audit 就记录了许多信息,我们不需要去解读这些信息,只需关注一个问题,那就是:为什么 audit 能够正确地记录是 root 用户(uid=root)查看了/etc/shadow文件,但该进程的原始登录用户(auid=yaney)是 yaney 呢?

为什么 Podman 比 Docker 更安全(一)
图 3:audit 可以正确记录原始登录用户是 yaney

unsetunset1.2 loginuidunsetunset

要回答这个问题,我们不得不了解 Linux 内核有个名为loginuid的属性了。

loginuid存储在虚拟文件系统/proc/self/loginuid 中,用来标识登录的用户。每当我们登录系统时,loginuid就被设置为用户的 ID(UID),且内核不允许任何进程对他进行修改。

最重要的是,从该登录进程派生出来的所有子进程都会继承这个 loginuid,并形成一条“跟踪链”,这使得系统能够追踪到当前活动是由哪个登录用户发起的。例如:当我以 yaney 的身份进入系统时,loginuid 的编号为 1000;当我切换用户至 root 时,loginuid的编号还是 1000。

为什么 Podman 比 Docker 更安全(一)

图 4: 由登录进程派生出来的子进程会继续继承 loginuid

0x02 Podman 和 Docker 容器中的 loginuid 差异

众所周知,容器只是宿主机中一个特殊的进程,那么容器中的loginuid又是怎样的呢?

我们分别用 Podman 和 Docker 启动容器,发现:Podman 的容器正确记录了我们的loginuid,而 Docker 的容器记录的却4294967295docker 所记录的这个数字并不是一个随机的数字,我们后面再说。

为什么 Podman 比 Docker 更安全(一)

图 5:docker 容器和 podman 容器中的 loginuid 不一致

那么,造成这种差异的原因又是什么呢?

Podman 使用的是传统的 fork/exec 模型,即 Podman 调用 fork 系统调用来创建一个子进程,这个子进程几乎完全复制了父进程的状态,与父进程共享相同的内存内容。子进程创建后,再调用 exec 或 execve 来替换自己的代码和数据。因此 Podman 容器进程是 Podman 的后代,podman 容器中的loginuid与宿主机上的loginuid完全一致。

而 Docker 使用的是 C/S 模型当我们执行 docker 命令时,本质上是 Docker 客户端工具(docker cli)向 Docker 守护进程(dockerd)发送请求,dockerd 来处理与 docker cli 的 stdin/stdout 通信并创建容器。所以 Docker 容器是 dockerd 的后代,需要与守护进程的loginuid 一致。

前面我们说了 Docker 容器的 loginuid 并不是一个随机数,那是因为 dockerd 是初始化系统的子进程,它的 loginuid 是未经过设置的默认值,具体为 32 位无符号整数的最大值0xFFFFFFFF,即十进制的4294967295。这种情况,audit 一般会将 auid 设置为 unset 表示该进程无法关联到登录用户。

我们可以查看 dockerd 或 systemd 的loginuid来进行验证。如图所示,dockerd 和 systemd 的 loginuid 都是默认值4294967295

  1. 查看 dockerd 和 systemd 的进程 ID(systemd 的进程 ID 一般为 1)。

    ps -eo pid,uid,comm | egrep 'dockerd|systemd'
  2. 查看 dockerd 和 systemd 的 loginuid。

    cat /proc/[pid]/loginuid
为什么 Podman 比 Docker 更安全(一)
图6: dockerd 和 systemd 的 loginuid 为默认值

0x03 攻击案例:从容器中修改宿主机文件

那么,如果我们通过启动 Podman 容器和 Docker 容器来修改宿主机的 /etc/shadow 文件,audit 记录下来的日志又有什么区别呢?我们先来看看 Docker 容器的。

  1. 启动一个可交互的临时的特权容器,并将宿主机的根目录挂在到容器的 /host 目录中。

    sudo docker run -it --rm --privileged -v /:/host alpine sh
  2. 向宿主机的 /etc/shadow 文件写入数据。

    echo'docker,miao~' | tee -a /host/etc/shadow > /dev/null
  3. 使用 audit 所提供的工具 ausearch 来搜索近期与 /etc/shadow 文件相关的事件。

    ausearch -f /etc/shadow -i -ts recent

如下图所示,audit 可以记录 /etc/shadow 文件被修改了,但是不知道是谁修改的(auid=unset)。在真实的业务环境中,如果攻击者随后删除了这个 Docker 容器,那么我们根本无法从海量的数据中准确找到修改 /etc/shadow 文件的痕迹

为什么 Podman 比 Docker 更安全(一)
图7: docker 容器修改宿主机的 /etc/shadow 文件

接下来,我们来看看相同场景下,Podman 的表现如何。Podman 由于使用传统的 fork/exec 模型,因此可以正确记录所有内容。

为什么 Podman 比 Docker 更安全(一)

图8:podman 容器修改宿主机的 /etc/shadow 文件

最后我们看到 /etc/shadow 都被写入了恶意数据。虽然这只是关于/etc/shadow 文件的一个简单的操作,但有的安全产品底层会使用 audit 来分析进程上的恶意行为,所以为了保持更好的安全性,我们推荐使用基于 fork/exec 启动容器的运行时而不是基于 C/S 启动容器的运行时。

为什么 Podman 比 Docker 更安全(一)
图 9:podman 容器和 docker 容器都往宿主机写入恶意数据

0x04 总结

本文,我们从日志审计的角度解释为什么 Podman 比 Docker 更安全:

  • Podman 使用传统的 fork/exec 模型容器进程正确继承父进程的 loginuid,使系统能追踪到操作的发起用户;
  • 而 Docker 使用 C/S 模型容器进程继承 Docker 守护进程(dockerd)的 loginuid(值为 4294967295),因此无法追踪具体的操作用户。

在实际攻击场景中,攻击者通过 Docker 容器修改宿主机的关键文件时,audit 日志无法记录操作者身份。相比之下,Podman 容器的所有操作都能被 audit 准确记录,有利于后续的安全审计和追踪。

除了日志审计的优势,Podman 还具有以下安全特性:

  • 无需 root 权限即可运行容器,避免了守护进程可能带来的安全风险
    • Docker 这类采用 C/S 模型的运行时需要用户以 root 权限运行守护进程并打开套接字来启动容器。这导致我们只能依赖守护进程实现的安全机制,若守护进程存在安全漏洞,攻击者就可能直接影响主机操作系统的安全性。
  • 支持 systemd 的 SD_NOTIFY 功能和套接字激活功能,提供更安全高效的服务管理方式
    • 当我们将 podman 命令放入 systemd unit 文件中,容器进程可通过 Podman 向 systemd 发送通知,表明容器已就绪并可接受外部请求。SD_NOTIFY功能提高了服务启动效率,避免竞态条件,实现更精确的服务管理。
    • 此外,我们可以将连接套接字从 systemd 传递到 Podman,再传递到容器进程。这样容器无需独立处理网络连接,只需通过 systemd 就能直接响应外部网络请求,减少了额外配置。
参考资料
[1] 

Podman: https://podman.io/

原文始发于微信公众号(喵苗安全):为什么 Podman 比 Docker 更安全(一)

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月9日15:18:29
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   为什么 Podman 比 Docker 更安全(一)http://cn-sec.com/archives/3610597.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息