Docker与Kubernetes安全联动:Pod安全策略的深度整合

摘要: 如果你还在研究 Kubernetes 的 Pod Security Policy (PSP),是时候停下来了。自 Kubernetes 1.25 版本起,这个曾经被寄予厚望的安全机制已被正式废弃并移除。这一变化并非简单的 API 弃用,而是反映了社区对 Pod 安全治理思路的根本性转变。

对于许多习惯了 Docker 安全参数的工程师而言,这无疑带来了新的困惑:没有了 PSP,我们该如何有效地在 Kubernetes 集群中实施安全策略?那些熟悉的 docker run 安全标志,又该如何在 Kubernetes 的世界里找到对应?

答案在于 Kubernetes 内置的一套新机制:以 Pod 安全标准(Pod Security Standards, PSS)为基础,由 Pod 安全准入控制器(Pod Security Admission, PSA)来强制执行。本文将为你清晰地梳理从 PSP 到 PSA 的演进路径,并深入探讨如何将 Docker 的安全能力与 Kubernetes 的 securityContext 进行深度整合,让你掌握当前 K8s Pod 安全的最佳实践。

为什么我们必须告别 Pod Security Policy (PSP)

在深入了解新方案之前,有必要先理解为什么 PSP 会被淘汰。PSP 的初衷是好的:提供一种集群范围的、强制性的方式来约束 Pod 的安全配置,例如禁止运行特权容器。然而,在长期的实践中,它的设计缺陷逐渐暴露。

难以预测的副作用

PSP 是一种集群级别的资源。一旦启用,它可能会在不经意间影响到集群中所有符合条件的 Pod。运维团队可能在无感知的情况下部署了一个严格的 PSP,导致开发团队的应用无法正常启动,并且排查过程异常困难,因为 Pod 的创建失败信息并不总是能清晰地指向是哪个 PSP 规则导致了问题。

复杂的权限模型

要让一个 PSP 生效,光创建它还不够。你必须通过 RBAC (Role-Based Access Control),将 use 这个权限动词绑定到特定的用户、用户组或 ServiceAccount 上。这套“创建 PSP -> 创建 Role -> 创建 RoleBinding”的流程不仅繁琐,而且极易出错。在大型多租户集群中,管理成百上千个 PSP 与其权限绑定的关系,是一场名副其实的噩梦。

设计理念的局限

PSP 的核心问题在于其“一刀切”且难以管理的集群级作用域。它试图用一种全局策略去应对多样化的应用场景,这在实践中被证明是低效且危险的。社区最终认识到,安全策略的上下文应该更贴近应用本身,也就是在命名空间(Namespace)级别进行控制,这样既能保证隔离性,又赋予了应用团队更大的自主权。

新范式:Pod 安全标准 (PSS) 与准-入控制器 (PSA)

正是基于对 PSP 缺陷的反思,社区推出了 Pod Security Admission (PSA)。这是一个内置的、默认开启的准入控制器,它不再需要复杂的 RBAC 配置,而是通过简单的命名空间标签来激活。PSA 的判断依据,则是清晰定义的 Pod 安全标准 (PSS)。

理解 Pod 安全标准 (PSS) 的三个层级

PSS 将 Pod 的安全级别划分为三个明确的、逐步收紧的层级。这种分级的设计,让我们可以根据不同环境和应用的需求,选择合适的安全基线。

Privileged: 不设防的“特权”级别

这基本上等同于没有限制。它允许 Pod 获取所有权限,包括运行特权容器、访问主机资源等。这个级别只应在极少数受信任的、用于系统级管理的场景下使用。

Baseline: 基础防护的“基线”级别

这是 PSS 的核心,旨在防止常见的容器逃逸和权限提升风险。它禁止了已知的特权提升配置,例如:

  • 禁止特权容器 (privileged: true)。
  • 限制使用特定的 Linux Capabilities。
  • 禁止挂载主机路径(HostPath)。
  • 限制使用某些主机网络和进程空间。

Baseline 策略旨在提供广泛的兼容性,大多数常规应用都应该能够在这个级别下正常运行。

Restricted: 高度受限的“受限”级别

这是最严格的安全级别,遵循了当前加固 Pod 的最佳实践。在 Baseline 的基础上,它增加了更多限制,例如:

  • 必须以非 root 用户运行 (runAsNonRoot: true)。
  • 必须禁止权限提升 (allowPrivilegeEscalation: false)。
  • 进一步收紧了允许使用的 Linux Capabilities,只保留极少数必要项。
  • 强制要求配置 Seccomp Profile。

这个级别主要面向对安全性要求极高的应用。

核心引擎:Pod Security Admission (PSA) 如何工作

PSA 作为一个准入控制器,会在 Pod 被创建或更新时进行拦截和校验。它通过检查目标命名空间的标签,来决定应用哪种 PSS 策略以及如何响应。

PSA 支持三种操作模式,它们可以组合使用:

  • enforce: 强制执行。如果 Pod 不符合策略要求,API Server 会直接拒绝创建请求。
  • audit: 审计。即使 Pod 不符合策略,创建请求也会被允许,但会在审计日志中记录一条违规信息。
  • warn: 警告。同样会允许创建不合规的 Pod,但会向客户端返回一条警告信息。

在命名空间中启用 PSA

启用 PSA 非常简单,只需为命名空间添加特定的标签即可。例如,如果我们希望某个命名空间强制执行 restricted 策略,同时对不符合 restricted 的 Pod 产生审计日志和警告,可以这样配置:

apiVersion: v1
kind: Namespace
metadata:
  name: my-secure-namespace
  labels:
    # 强制执行 'restricted' 策略
    pod-security.kubernetes.io/enforce: restricted
    # 如果不符合 'restricted',记录审计日志
    pod-security.kubernetes.io/audit: restricted
    # 如果不符合 'restricted',向用户显示警告
    pod-security.kubernetes.io/warn: restricted
    # 可选:指定强制执行的版本,建议使用 'latest'
    pod-security.kubernetes.io/enforce-version: latest

这种基于标签的声明式配置,比 PSP 的 RBAC 绑定模式要直观和简单得多。

从 Docker 命令到 K8s 配置:深度映射 securityContext

理解了 PSA 的工作方式后,我们还需要知道如何配置 Pod 自身,使其满足 PSS 的要求。这就要深入到 Pod Spec 中的 securityContext 字段。对于熟悉 Docker 的工程师来说,最好的学习方式就是将 docker run 的安全参数与 securityContext 的字段进行一一对应。

核心安全字段概览

securityContext 可以在 Pod 级别和 Container 级别进行设置。如果在 Pod 级别设置,它将作为所有容器的默认值;Container 级别的设置则会覆盖 Pod 级别的设置。这种分层设计提供了极大的灵活性。

关键参数映射实践

让我们通过具体的例子,看看那些熟悉的 Docker 安全操作如何在 Kubernetes 中实现。

禁止特权容器:--privileged vs privileged: false

在 Docker 中,我们使用 --privileged 来赋予容器几乎所有的主机权限,这通常是极力避免的。

  • Docker:

    # 危险操作
    docker run --privileged -it my-image
  • Kubernetes: securityContext 中的 privileged 字段直接对应此项。Baseline 和 Restricted 策略都要求它为 false。

    apiVersion: v1
    kind: Pod
    metadata:
      name: non-privileged-pod
    spec:
      containers:
      - name: my-container
        image: my-image
        securityContext:
          privileged: false # 明确禁止

控制用户与用户组:--user vs runAsUser / runAsGroup

以非 root 用户运行容器是基本的安全准则。

  • Docker:

    docker run --user "1000:3000" my-image
  • Kubernetes: 使用 runAsUser 和 runAsGroup。Restricted 策略甚至强制要求 runAsNonRoot: true。

    apiVersion: v1
    kind: Pod
    metadata:
      name: non-root-pod
    spec:
      securityContext:
        runAsUser: 1000
        runAsGroup: 3000
        runAsNonRoot: true # 强制以非 root 身份运行
      containers:
      - name: my-container
        image: my-image

防止根权限升级:--security-opt no-new-privileges vs allowPrivilegeEscalation: false

这个选项可以阻止容器内的进程通过 setuid 或 setgid 等方式获取新的权限。

  • Docker:

    docker run --security-opt no-new-privileges my-image
  • Kubernetes: allowPrivilegeEscalation 字段的功能完全相同。Baseline 和 Restricted 策略都要求其为 false。

    apiVersion: v1
    kind: Pod
    metadata:
      name: no-escalation-pod
    spec:
      containers:
      - name: my-container
        image: my-image
        securityContext:
          allowPrivilegeEscalation: false # 禁止权限提升

精细化权限控制:--cap-add / --cap-drop vs capabilities

Linux Capabilities 将 root 用户的超级权限分解为一系列独立的、可控的单元,实现了更精细的权限管理。

  • Docker:

    # 移除所有权限,然后只添加 NET_BIND_SERVICE
    docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE my-image
  • Kubernetes: capabilities 字段提供了同样的功能。Restricted 策略会严格限制 add 列表,并要求必须包含 drop: ["ALL"]。

    apiVersion: v1
    kind: Pod
    metadata:
      name: capabilities-pod
    spec:
      containers:
      - name: my-container
        image: my-image
        securityContext:
          capabilities:
            drop:
            - "ALL" # 先移除所有
            add:
            - "NET_BIND_SERVICE" # 再添加必要的

应用内核安全模块:--security-opt seccomp/apparmor vs seccompProfile / apparmorProfile

Seccomp (Secure Computing Mode) 用于限制容器可以进行的系统调用,而 AppArmor 则用于限制程序对文件、网络等资源的访问。

  • Docker:

    docker run --security-opt seccomp=unconfined --security-opt apparmor=docker-default my-image
  • Kubernetes: securityContext 提供了专门的 seccompProfile 和 apparmorProfile 字段。Restricted 策略强制要求配置 seccompProfile 为 RuntimeDefault 或 Localhost。

    apiVersion: v1
    kind: Pod
    metadata:
      name: seccomp-pod
    spec:
      securityContext:
        seccompProfile:
          type: RuntimeDefault # 推荐使用容器运行时的默认配置
      containers:
      - name: my-container
        image: my-image

策略落地与演进建议

掌握了技术细节后,如何在现有集群中平滑地落地这些安全策略呢?

如何平滑迁移

直接在生产命名空间启用 enforce 模式是危险的。正确的做法是分阶段进行:

  1. 从审计开始:首先在目标命名空间中启用 audit 和 warn 模式,例如 pod-security.kubernetes.io/audit: baseline。
  2. 分析日志:观察一段时间,收集审计日志。分析哪些现有的 Pod 或工作负载不符合 baseline 标准。
  3. 修复工作负载:根据分析结果,修改不合规工作负载的 YAML 文件,为其添加或调整 securityContext,使其满足策略要求。这是一个与开发团队协作的过程。
  4. 切换到强制模式:当审计日志中不再出现违规记录后,你就可以自信地将标签切换为 pod-security.kubernetes.io/enforce: baseline,完成策略的强制落地。

对于新项目,建议直接从 baseline 甚至 restricted 的 enforce 模式开始,从源头上确保应用的安全性。

关键要点回顾

  • 拥抱新标准:Pod Security Policy (PSP) 已被彻底废弃。Pod Security Admission (PSA) 结合 Pod Security Standards (PSS) 是当前 Kubernetes 内置的、唯一推荐的 Pod 安全治理方案。
  • 理解三个层级:PSS 定义了 Privileged、Baseline 和 Restricted 三个安全等级,为不同场景提供了清晰的指引。
  • 善用命名空间标签:通过为命名空间设置 enforce、audit、warn 标签,可以非常灵活地启用和调整 PSA 策略,无需复杂的 RBAC 配置。
  • securityContext 是核心:所有安全策略的最终落地,都需要通过配置 Pod 和容器的 securityContext 来实现。它与 Docker 的安全参数有着清晰的映射关系,是连接容器安全与编排安全的关键桥梁。

从 PSP 到 PSA 的转变,标志着 Kubernetes 安全理念的成熟。它将安全控制的权力从集群管理员下放到了更贴近应用的层面,使得安全策略更易于管理、预测和实施。

虽然 PSA 提供了强大的命名空间级控制机制,但在管理成百上千个集群、生成合规报告以及可视化策略漂移等企业级规模的场景中,可能还需要更上一层的抽象。在这些情况下,可以借助专业的安全平台来自动化策略治理,提供统一的视图,从而进一步简化安全管理的复杂性。但无论如何,深入理解 PSA 和 securityContext,都是每一位 Kubernetes 从业者构建云原生安全防线的基石。