使用 OCI 工件为 seccomp、SELinux 和 AppArmor 分发安全配置文件

作者: Sascha Grunert

译者: Michael Yao (DaoCloud)

Security Profiles Operator (SPO) 使得在 Kubernetes 中管理 seccomp、SELinux 和 AppArmor 配置文件变得更加容易。 它允许集群管理员在预定义的自定义资源 YAML 中定义配置文件,然后由 SPO 分发到整个集群中。 安全配置文件的修改和移除也由 Operator 以同样的方式进行管理,但这只是其能力的一小部分。

SPO 的另一个核心特性是能够组合 seccomp 配置文件。这意味着用户可以在 YAML 规约中定义 baseProfileName,然后 Operator 会自动解析并组合系统调用规则。 如果基本配置文件有另一个 baseProfileName,那么 Operator 将以递归方式解析配置文件到一定深度。 常见的使用场景是为低级容器运行时(例如 runccrun)定义基本配置文件, 在这些配置文件中包含各种情况下运行容器所需的系统调用。另外,应用开发人员可以为其标准分发容器定义 seccomp 基本配置文件,并在其上组合针对应用逻辑的专用配置文件。 这样开发人员就可以专注于维护更简单且范围限制为应用逻辑的 seccomp 配置文件, 而不需要考虑整个基础设施的设置。

但是如何维护这些基本配置文件呢? 例如,运行时所需的系统调用数量可能会像主应用一样在其发布周期内发生变化。 基本配置文件必须在同一集群中可用,否则主 seccomp 配置文件将无法部署。 这意味着这些基本配置文件与主应用配置文件紧密耦合,因此违背了基本配置文件的核心理念。 将基本配置文件作为普通文件分发和管理感觉像是需要解决的额外负担。

OCI 工件成为救命良方

Security Profiles Operator 的 v0.8.0 版本支持将基本配置文件作为 OCI 工件进行管理!将 OCI 工件假想为轻量级容器镜像,采用与镜像相同的方式在各层中存储文件, 但没有要执行的进程。这些工件可以用于像普通容器镜像一样在兼容的镜像仓库中存储安全配置文件。 这意味着这些工件可以被版本化、作用于命名空间并类似常规容器镜像一样添加注解。

若要查看具体的工作方式,可以在 seccomp 配置文件 CRD 内以前缀 oci:// 指定 baseProfileName,例如:

apiVersion: security-profiles-operator.x-k8s.io/v1beta1
kind: SeccompProfile
metadata:
  name: test
spec:
  defaultAction: SCMP_ACT_ERRNO
  baseProfileName: oci://ghcr.io/security-profiles/runc:v1.1.5
  syscalls:
    - action: SCMP_ACT_ALLOW
      names:
        - uname

Operator 将负责使用 oras 拉取内容,并验证工件的 sigstore (cosign) 签名。 如果某些工件未经签名,则 SPO 将拒绝它们。随后生成的配置文件 test 将包含来自远程 runc 配置文件的所有基本系统调用加上额外允许的 uname 系统调用。 你还可以通过摘要(SHA256)来引用基本配置文件,使要被拉取的工件更为确定, 例如通过引用 oci://ghcr.io/security-profiles/runc@sha256: 380…

Operator 在内部缓存已拉取的工件,最多可缓存 1000 个配置文件 24 小时, 这意味着如果缓存已满、Operator 守护进程重启或超出给定时段后这些工件将被刷新。

因为总体生成的系统调用对用户不可见 (我只列出了 SeccompProfile 中的 baseProfileName,而没有列出系统调用本身), 所以我为该 SeccompProfile 的最终 syscalls 添加了额外的注解。

以下是我注解后的 SeccompProfile:

> kubectl describe seccompprofile test
Name:         test
Namespace:    security-profiles-operator
Labels:       spo.x-k8s.io/profile-id=SeccompProfile-test
Annotations:  syscalls:
                [{"names":["arch_prctl","brk","capget","capset","chdir","clone","close",...
API Version:  security-profiles-operator.x-k8s.io/v1beta1

SPO 维护者们作为 “Security Profiles” GitHub 组织 的成员提供所有公开的基本配置文件。

管理 OCI 安全配置文件

好的,官方的 SPO 提供了许多基本配置文件,但是我如何定义自己的配置文件呢? 首先,我们必须选择一个可用的镜像仓库。有许多镜像仓库都已支持 OCI 工件:

Security Profiles Operator 交付一个新的名为 spoc 的命令行界面, 这是一个用于管理 OCI 配置文件的小型辅助工具,该工具提供的各项能力不在这篇博文的讨论范围内。 但 spoc push 命令可以用于将安全配置文件推送到镜像仓库:

> export USERNAME=my-user
> export PASSWORD=my-pass
> spoc push -f ./examples/baseprofile-crun.yaml ghcr.io/security-profiles/crun:v1.8.3
16:35:43.899886 Pushing profile ./examples/baseprofile-crun.yaml to: ghcr.io/security-profiles/crun:v1.8.3
16:35:43.899939 Creating file store in: /tmp/push-3618165827
16:35:43.899947 Adding profile to store: ./examples/baseprofile-crun.yaml
16:35:43.900061 Packing files
16:35:43.900282 Verifying reference: ghcr.io/security-profiles/crun:v1.8.3
16:35:43.900310 Using tag: v1.8.3
16:35:43.900313 Creating repository for ghcr.io/security-profiles/crun
16:35:43.900319 Using username and password
16:35:43.900321 Copying profile to repository
16:35:46.976108 Signing container image
Generating ephemeral keys...
Retrieving signed certificate...

        Note that there may be personally identifiable information associated with this signed artifact.
        This may include the email address associated with the account with which you authenticate.
        This information will be used for signing this artifact and will be stored in public transparency logs and cannot be removed later.

By typing 'y', you attest that you grant (or have permission to grant) and agree to have this information stored permanently in transparency logs.
Your browser will now be opened to:
https://oauth2.sigstore.dev/auth/auth?access_type=…
Successfully verified SCT...
tlog entry created with index: 16520520
Pushing signature to: ghcr.io/security-profiles/crun

你可以看到该工具自动签署工件并将 ./examples/baseprofile-crun.yaml 推送到镜像仓库中, 然后直接可以在 SPO 中使用此文件。如果需要验证用户名和密码,则可以使用 --username-u 标志或导出 USERNAME 环境变量。要设置密码,可以导出 PASSWORD 环境变量。

采用 KEY:VALUE 的格式多次使用 --annotations / -a 标志, 可以为安全配置文件添加自定义注解。目前这些对安全配置文件没有影响, 但是在后续某个阶段,Operator 的其他特性可能会依赖于它们。

spoc 客户端还可以从兼容 OCI 工件的镜像仓库中拉取安全配置文件。 要执行此操作,只需运行 spoc pull

> spoc pull ghcr.io/security-profiles/runc:v1.1.5
16:32:29.795597 Pulling profile from: ghcr.io/security-profiles/runc:v1.1.5
16:32:29.795610 Verifying signature

Verification for ghcr.io/security-profiles/runc:v1.1.5 --
The following checks were performed on each of these signatures:
  - Existence of the claims in the transparency log was verified offline
  - The code-signing certificate was verified using trusted certificate authority certificates

[{"critical":{"identity":{"docker-reference":"ghcr.io/security-profiles/runc"},…}}]
16:32:33.208695 Creating file store in: /tmp/pull-3199397214
16:32:33.208713 Verifying reference: ghcr.io/security-profiles/runc:v1.1.5
16:32:33.208718 Creating repository for ghcr.io/security-profiles/runc
16:32:33.208742 Using tag: v1.1.5
16:32:33.208743 Copying profile from repository
16:32:34.119652 Reading profile
16:32:34.119677 Trying to unmarshal seccomp profile
16:32:34.120114 Got SeccompProfile: runc-v1.1.5
16:32:34.120119 Saving profile in: /tmp/profile.yaml

现在可以在 /tmp/profile.yaml--output-file / -o 所指定的输出文件中找到该配置文件。 我们可以像 spoc push 一样指定用户名和密码。

spoc 使得以 OCI 工件的形式管理安全配置文件变得非常容易,这些 OCI 工件可以由 Operator 本身直接使用。

本文简要介绍了通过 Security Profiles Operator 能够达成的各种最新可能性! 如果你有兴趣了解更多,无论是提出反馈还是寻求帮助, 请通过 Slack (#security-profiles-operator)邮件列表直接与我们联系。