Kubernetes 基础体系 · 第 46/83 篇。示例基于 Kubernetes 当前稳定 API;弃用、版本偏差、云厂商差异和生产风险会明确说明。
Kubernetes Pod Security:Standards、Admission、SecurityContext 和基线
Kubernetes 中的 Pod 安全不是单个字段或单个插件完成的。一个 Pod 能否创建,通常由以下几层共同决定:
- 认证与授权决定“谁可以请求什么”;
- Admission 决定“请求是否满足集群策略”,并可能修改对象;
- Pod Security Standards(PSS) 定义一组可移植的 Pod 安全级别;
- Pod Security Admission(PSA) 将这些级别应用到命名空间;
- SecurityContext 将安全要求表达为 Pod 或容器的运行时配置;
- 容器运行时、Linux 内核和节点安全机制最终执行这些限制。
因此,“Pod 使用了 runAsNonRoot: true”并不等于“Pod 已经符合安全基线”。它只表达了一个运行时约束,不能替代 Admission 策略,也不能覆盖网络、身份、节点和供应链风险。
一、先区分四个容易混淆的概念
1. SecurityContext 是运行配置
securityContext 是 Pod API 的一部分,用来描述容器进程应具备或不具备的安全属性,例如:
- 是否以非 root 用户运行;
- 使用哪个 UID、GID;
- 是否允许获得特权;
- Linux capabilities;
- seccomp、AppArmor、SELinux 配置;
- 根文件系统是否只读;
- 是否使用特定的补充组;
- Pod 是否设置
fsGroup。
它回答的是:
这个容器或 Pod 启动后,应以什么安全身份和内核约束运行?
2. Pod Security Standards 是安全规则集合
PSS 不是一个字段,也不是一个运行时沙箱。它定义了 Kubernetes 官方认可的三种策略级别:
privileged:不施加限制;baseline:禁止已知的高风险配置;restricted:在 baseline 之上,要求更严格的安全默认值。
它回答的是:
一个 Pod 的规格,是否落在某个安全策略允许的范围内?
3. Pod Security Admission 是准入控制器
PSA 是 Kubernetes 内置的 Admission Controller。它读取命名空间上的标签,对 Pod 进行检查:
enforce:不符合策略时拒绝请求;audit:允许请求,但写入审计注解;warn:允许请求,但向客户端返回警告。
它回答的是:
这个 Pod 是否可以进入 API Server 的持久化流程?
4. 基线不是“所有 Pod 都必须非 root”
baseline 是一个具体的 PSS 级别,不是泛指“最低安全要求”。它主要禁止特权、主机命名空间、危险 capabilities、任意 hostPath 等高风险行为,但通常不会要求所有应用都满足 restricted 的完整约束。
例如,一个 Pod 以 UID 0 运行,可能不符合 restricted,但不一定仅因为这一点就违反 baseline。反过来,一个非 root Pod 如果使用 hostNetwork: true,仍可能违反 baseline。
二、请求进入集群后,安全检查发生在哪里
一个创建 Pod 的请求大致经过以下路径:
flowchart LR
C[客户端] --> A[认证 Authentication]
A --> Z[授权 Authorization]
Z --> M[Mutating Admission]
M --> P[Pod Security Admission]
P --> V[其他 Validating Admission / Webhook]
V --> S[API Server 持久化]
S --> K[调度器与 Kubelet]
K --> R[容器运行时与 Linux 内核]
这张图表示的是逻辑阶段,而不是所有插件的精确固定顺序。具体 Admission 顺序由 API Server 配置和插件类型决定,但安全上必须区分以下事实:
- 认证只确定请求者身份,不判断 Pod 是否安全;
- 授权判断请求者是否有权限在某命名空间创建 Pod;
- Admission处理对象内容,可以拒绝或修改;
- PSA主要是验证 Pod 是否符合 PSS,不是 Linux 沙箱;
- 容器运行时和内核才真正执行 seccomp、capabilities、UID 等约束。
例如:
用户 alice 有权限在 team-a 创建 Pod
只说明 Alice 可以发起请求。它不说明:
Pod 可以使用 hostNetwork
Pod 可以挂载 hostPath
Pod 可以以 root 运行
Pod 可以添加 SYS_ADMIN capability
认证、授权与 Admission 是三个不同问题。
Admission 的拒绝点
设:
- 是提交的 Pod;
- 是命名空间上的策略标签;
- 是策略评估结果;
- 是 Admission 是否接受该请求。
对于 enforce 模式,可以简化为:
audit 和 warn 不改变是否接受:
但它们分别把结果写入审计事件或返回客户端警告。
因此,命名空间同时使用三个模式时,可能出现:
enforce=baseline
audit=restricted
warn=restricted
此时一个“不符合 restricted、但符合 baseline”的 Pod:
- 可以创建,因为 enforce 只要求 baseline;
- 会产生 audit 信息;
- 客户端会收到 warning。
这是一种常见的迁移方式:先观察 restricted 违规,再逐步切换 enforce。
三、Pod Security Standards 的三个级别
1. Privileged
privileged 不限制 Pod 的安全上下文。它适合确实需要节点级能力的系统组件,例如某些节点代理、调试工具或基础设施 DaemonSet。
但 privileged 不是“更高权限的安全模式”,而是:
不通过 PSS 对 Pod 的这些安全属性施加限制。
它不等于 Kubernetes RBAC 中的 cluster-admin,也不自动授予 API Server 权限。一个 privileged 容器可能拥有大量 Linux 权限,却仍没有访问 Kubernetes API 的 ServiceAccount 权限。
2. Baseline
baseline 禁止常见的高风险配置,典型范围包括:
- 使用特权容器;
- 使用主机网络、主机 PID 或主机 IPC;
- 添加危险 Linux capabilities;
- 使用某些不安全的 volume 类型;
- 使用 hostPath;
- 使用不受允许范围约束的主机端口;
- 使用不安全的 procMount;
- 在 Linux Pod 中使用不允许的 seccomp 配置;
- 某些主机用户命名空间或 SELinux 相关高风险配置。
Baseline 的核心思想是:
阻止容易导致容器直接扩大到节点权限的配置,但不强迫所有应用立即采用最严格的运行时约束。
3. Restricted
restricted 在 baseline 之上,进一步要求 Pod 使用更安全的默认值。典型要求包括:
- 明确使用非 root;
- 禁止
runAsUser: 0; - 必须设置
allowPrivilegeEscalation: false; - capabilities 必须删除
ALL,并且只能添加极少数允许项; - seccomp 必须使用
RuntimeDefault或允许的本地配置; - 某些版本的 restricted 还会检查 Linux Pod 的安全上下文完整性;
- 对 Windows Pod 和 Linux Pod 的规则存在差异。
这里必须注意版本问题:PSS 的具体字段检查会随 Kubernetes 版本演进。restricted 在不同 Kubernetes minor 版本中可能新增要求,因此生产环境不应只写“restricted”,还应考虑固定版本。
四、策略版本与命名空间标签
PSA 通过命名空间标签选择策略。例如:
apiVersion: v1
kind: Namespace
metadata:
name: team-a
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: v1.34
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: v1.34
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: v1.34
执行:
kubectl apply -f namespace.yaml
kubectl get ns team-a --show-labels
预期可以看到这些标签。
标签含义是:
pod-security.kubernetes.io/<mode>:策略级别;pod-security.kubernetes.io/<mode>-version:策略版本;mode可以是enforce、audit或warn;- 版本通常写成
v1.xx,而不是 Kubernetes 发行版完整版本号。
为什么要固定版本
假设今天 restricted 允许某个配置,升级 Kubernetes 后该配置被纳入违规检查。如果命名空间使用:
pod-security.kubernetes.io/enforce: restricted
其行为可能随集群支持的默认策略版本变化。
固定为:
pod-security.kubernetes.io/enforce-version: v1.34
可以使策略语义更稳定。但它不是永久兼容保证:当集群不再支持该策略版本,仍需要按升级计划迁移。
使用 kubectl 预检查
可以在不真正创建对象的情况下预检查:
kubectl label --dry-run=server --overwrite ns team-a \
pod-security.kubernetes.io/enforce=restricted
也可以直接检查资源:
kubectl apply --dry-run=server -f pod.yaml
如果命名空间启用了 warn,客户端可能看到类似以下警告:
Warning: would violate PodSecurity "restricted:v1.34": ...
警告文本是诊断入口,但具体字段应以当前集群返回内容为准,不能依赖某个固定错误字符串做自动化解析。
五、一个完整的 Pod 安全上下文
下面的 Pod 以 restricted 常见要求为目标:
apiVersion: v1
kind: Pod
metadata:
name: secure-demo
namespace: team-a
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10000
runAsGroup: 10000
fsGroup: 10000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: nginx:1.27
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
创建:
kubectl apply -f secure-demo.yaml
kubectl get pod secure-demo -n team-a
kubectl describe pod secure-demo -n team-a
这个例子中有几层含义:
runAsNonRoot: true要求进程不能以 UID 0 运行;runAsUser: 10000指定目标 UID;runAsGroup指定主组;fsGroup主要影响挂载卷上的组所有权和访问组;seccompProfile: RuntimeDefault使用运行时默认 seccomp 配置;allowPrivilegeEscalation: false禁止进程通过setuid等机制获得更高权限;drop: [ALL]删除所有 Linux capabilities;readOnlyRootFilesystem: true将根文件系统挂载为只读。
但是这个示例未必能直接运行。nginx 可能需要写入某些路径,例如 PID、缓存或临时目录。若根文件系统只读,应显式提供可写的临时卷:
apiVersion: v1
kind: Pod
metadata:
name: secure-nginx
namespace: team-a
spec:
securityContext:
runAsNonRoot: true
runAsUser: 101
runAsGroup: 101
fsGroup: 101
seccompProfile:
type: RuntimeDefault
containers:
- name: nginx
image: nginxinc/nginx-unprivileged:1.27
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
readOnlyRootFilesystem: true
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /var/cache/nginx
- name: run
mountPath: /var/run
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
- name: run
emptyDir: {}
这里使用非 root 镜像很重要。仅仅写:
runAsNonRoot: true
并不能把一个只支持 root 的镜像“改造成”非 root 镜像。Kubelet 会根据镜像元数据和运行时配置判断,如果无法证明容器不会以 root 启动,Pod 可能出现:
container has runAsNonRoot and image will run as root
六、Pod 级与容器级 SecurityContext 的作用域
securityContext 可以写在 spec.securityContext,也可以写在每个容器的 securityContext。
Pod 级字段
常见 Pod 级字段包括:
spec:
securityContext:
runAsUser: 10000
runAsGroup: 10000
runAsNonRoot: true
fsGroup: 10000
seccompProfile:
type: RuntimeDefault
它们通常作为 Pod 内容器的默认值,适合表达整个 Pod 的共同身份或策略。
容器级字段
容器级配置例如:
containers:
- name: app
securityContext:
allowPrivilegeEscalation: false
privileged: false
capabilities:
drop: ["ALL"]
readOnlyRootFilesystem: true
这些字段直接作用于某个容器。
当 Pod 级和容器级都设置同一属性时,不能简单理解为“两个值合并”。通常容器级配置会覆盖对应的 Pod 默认值;但不同字段的继承和校验规则不同,最终应查看生成后的 Pod:
kubectl get pod secure-demo -n team-a -o yaml
Admission 也会检查 Pod 中的所有相关容器,包括:
- 普通
containers; initContainers;- 在相应版本规则中受检查的 ephemeral containers。
因此只保护主容器而遗漏 initContainer 是常见错误:
initContainers:
- name: migration
image: migration:latest
securityContext:
privileged: true
即使主容器完全符合 restricted,整个 Pod 仍可能因为 initContainer 违规而被拒绝。
七、关键安全字段的真实语义
1. runAsNonRoot、runAsUser 与 root
这三个概念不同:
runAsUser: 10000:请求使用 UID 10000;runAsNonRoot: true:拒绝以 UID 0 运行;- 镜像中的
USER:镜像默认用户,只有在没有更高层配置时才可能成为最终依据。
一个常见误解是:
runAsUser: 10000
就能保证进程安全。它只改变身份,不限制:
- 是否能访问挂载的宿主机路径;
- 是否持有危险 capabilities;
- 是否可以利用内核漏洞;
- 是否能访问 Kubernetes API;
- 是否能写入共享卷中的敏感文件。
非 root 是重要约束,但不是完整隔离。
2. allowPrivilegeEscalation
该字段控制进程是否可以获得比启动时更高的权限,通常对应 Linux 的 no_new_privs 语义。
securityContext:
allowPrivilegeEscalation: false
它不是“禁止所有特权”的同义词:
- 容器可能仍以 root 启动;
- 容器可能仍拥有已有 capabilities;
privileged: true的行为不能靠它补救;- 它通常不能与需要 setuid 提权的程序兼容。
restricted 要求该字段为 false,这是因为“初始权限不高”还不够,进程也不应通过执行特殊文件获得更高权限。
3. Linux capabilities
Linux capability 将传统 root 权限拆分为多个能力,例如:
NET_BIND_SERVICE:绑定低于 1024 的端口;NET_ADMIN:部分网络管理操作;SYS_ADMIN:权限范围很大,风险高;SYS_PTRACE:跟踪其他进程。
更安全的默认写法是:
capabilities:
drop:
- ALL
若应用确实需要绑定低端口,可以只添加必要能力:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
不要因为“容器不是 root”就忽略 capabilities。一个非 root 进程如果被授予高风险 capability,仍可能执行高影响操作。反过来,删除所有 capabilities 也不等于没有所有权限,因为权限还来自 UID、文件权限、seccomp、设备、挂载和内核漏洞等来源。
4. privileged
securityContext:
privileged: true
通常会显著扩大容器与宿主机的交互能力,可能获得设备访问、更多 capabilities 以及弱化的隔离语义。它不是修复权限问题的普通开关。
需要节点级能力的系统组件可以使用它,但应通过:
- 独立命名空间;
- 严格 RBAC;
- 固定镜像;
- 节点隔离;
- 最小化挂载;
- 审计和变更审批;
限制影响范围。
5. readOnlyRootFilesystem
readOnlyRootFilesystem: true
它只读的是容器根文件系统,不代表所有文件都只读。以下位置仍可能可写:
emptyDir;- PVC;
- Secret 或 ConfigMap 的特定挂载语义;
- 某些运行时提供的文件系统。
生产中开启该选项后,应根据应用启动失败日志补充明确的 emptyDir 或持久卷,而不是直接关闭该限制。
6. fsGroup
spec:
securityContext:
fsGroup: 10000
fsGroup 主要用于卷挂载时的组访问控制。它不是进程 UID,也不是 Kubernetes 用户身份。某些卷类型和 CSI 驱动对 fsGroup 的处理不同,可能出现:
- 挂载时递归修改大量文件导致启动变慢;
- 存储驱动不支持预期的组变更;
- 共享卷中的旧文件权限仍然不正确。
所以 fsGroup 的实际效果取决于卷类型、CSI 驱动和节点实现,不能仅凭 YAML 推断全部行为。
八、seccomp、AppArmor 与 SELinux
1. seccomp
seccomp 通过限制进程可调用的系统调用来缩小内核攻击面。常见配置为:
securityContext:
seccompProfile:
type: RuntimeDefault
类型主要包括:
RuntimeDefault:使用容器运行时默认 profile;Localhost:使用节点上配置的本地 profile;Unconfined:不使用 seccomp 限制。
RuntimeDefault 的具体系统调用集合由容器运行时和节点配置决定,不是一个跨所有发行版完全相同的固定列表。若应用启动后报 Operation not permitted,可能是 seccomp 拦截了系统调用,诊断时需要结合:
kubectl describe pod POD -n NAMESPACE
kubectl logs POD -n NAMESPACE
并检查节点运行时、内核审计日志。不要首先将 profile 改成 Unconfined 作为永久修复;这会扩大系统调用面,正确做法通常是确认应用确实需要的调用,再提供经过测试的本地 profile。
2. AppArmor
AppArmor 是 Linux LSM 之一,通过配置文件约束文件访问、能力和部分系统行为。它要求:
- 节点内核支持 AppArmor;
- 节点加载对应 profile;
- Kubernetes 与容器运行时支持对应配置方式。
较新的 Kubernetes API 提供 appArmorProfile 字段时,可以在 securityContext 中声明 profile;较旧集群常见的是使用 container.apparmor.security.beta.kubernetes.io/<container-name> 注解。注解方式与字段方式不能不加判断地混用,必须以目标 Kubernetes 版本 API 文档和节点支持情况为准。
AppArmor 不是 Pod Security Admission 的替代品。PSA 可以阻止不允许的安全配置,但不会为业务自动生成一个正确的 AppArmor profile。
3. SELinux
SELinux 通过标签和策略控制进程与文件的访问。相关配置可能包括:
securityContext:
seLinuxOptions:
level: "s0:c123,c456"
但 SELinux 标签具有强烈的节点发行版和集群配置依赖。错误配置可能导致容器无法访问本应可访问的文件。生产环境应确认:
- 节点是否启用 SELinux;
- CRI 是否正确处理标签;
- 存储驱动是否支持;
- 标签是否与平台安全策略一致。
PSS 对 SELinux 相关字段有基线约束,但“通过 PSS”不等于“SELinux 策略已经正确保护业务”。
九、一个会失败的基线示例
以下 Pod 同时使用了多个高风险设置:
apiVersion: v1
kind: Pod
metadata:
name: unsafe-demo
namespace: team-a
spec:
hostNetwork: true
hostPID: true
containers:
- name: shell
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
securityContext:
privileged: true
volumeMounts:
- name: host
mountPath: /host
volumes:
- name: host
hostPath:
path: /
如果 team-a 使用:
pod-security.kubernetes.io/enforce=baseline
执行:
kubectl apply -f unsafe-demo.yaml
预期请求被拒绝,错误通常会列出一个或多个违规项,例如:
violates PodSecurity "baseline": privileged, host namespaces, hostPath ...
这里的因果链是:
privileged扩大容器权限;hostPID让容器看到主机进程命名空间;hostNetwork让容器使用主机网络栈;hostPath: /暴露宿主机文件系统;- 任意一项都可能形成严重风险,组合使用时风险更高;
- baseline 在 Admission 阶段拒绝对象,因此 Pod 不会进入调度和启动阶段。
这与“Pod 创建成功但容器启动失败”不同。若是 PSA 拒绝,通常不会产生一个可查询的运行中 Pod:
kubectl get pod unsafe-demo -n team-a
可能得到:
No resources found
而不是 CrashLoopBackOff。
十、Baseline 与 Restricted 的迁移方法
可以先创建一个“只观察、不阻断”的命名空间策略:
apiVersion: v1
kind: Namespace
metadata:
name: migration
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: v1.34
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: v1.34
应用业务 Pod:
kubectl apply -f workload.yaml -n migration
然后观察三类信息:
kubectl get events -n migration --sort-by=.lastTimestamp
kubectl get pod -n migration
kubectl describe pod POD_NAME -n migration
warn:直接显示给执行命令的客户端;audit:进入审计事件,具体保存方式取决于 API Server 审计配置;enforce:不符合时请求失败。
修复的顺序应以违规字段为依据,而不是盲目添加全部字段:
- 移除
privileged、host namespace 和不必要的 hostPath; - 删除所有 capabilities,再按错误逐个恢复必要能力;
- 设置
runAsNonRoot和非 root UID; - 设置
allowPrivilegeEscalation: false; - 使用
RuntimeDefaultseccomp; - 配置只读根文件系统,并显式提供必要可写目录;
- 修复 initContainer 和临时调试容器;
- 在验证所有工作负载后,将
enforce从 baseline 提升为 restricted。
不能把 warn 或 audit 当成保护措施。它们只提供可见性,不会阻止不安全 Pod 进入集群。
十一、PSA 的豁免与自动化风险
集群管理员可以通过 PSA 配置文件设置豁免范围,例如豁免:
- 特定用户名;
- 特定运行时类;
- 特定命名空间;
- 特定资源请求。
豁免通常用于系统组件或受控基础设施,而不是为普通业务开发提供“绕过按钮”。
真实风险在于,某些工作负载并不是用户直接创建的:
用户提交 Deployment
→ Deployment Controller 创建 ReplicaSet
→ ReplicaSet Controller 创建 Pod
PSA 最终检查的是 Pod 对象,但 Admission 请求的用户可能是控制器 ServiceAccount。于是需要确认:
- 豁免匹配的是原始用户还是控制器身份;
- 生成的 Pod 是否会落入受保护命名空间;
- 自定义 Operator 是否需要特殊权限;
- 扩容、滚动更新和恢复流程是否都能通过策略。
测试只执行一次 kubectl apply 不足以证明控制器工作正常。至少应验证:
kubectl rollout status deployment/app -n team-a
kubectl get rs,pod -n team-a
kubectl describe deployment app -n team-a
十二、Webhook 与 PSA 的故障语义不同
PSA 是内置 Admission 插件,而自定义策略通常通过 Validating Webhook 或 Mutating Webhook 实现。
Webhook 常有以下配置:
failurePolicy: Fail
Fail:Webhook 不可达或返回错误时,拒绝请求;Ignore:Webhook 故障时放行请求。
Fail 提高策略完整性,但 Webhook 的可用性会直接影响集群写入;Ignore 提高可用性,却可能在故障期间形成策略旁路。
PSA 的核心策略不应依赖一个可能因网络、证书、Service、端点或升级而不可达的外部 Webhook。常见分工是:
- PSA 负责官方 Pod 安全基线;
- Webhook 负责组织特有规则,例如镜像仓库、标签、资源限制、业务隔离;
- Webhook 必须有超时、证书轮换、拓扑和升级方案;
- 对安全强制规则慎用
Ignore。
还要注意 Admission 的失败路径。请求可能在:
- 授权阶段被拒绝;
- Mutating Webhook 阶段超时;
- PSA 阶段违反 baseline;
- Validating Webhook 阶段因策略失败;
- API Server 持久化或 etcd 阶段失败。
诊断时应根据 HTTP 错误、API Server 日志、事件和 Webhook 配置区分原因,而不是把所有“创建失败”都归咎于 PSA。
十三、排查 Pod 安全问题的顺序
1. 确认目标命名空间和标签
kubectl get ns team-a -o yaml
kubectl label ns team-a --list
重点检查:
- 是否真的在预期命名空间;
enforce是否存在;enforce-version是否固定;- 是否有命名空间拼写或上下文错误。
2. 确认服务端实际收到的对象
客户端 YAML 可能由 Helm、Kustomize 或 Operator 生成。应检查最终清单:
helm template release ./chart -n team-a
kubectl apply --dry-run=server -f rendered.yaml
不要只检查模板源文件。
3. 区分拒绝与运行失败
kubectl apply立即返回violates PodSecurity:通常是 Admission 拒绝;- Pod 存在但
Pending:可能是调度、卷或节点问题; - Pod 存在但
CrashLoopBackOff:可能是用户、文件权限、只读根文件系统或 seccomp; - Pod 创建后立即消失:可能是控制器回滚或对象被删除。
4. 检查所有容器和卷
kubectl get pod app-xxx -n team-a -o jsonpath='{.spec.initContainers[*].securityContext}'
kubectl get pod app-xxx -n team-a -o yaml
检查主容器、initContainer、ephemeral container、卷、主机命名空间和端口,而不是只看第一个容器。
5. 在节点侧确认运行时限制
当 YAML 看起来正确但行为不符时,还要检查:
- 节点内核是否支持 seccomp/AppArmor/SELinux;
- 容器运行时实际加载的 profile;
- CSI 驱动是否处理 fsGroup;
- 镜像真实默认用户;
- 节点是否属于不同发行版或不同运行时。
云厂商托管 Kubernetes 还可能对节点镜像、Admission 配置、默认 seccomp、AppArmor 和系统组件做额外处理。这些行为不属于 Kubernetes API 的统一保证,必须查目标平台文档和节点实际状态。
十四、边界与生产取舍
1. PSS 不是完整容器安全方案
PSS 主要检查 Pod 规格,不能解决:
- 应用漏洞;
- 恶意镜像;
- Kubernetes API 权限过大;
- Secret 泄露;
- 网络横向移动;
- 节点内核漏洞;
- 供应链投毒;
- 容器运行后的异常行为。
因此还需要分别配置 RBAC、NetworkPolicy、镜像签名或扫描、Secret 管理、节点加固和运行时检测。
2. 非 root 不是绝对隔离
非 root 能减少传统 root 风险,但容器仍可能:
- 访问错误挂载的 Secret;
- 访问共享卷中的其他数据;
- 使用被授予的 capabilities;
- 利用内核或运行时漏洞;
- 通过应用身份访问 Kubernetes API。
3. Restricted 可能与旧应用冲突
旧应用常见不兼容包括:
- 启动脚本要求 root;
- 需要写入镜像内目录;
- 需要低端口但不能添加
NET_BIND_SERVICE; - 需要额外系统调用;
- 依赖 setuid;
- 使用 hostNetwork 或 hostPath;
- initContainer 需要修改共享卷权限。
这些问题不应通过把整个命名空间改为 privileged 解决。更合理的方式是:
- 修改镜像和启动脚本;
- 使用固定非 root UID;
- 提供明确的 writable volume;
- 缩小 capability;
- 编写受控 seccomp/AppArmor profile;
- 将确实需要节点权限的组件放入独立命名空间并限制其权限。
4. “通过 baseline”不是安全证明
形式上,如果:
只能说明 Pod 满足 baseline 定义的约束。它不能推出:
更不能推出:
安全级别是策略集合之间的关系,而不是风险评分。一个 Pod 可以通过 baseline,却仍以 root 运行、根文件系统可写、拥有过多应用权限。
十五、一个可操作的最低闭环
对普通业务命名空间,可以采用如下闭环:
metadata:
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: v1.34
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: v1.34
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: v1.34
然后对工作负载逐步落实:
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
readOnlyRootFilesystem: true
验证不仅包括:
kubectl apply --dry-run=server -f workload.yaml
kubectl apply -f workload.yaml
kubectl rollout status deployment/app -n team-a
kubectl logs deployment/app -n team-a
还要验证升级、回滚、扩容、initContainer、探针、卷权限和节点差异。最终把 restricted 从 warn/audit 提升为 enforce,应以生产工作负载已经完成兼容性验证为前提。
Pod Security 的正确理解不是“给 YAML 加几个字段”,而是建立一条完整因果链:
安全目标
→ SecurityContext 表达约束
→ PSS 定义可验证规则
→ PSA 在 API Server 阶段拒绝违规对象
→ 容器运行时和内核执行约束
→ 日志、审计和测试验证实际结果
只有这条链条同时成立,Pod 安全基线才不是文档中的声明,而是集群中的可执行控制。
系列导航与关联阅读
- 系列入口:Kubernetes 完整学习路线:从 Pod 与控制面到安全、运维和 Operator
- 上一篇:Kubernetes ServiceAccount:Projected Token、Audience、轮换和 Workload Identity
- 下一篇:Kubernetes 运行时安全:非 root、Capabilities、Seccomp、AppArmor 和只读根
- 延伸:Kubernetes Admission Control:内置插件、Webhook、策略、失败和可用性
官方资料
本文依据 Kubernetes、CNCF 与相关项目官方文档重新梳理;正文和生产清单由 WR BLOG 编写。

评论
0 条讨论