在本系列中,我们介绍了各种安全层,这些安全层不仅可以将容器与主机上的其他进程隔离开来,还可以将容器与其底层主机隔离开来。在这篇文章中,我们将讨论容器运行时如何将 seccomp 过滤器用作“最后一道防线”。
Syscalls 和 seccomp 概述
Seccomp 过滤器是一种限制进程可以执行哪些 Linux 系统调用的方法。系统调用本质上是用户空间程序和 Linux 内核之间的接口。每当程序需要访问主机内核提供的服务时(例如,打开文件或创建新进程时),它都会使用系统调用来获取它。
Linux 提供了大量的系统调用,目前大概有 300 多个系统调用可用。需要注意的是,系统调用因底层硬件架构而异。比如你将在基于 ARM 的系统和 AMD64 系统之间的系统调用表中看到差异。
Seccomp 过滤器是编写的 Berkeley 数据包过滤器 (BPF) 程序,用于限制进程可以进行的系统调用,从而允许实施非常细粒度的限制。最广泛使用的例子是在容器中,用户通常以 root 身份运行,但需要阻止可能导致容器突破的危险系统调用。
Docker 容器中的 Seccomp 筛选器
作为 Docker 实施的默认限制集的一部分,seccomp 过滤器将应用于任何新容器。此过滤器可以捕获其他保护层(例如Capability)允许容器中的操作的情况。从历史上看,在一些情况下,Docker 的 seccomp 过滤器会阻止安全漏洞。一个例子是 CVE-2022-0185,它使用 unshare 系统调用来利用漏洞。此系统调用就会被 Docker 的 seccomp 过滤器阻止。
为了创建这种 seccomp 过滤,Docker 创建了一个调用允许列表,然后阻止了列表中未列出的任何系统调用。这意味着我们可以避免在 Linux 内核中添加新的危险系统调用(即可用于逃逸容器的系统调用)的风险。
让我们通过展示被阻止的系统调用的实用程序来说明 Docker 的 seccomp 过滤器的效果。在本例中,我们将使用 unshare ,它在主机上创建新的命名空间。
首先,我们将使用 docker run -it ubuntu:22.04 /bin/bash 命令运行一个标准的 Docker 容器并执行 unshare。由于seccomp 过滤器,这会导致“操作不被允许”。
接下来,我们在禁用 seccomp 过滤器的情况下执行 docker run --security-opt seccomp=unconfined -it ubuntu:22.04 /bin/bash 启动一个容器。如果我们再次尝试运行相同的命令,我们可以看到它成功了。
创建自定义 seccomp 筛选器
尽管 Docker 默认的 seccomp 配置文件提供了良好的隔离策略,但在某些情况下,需要更加个性化的限制。在这些情况下,您将需要一个自定义 seccomp 配置文件。
对于 Docker,您可以指定 JSON 格式的 seccomp 配置文件。例如,如果您想要一个空白的 seccomp 配置文件来阻止所有系统调用,则它看起来像这样:
代码语言:txt复制{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": [
"SCMP_ARCH_X86_64",
"SCMP_ARCH_X86",
"SCMP_ARCH_X32"
],
"syscalls": [
]
}
defaultAction 代表了当系统调用与策略的任何部分不匹配时将执行的操作。在本例中,其动作为 SCMP_ACT_ERRNO,这意味着将返回错误并拒绝调用。
当然,这个策略肯定是不可用的,这会影响到容器的正常使用,因为所有容器都需要进行系统调用。一个更实际的例子可能是阻止 Docker 通常允许的某些功能集。例如,您可能希望阻止 io_uring 系统调用集,因为它们在过去几年中涉及大量内核漏洞。
在这里,最好的方法是从 Docker 的默认 seccomp 策略开始,然后删除相关的系统调用。在本例中,该策略包括三个io_uring相关的系统调用:
代码语言:javascript复制"io_uring_enter","io_uring_register","io_uring_setup",
我们需要做的就是删除这些条目,将配置文件另存为新文件,并在启动时将其提供给我们的 Docker 容器。
要提供自定义 seccomp 配置文件,只需将配置文件的名称作为参数传递给 docker run 命令即可。因此,例如,如果您有一个名为 no_io_uring.json 的配置文件,则可以将其应用于新容器,如下所示:
代码语言:javascript复制docker run -it --security-opt seccomp=no_io_uring.json ubuntu:22.04 /bin/bash
生成自定义 seccomp 配置文件的另一个选项是审核应用程序生成的系统调用,然后使用此审核日志创建仅允许这些系统调用的自定义配置文件。像 Inspektor Gadget 这样的工具可以帮助自动化这个过程。
结论
Seccomp 过滤器为希望阻止对特定系统调用的访问的容器和其他 Linux 进程提供了细粒度的“最后一道防线”。它是 Docker 容器安全性的有用补充,在阻止一些可能允许容器突破的漏洞方面发挥了重要作用。我们还了解了创建自定义 seccomp 过滤器如何有助于在不中断业务的情况下为容器增添另一层安全防护。
通过本系列文章,我们可以了解,虽然 Docker 容器的安全模型感觉有点像一个封闭的盒子,但它实际上是一系列可以使用的标准 Linux 工具的集合。