Podman:一个更安全的运行容器的方式

Podman:一个更安全的运行容器的方式

Podman 使用传统的 fork/exec 模型(相对于客户端/服务器模型)来运行容器。

在进入本文的主要主题 Podman 和容器之前,我需要了解一点 Linux 审计功能的技术。

什么是审计?

Linux 内核有一个有趣的安全功能,叫做审计。它允许管理员在系统上监视安全事件,并将它们记录到audit.log 中,该文件可以本地存储或远程存储在另一台机器上,以防止黑客试图掩盖他的踪迹。

/etc/shadow 文件是一个经常要监控的安全文件,因为向其添加记录可能允许攻击者获得对系统的访问权限。管理员想知道是否有任何进程修改了该文件,你可以通过执行以下命令来执行此操作:

  1. <span class="com">#</span><span class="pln"> auditctl </span><span class="pun">-</span><span class="kwd">w</span><span class="pln"> </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">shadow</span>

现在让我们看看当我修改了 /etc/shadow 文件会发生什么:

  1. <span class="com">#</span><span class="pln"> </span><span class="kwd">touch</span><span class="pln"> </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">shadow </span>
  2. <span class="com">#</span><span class="pln"> ausearch </span><span class="pun">-</span><span class="pln">f </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">shadow </span><span class="pun">-</span><span class="pln">i </span><span class="pun">-</span><span class="pln">ts recent</span>
  3.  
  4. <span class="pln">type</span><span class="pun">=</span><span class="pln">PROCTITLE msg</span><span class="pun">=</span><span class="pln">audit</span><span class="pun">(</span><span class="lit">10</span><span class="pun">/</span><span class="lit">10</span><span class="pun">/</span><span class="lit">2018</span><span class="pln"> </span><span class="lit">09</span><span class="pun">:</span><span class="lit">46</span><span class="pun">:</span><span class="lit">03.042</span><span class="pun">:</span><span class="lit">4108</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> proctitle</span><span class="pun">=</span><span class="kwd">touch</span><span class="pln"> </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">shadow type</span><span class="pun">=</span><span class="pln">SYSCALL msg</span><span class="pun">=</span><span class="pln">audit</span><span class="pun">(</span><span class="lit">10</span><span class="pun">/</span><span class="lit">10</span><span class="pun">/</span><span class="lit">2018</span><span class="pln"> </span><span class="lit">09</span><span class="pun">:</span><span class="lit">46</span><span class="pun">:</span><span class="lit">03.042</span><span class="pun">:</span><span class="lit">4108</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> arch</span><span class="pun">=</span><span class="pln">x86_64 syscall</span><span class="pun">=</span><span class="pln">openat success</span><span class="pun">=</span><span class="kwd">yes</span><span class="pln"> </span><span class="kwd">exit</span><span class="pun">=</span><span class="lit">3</span><span class="pln"> a0</span><span class="pun">=</span><span class="lit">0xffffff9c</span><span class="pln"> a1</span><span class="pun">=</span><span class="lit">0x7ffdb17f6704</span><span class="pln"> a2</span><span class="pun">=</span><span class="pln">O_WRONLY</span><span class="pun">|</span><span class="pln">O_CREAT</span><span class="pun">|</span><span class="pln">O_NOCTTY</span><span class="pun">|</span><span class="pln"> O_NONBLOCK a3</span><span class="pun">=</span><span class="lit">0x1b6</span><span class="pln"> items</span><span class="pun">=</span><span class="lit">2</span><span class="pln"> ppid</span><span class="pun">=</span><span class="lit">2712</span><span class="pln"> pid</span><span class="pun">=</span><span class="lit">3727</span><span class="pln"> auid</span><span class="pun">=</span><span class="pln">dwalsh uid</span><span class="pun">=</span><span class="pln">root gid</span><span class="pun">=</span><span class="pln">root euid</span><span class="pun">=</span><span class="pln">root suid</span><span class="pun">=</span><span class="pln">root fsuid</span><span class="pun">=</span><span class="pln">root egid</span><span class="pun">=</span><span class="pln">root sgid</span><span class="pun">=</span><span class="pln">root fsgid</span><span class="pun">=</span><span class="pln">root </span><span class="kwd">tty</span><span class="pun">=</span><span class="pln">pts1 ses</span><span class="pun">=</span><span class="lit">3</span><span class="pln"> comm</span><span class="pun">=</span><span class="kwd">touch</span><span class="pln"> exe</span><span class="pun">=</span><span class="str">/usr/</span><span class="pln">bin</span><span class="pun">/</span><span class="kwd">touch</span><span class="pln"> subj</span><span class="pun">=</span><span class="pln">unconfined_u</span><span class="pun">:</span><span class="pln">unconfined_r</span><span class="pun">:</span><span class="typ">unconfined_t</span><span class="pun">:</span><span class="pln">s0</span><span class="pun">-</span><span class="pln">s0</span><span class="pun">:</span><span class="pln">c0</span><span class="pun">.</span><span class="pln">c1023 key</span><span class="pun">=(</span><span class="kwd">null</span><span class="pun">)</span><span class="str">`</span>

审计记录中有很多信息,但我重点注意到它记录了 root 修改了 /etc/shadow 文件,并且该进程的审计 UID(auid)的所有者是 dwalsh

内核修改了这个文件了么?

跟踪登录 UID

登录 UID(loginuid),存储在 /proc/self/loginuid 中,它是系统上每个进程的 proc 结构的一部分。该字段只能设置一次;设置后,内核将不允许任何进程重置它。

当我登录系统时,登录程序会为我的登录过程设置 loginuid 字段。

我(dwalsh)的 UID 是 3267。

  1. <span class="pln">$ </span><span class="kwd">cat</span><span class="pln"> </span><span class="pun">/</span><span class="pln">proc</span><span class="pun">/</span><span class="kwd">self</span><span class="pun">/</span><span class="pln">loginuid</span>
  2. <span class="lit">3267</span>

现在,即使我变成了 root,我的登录 UID 仍将保持不变。

  1. <span class="pln">$ </span><span class="kwd">sudo</span><span class="pln"> </span><span class="kwd">cat</span><span class="pln"> </span><span class="pun">/</span><span class="pln">proc</span><span class="pun">/</span><span class="kwd">self</span><span class="pun">/</span><span class="pln">loginuid</span>
  2. <span class="lit">3267</span>

请注意,从初始登录过程 fork 并 exec 的每个进程都会自动继承 loginuid。这就是内核知道登录的人是 dwalsh 的方式。

容器

现在让我们来看看容器。

  1. <span class="kwd">sudo</span><span class="pln"> podman run fedora </span><span class="kwd">cat</span><span class="pln"> </span><span class="pun">/</span><span class="pln">proc</span><span class="pun">/</span><span class="kwd">self</span><span class="pun">/</span><span class="pln">loginuid</span>
  2. <span class="lit">3267</span>

甚至容器进程也保留了我的 loginuid。 现在让我们用 Docker 试试。

  1. <span class="kwd">sudo</span><span class="pln"> docker run fedora </span><span class="kwd">cat</span><span class="pln"> </span><span class="pun">/</span><span class="pln">proc</span><span class="pun">/</span><span class="kwd">self</span><span class="pun">/</span><span class="pln">loginuid </span>
  2. <span class="lit">4294967295</span>

为什么不一样?

Podman 对于容器使用传统的 fork/exec 模型,因此容器进程是 Podman 进程的后代。Docker 使用客户端/服务器模型。我执行的 docker 命令是 Docker 客户端工具,它通过客户端/服务器操作与 Docker 守护进程通信。然后 Docker 守护程序创建容器并处理 stdin/stdout 与 Docker 客户端工具的通信。

进程的默认 loginuid(在设置 loginuid 之前)是 4294967295(LCTT 译注:232 - 1)。由于容器是 Docker 守护程序的后代,而 Docker 守护程序是 init 系统的子代,所以,我们看到 systemd、Docker 守护程序和容器进程全部具有相同的 loginuid4294967295,审计系统视其为未设置审计 UID。

  1. <span class="kwd">cat</span><span class="pln"> </span><span class="pun">/</span><span class="pln">proc</span><span class="pun">/</span><span class="lit">1</span><span class="pun">/</span><span class="pln">loginuid </span>
  2. <span class="lit">4294967295</span>

怎么会被滥用?

让我们来看看如果 Docker 启动的容器进程修改 /etc/shadow 文件会发生什么。

  1. <span class="pln">$ </span><span class="kwd">sudo</span><span class="pln"> docker run </span><span class="pun">--</span><span class="pln">privileged </span><span class="pun">-</span><span class="pln">v </span><span class="pun">/:</span><span class="str">/host fedora touch /</span><span class="pln">host</span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">shadow </span>
  2. <span class="pln">$ </span><span class="kwd">sudo</span><span class="pln"> ausearch </span><span class="pun">-</span><span class="pln">f </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">shadow </span><span class="pun">-</span><span class="pln">i type</span><span class="pun">=</span><span class="pln">PROCTITLE msg</span><span class="pun">=</span><span class="pln">audit</span><span class="pun">(</span><span class="lit">10</span><span class="pun">/</span><span class="lit">10</span><span class="pun">/</span><span class="lit">2018</span><span class="pln"> </span><span class="lit">10</span><span class="pun">:</span><span class="lit">27</span><span class="pun">:</span><span class="lit">20.055</span><span class="pun">:</span><span class="lit">4569</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> proctitle</span><span class="pun">=</span><span class="str">/usr/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">coreutils </span><span class="pun">--</span><span class="pln">coreutils</span><span class="pun">-</span><span class="pln">prog</span><span class="pun">-</span><span class="pln">shebang</span><span class="pun">=</span><span class="kwd">touch</span><span class="pln"> </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="kwd">touch</span><span class="pln"> </span><span class="pun">/</span><span class="pln">host</span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">shadow type</span><span class="pun">=</span><span class="pln">SYSCALL msg</span><span class="pun">=</span><span class="pln">audit</span><span class="pun">(</span><span class="lit">10</span><span class="pun">/</span><span class="lit">10</span><span class="pun">/</span><span class="lit">2018</span><span class="pln"> </span><span class="lit">10</span><span class="pun">:</span><span class="lit">27</span><span class="pun">:</span><span class="lit">20.055</span><span class="pun">:</span><span class="lit">4569</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> arch</span><span class="pun">=</span><span class="pln">x86_64 syscall</span><span class="pun">=</span><span class="pln">openat success</span><span class="pun">=</span><span class="kwd">yes</span><span class="pln"> </span><span class="kwd">exit</span><span class="pun">=</span><span class="lit">3</span><span class="pln"> a0</span><span class="pun">=</span><span class="lit">0xffffff9c</span><span class="pln"> a1</span><span class="pun">=</span><span class="lit">0x7ffdb6973f50</span><span class="pln"> a2</span><span class="pun">=</span><span class="pln">O_WRONLY</span><span class="pun">|</span><span class="pln">O_CREAT</span><span class="pun">|</span><span class="pln">O_NOCTTY</span><span class="pun">|</span><span class="pln"> O_NONBLOCK a3</span><span class="pun">=</span><span class="lit">0x1b6</span><span class="pln"> items</span><span class="pun">=</span><span class="lit">2</span><span class="pln"> ppid</span><span class="pun">=</span><span class="lit">11863</span><span class="pln"> pid</span><span class="pun">=</span><span class="lit">11882</span><span class="pln"> auid</span><span class="pun">=</span><span class="kwd">unset</span><span class="pln"> uid</span><span class="pun">=</span><span class="pln">root gid</span><span class="pun">=</span><span class="pln">root euid</span><span class="pun">=</span><span class="pln">root suid</span><span class="pun">=</span><span class="pln">root fsuid</span><span class="pun">=</span><span class="pln">root egid</span><span class="pun">=</span><span class="pln">root sgid</span><span class="pun">=</span><span class="pln">root fsgid</span><span class="pun">=</span><span class="pln">root </span><span class="kwd">tty</span><span class="pun">=(</span><span class="pln">none</span><span class="pun">)</span><span class="pln"> ses</span><span class="pun">=</span><span class="kwd">unset</span><span class="pln"> comm</span><span class="pun">=</span><span class="kwd">touch</span><span class="pln"> exe</span><span class="pun">=</span><span class="str">/usr/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">coreutils subj</span><span class="pun">=</span><span class="pln">system_u</span><span class="pun">:</span><span class="pln">system_r</span><span class="pun">:</span><span class="typ">spc_t</span><span class="pun">:</span><span class="pln">s0 key</span><span class="pun">=(</span><span class="kwd">null</span><span class="pun">)</span>

在 Docker 情形中,auid 是未设置的(4294967295);这意味着安全人员可能知道有进程修改了 /etc/shadow 文件但身份丢失了。

如果该攻击者随后删除了 Docker 容器,那么在系统上谁修改 /etc/shadow 文件将没有任何跟踪信息。

现在让我们看看相同的场景在 Podman 下的情况。

  1. <span class="pln">$ </span><span class="kwd">sudo</span><span class="pln"> podman run </span><span class="pun">--</span><span class="pln">privileged </span><span class="pun">-</span><span class="pln">v </span><span class="pun">/:</span><span class="str">/host fedora touch /</span><span class="pln">host</span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">shadow </span>
  2. <span class="pln">$ </span><span class="kwd">sudo</span><span class="pln"> ausearch </span><span class="pun">-</span><span class="pln">f </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">shadow </span><span class="pun">-</span><span class="pln">i type</span><span class="pun">=</span><span class="pln">PROCTITLE msg</span><span class="pun">=</span><span class="pln">audit</span><span class="pun">(</span><span class="lit">10</span><span class="pun">/</span><span class="lit">10</span><span class="pun">/</span><span class="lit">2018</span><span class="pln"> </span><span class="lit">10</span><span class="pun">:</span><span class="lit">23</span><span class="pun">:</span><span class="lit">41.659</span><span class="pun">:</span><span class="lit">4530</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> proctitle</span><span class="pun">=</span><span class="str">/usr/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">coreutils </span><span class="pun">--</span><span class="pln">coreutils</span><span class="pun">-</span><span class="pln">prog</span><span class="pun">-</span><span class="pln">shebang</span><span class="pun">=</span><span class="kwd">touch</span><span class="pln"> </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="kwd">touch</span><span class="pln"> </span><span class="pun">/</span><span class="pln">host</span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">shadow type</span><span class="pun">=</span><span class="pln">SYSCALL msg</span><span class="pun">=</span><span class="pln">audit</span><span class="pun">(</span><span class="lit">10</span><span class="pun">/</span><span class="lit">10</span><span class="pun">/</span><span class="lit">2018</span><span class="pln"> </span><span class="lit">10</span><span class="pun">:</span><span class="lit">23</span><span class="pun">:</span><span class="lit">41.659</span><span class="pun">:</span><span class="lit">4530</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> arch</span><span class="pun">=</span><span class="pln">x86_64 syscall</span><span class="pun">=</span><span class="pln">openat success</span><span class="pun">=</span><span class="kwd">yes</span><span class="pln"> </span><span class="kwd">exit</span><span class="pun">=</span><span class="lit">3</span><span class="pln"> a0</span><span class="pun">=</span><span class="lit">0xffffff9c</span><span class="pln"> a1</span><span class="pun">=</span><span class="lit">0x7fffdffd0f34</span><span class="pln"> a2</span><span class="pun">=</span><span class="pln">O_WRONLY</span><span class="pun">|</span><span class="pln">O_CREAT</span><span class="pun">|</span><span class="pln">O_NOCTTY</span><span class="pun">|</span><span class="pln"> O_NONBLOCK a3</span><span class="pun">=</span><span class="lit">0x1b6</span><span class="pln"> items</span><span class="pun">=</span><span class="lit">2</span><span class="pln"> ppid</span><span class="pun">=</span><span class="lit">11671</span><span class="pln"> pid</span><span class="pun">=</span><span class="lit">11683</span><span class="pln"> auid</span><span class="pun">=</span><span class="pln">dwalsh uid</span><span class="pun">=</span><span class="pln">root gid</span><span class="pun">=</span><span class="pln">root euid</span><span class="pun">=</span><span class="pln">root suid</span><span class="pun">=</span><span class="pln">root fsuid</span><span class="pun">=</span><span class="pln">root egid</span><span class="pun">=</span><span class="pln">root sgid</span><span class="pun">=</span><span class="pln">root fsgid</span><span class="pun">=</span><span class="pln">root </span><span class="kwd">tty</span><span class="pun">=(</span><span class="pln">none</span><span class="pun">)</span><span class="pln"> ses</span><span class="pun">=</span><span class="lit">3</span><span class="pln"> comm</span><span class="pun">=</span><span class="kwd">touch</span><span class="pln"> exe</span><span class="pun">=</span><span class="str">/usr/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">coreutils subj</span><span class="pun">=</span><span class="pln">unconfined_u</span><span class="pun">:</span><span class="pln">system_r</span><span class="pun">:</span><span class="typ">spc_t</span><span class="pun">:</span><span class="pln">s0 key</span><span class="pun">=(</span><span class="kwd">null</span><span class="pun">)</span>

由于它使用传统的 fork/exec 方式,因此 Podman 正确记录了所有内容。

这只是观察 /etc/shadow 文件的一个简单示例,但审计系统对于观察系统上的进程非常有用。使用 fork/exec 容器运行时(而不是客户端/服务器容器运行时)来启动容器允许你通过审计日志记录保持更好的安全性。

最后的想法