满足 Pod Security Restricted 安全规范

目录

功能概述

pod-security.kubernetes.io/enforce=restricted 标准是最严格的 Pod Security Standard,强制执行当前 Pod 加固的最佳实践。当命名空间被标记为该标准时,该命名空间中创建的所有 Pod 必须符合严格的安全要求。

本指南说明如何配置 Tekton Pipelines 以满足 restricted 安全标准,确保您 Tasks 中的所有容器都能在受限命名空间中成功运行。

使用场景

  • 在带有 pod-security.kubernetes.io/enforce=restricted 标签的命名空间中运行 Tekton Pipelines
  • 满足组织的安全合规性要求
  • 提升 CI/CD 流水线的安全防护能力
  • 在高度受监管的环境中运行工作负载

前提条件

  • 通过 TektonPipelineTektonConfig CR 安装了 Tekton Pipelines
  • 您有权限修改 TektonPipelineTektonConfig 资源
  • 您可以创建或编辑 Task 定义
  • 对于自定义镜像,您可以修改 Dockerfile 并重新构建镜像

理解 Restricted 标准

pod-security.kubernetes.io/enforce=restricted 标准要求 Pod 中的三类容器均满足以下安全上下文配置:

  • 普通容器 (containers)
  • 初始化容器 (initContainers)
  • 临时容器 (ephemeralContainers)

每个容器必须具有如下安全上下文配置:

securityContext:
  allowPrivilegeEscalation: false
  runAsNonRoot: true
  capabilities:
    drop:
      - "ALL"
  seccompProfile:
    type: RuntimeDefault

配置说明:

字段作用影响
allowPrivilegeEscalationfalse防止进程获得比其父进程更多的权限阻止恶意代码通过 setuid 二进制文件或文件能力提升权限
runAsNonRoottrue要求容器以非 root 用户身份运行(UID ≠ 0)防止容器以 root 身份运行,降低容器逃逸漏洞的影响
capabilities.drop["ALL"]从容器中移除所有 Linux 能力限制容器执行特权操作的能力(如网络配置、加载内核模块等)
seccompProfile.typeRuntimeDefault应用容器运行时的默认 seccomp 配置限制容器可调用的系统调用,减少内核攻击面

操作步骤

1. 配置 Tekton 为初始化容器添加安全上下文

Tekton 会为其管理的每个 Pod 创建初始化容器。为符合 restricted 标准,您需要启用 Tekton 自动为这些初始化容器添加所需的安全上下文。

方案 A:通过 TektonPipeline 配置

如果您通过 TektonPipeline CR 直接管理 Tekton

apiVersion: operator.tekton.dev/v1alpha1
kind: TektonPipeline
spec:
  set-security-context: true

应用配置:

$ kubectl patch tektonpipeline tektonpipeline \
  --type merge \
  -p '{"spec":{"set-security-context":true}}'

tektonpipeline.operator.tekton.dev/tektonpipeline patched

方案 B:通过 TektonConfig 配置

如果您通过 TektonConfig CR 管理 Tekton

apiVersion: operator.tekton.dev/v1alpha1
kind: TektonConfig
spec:
  pipeline:
    set-security-context: true

应用配置:

$ kubectl patch tektonconfig config \
  --type merge \
  -p '{"spec":{"pipeline":{"set-security-context":true}}}'

tektonconfig.operator.tekton.dev/config patched

注意: 此配置更改立即生效,无需重启 Tekton 控制器。更改后创建的新 TaskRunsPipelineRuns 会自动为初始化容器应用所需的安全上下文。

2. 为自定义 Task 定义添加安全上下文

对于自定义 Tasks(非平台内置 Tasks),您需要显式为每个步骤添加安全上下文。

示例带安全上下文的 Task

apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: custom-build-task
spec:
  steps:
    - name: build
      image: registry.example.com/builder:latest
      securityContext:
        allowPrivilegeEscalation: false
        runAsNonRoot: true
        capabilities:
          drop:
            - "ALL"
        seccompProfile:
          type: RuntimeDefault
      script: |
        #!/bin/sh
        echo "Building application..."

重要提示: 此步骤适用于自定义 Tasks。平台提供的内置 Tasks(除 buildah,详见故障排除部分)兼容这些安全约束,但其 Task 定义中未包含显式的 securityContext 配置,因为它们设计为可在多种安全上下文中运行,而不仅限于受限模式。

3. 配置容器镜像使用非 root 用户

容器镜像必须配置为以非 root 用户运行,且用户需使用数字 UID 指定,而非用户名。

在您的 Dockerfile 中添加非 root 用户并设置为默认用户。以下是基于 Alpine 镜像的示例:

# 添加 UID 为 65532 的非 root 用户(Alpine 语法)
RUN adduser -u 65532 -h /home/nonroot -D nonroot

# 设置工作目录权限
RUN chown -R 65532:65532 /app

# 切换到非 root 用户(使用数字 UID)
USER 65532

注意: adduser 命令语法因基础镜像不同而异。请参阅下方参考文档了解其他基础镜像的示例。

验证镜像配置:

# 检查镜像是否以非 root 用户运行
$ podman run -it --rm ${registry} id

uid=65532(nonroot) gid=65532(nonroot) groups=65532(nonroot)

有关调整 Dockerfile 的详细指导,请参阅 Adjust Dockerfile for Building Task-Compatible Custom Images

操作结果

完成上述步骤后:

  1. 初始化容器Tekton 创建的初始化容器将自动符合 restricted 标准
  2. 自定义 Tasks:您的自定义 Task 步骤将具备所需的安全上下文
  3. 容器镜像:镜像将以非 root 用户且权限最小化的方式运行

您可以通过在受限命名空间中创建 TaskRun 来验证合规性:

# 为命名空间添加 restricted 标准标签
$ kubectl label namespace test-ns pod-security.kubernetes.io/enforce=restricted

namespace/test-ns labeled

# 在受限命名空间中创建 TaskRun
$ kubectl -n test-ns create -f taskrun.yaml

taskrun.tekton.dev/example-taskrun created

# 验证 TaskRun 是否成功
$ kubectl -n test-ns get taskrun

NAME               SUCCEEDED   REASON      STARTTIME   COMPLETIONTIME
example-taskrun    True        Succeeded   2m ago      1m ago

成功的 TaskRun 显示 SUCCEEDEDTrueREASONSucceeded,表明所有容器均已成功运行且满足所需安全约束。

使用策略执行工具

为了更自动化,您可以使用如 Kyverno 之类的策略执行工具,自动向所有容器注入所需的安全上下文。通过创建 Kyverno Policy(使用 apiVersion: kyverno.io/v1kind: Policy),可以自动变更 Pods,添加必要的安全上下文配置。

更多信息请参见 Scenario 4: Specified Namespace Security Context Enforcement

此方法免去了为每个 Task 手动配置安全上下文的繁琐,简化了合规管理。

关于配置 Kyverno 策略的详细指导,请参考:

故障排除

内置 Tasks 与 Restricted 标准

平台提供的内置 Tasks 中,只有 buildah Task 无法在 restricted 标准下运行。原因是 buildah 需要提升权限以构建容器镜像。

buildah Task 需要如下安全上下文:

securityContext:
  # allowPrivilegeEscalation: false  # 不能设置为 false —— buildah 需要提升权限以使用 SETFCAP 能力,在构建容器镜像时设置文件能力;强制 false 也会阻止 newuidmap/newgidmap,导致 rootless 回退为单 UID/GID 映射,伴随警告且可能导致文件所有权错误
  runAsNonRoot: true
  capabilities:
    # drop: ["ALL"]  # 不能丢弃所有能力 —— buildah 需要 SETFCAP 能力,在构建过程中为容器镜像内文件设置文件能力(如 cap_net_bind_service)
    add: ["SETFCAP"]
  # seccompProfile:
  #   type: RuntimeDefault  # 不能使用 RuntimeDefault —— 默认 seccomp 会阻止 buildah 需要的 unshare/clone(CLONE_NEWUSER)/setns 系统调用,导致构建失败;应使用 Unconfined 或允许这些系统调用的自定义配置文件

解决方案:

  1. 在单独的命名空间中使用 baseline 模式(如 pod-security.kubernetes.io/enforce=baseline)运行 buildah Task,而非 restricted 模式
  2. 探索其他容器镜像构建方法,可能具有不同的安全需求

TaskRun 因容器用户错误失败

可能遇到以下错误:

  • "container has runAsNonRoot and image will run as root" —— 容器镜像的 Dockerfile 中无 USER 指令(默认为 root),或显式设置了 USER 0USER root
  • "container has runAsNonRoot and image has non-numeric user" —— 容器镜像使用了符号用户名(如 USER appuser)而非数字 UID

解决方案:

  1. 按步骤 3 所述,使用数字非 root 用户 ID 重新构建镜像。例如,使用 USER 65532 替代 USER appuserUSER root

  2. TasksecurityContext 中指定用户:

    apiVersion: tekton.dev/v1
    kind: Task
    metadata:
      name: example-task
    spec:
      steps:
        - name: step1
          image: registry.example.com/myimage:latest
          securityContext:
            runAsUser: 65532
            runAsNonRoot: true
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - "ALL"
            seccompProfile:
              type: RuntimeDefault
          script: |
            #!/bin/sh
            echo "Running as user $(id -u)"
  3. TaskRunpodTemplate 中指定用户:

    apiVersion: tekton.dev/v1
    kind: TaskRun
    metadata:
      name: example-taskrun
    spec:
      taskRef:
        name: example-task
      podTemplate:
        securityContext:
          runAsUser: 65532
          runAsNonRoot: true
          fsGroup: 65532

注意: podTemplate.securityContext 设置 Pod 级别的安全上下文,所有容器会继承此配置,除非容器级别另有覆盖。

当无法修改容器镜像时,方案 2 和 3 非常有用。

TaskRun 因 "Forbidden: cannot set securityContext.capabilities" 失败

此错误发生在安全上下文尝试添加能力的同时又丢弃所有能力。

解决方案: 确保您的 Task 不添加任何能力,仅按示例中那样丢弃能力。

初始化容器因权限错误失败

如果设置 set-security-context: true 后初始化容器出现权限错误,请检查:

  1. 命名空间是否有合适的安全策略
  2. Tekton 使用的容器镜像是否配置为非 root 用户运行
  3. Tekton 安装是否为最新版本

了解更多