容器里的 /proc 通常不是空白目录,而是内核暴露给进程的窗口。Kubernetes 默认会给容器挂载带掩码的 /proc,把一部分敏感节点遮住,以缩小攻击面;当工作负载在 securityContext.procMount 中写入 Unmasked 时,这层默认掩码就被绕开,容器可以看到更接近宿主机的 /proc 视图。这个字段常被忽略,因为它不像 privileged 那样显眼,也不一定立即导致 Pod 启动失败。本文只讨论这一细节:如何确认工作负载是否显式放开了 /proc 挂载,如何在准入层和工作负载层收敛配置,变更后如何复核容器内可见内容,以及出问题时如何回滚。适用范围是 linux 节点上的 Kubernetes 工作负载;Windows 容器不适用这套 /proc 掩码逻辑。

先明确作用边界
procMount 是容器级 securityContext 字段,Pod Security Standards 在限制 /proc 挂载类型时,会检查 spec.containers[].securityContext.procMount、spec.initContainers[].securityContext.procMount 和 spec.ephemeralContainers[].securityContext.procMount。根据 Kubernetes 官方 Pod 安全性标准文档,baseline 与 restricted 对 /proc 挂载类型的要求是使用默认掩码,准许值为未定义、nil 或 Default。这意味着省略字段、写 nil 或显式写 Default 都落在默认掩码一侧;Unmasked 则是需要单独解释和审查的例外。
但掩码不是完整隔离。它主要减少 /proc 中敏感信息的暴露面,不能替代最小权限、只读根文件系统、seccomp、能力裁剪、运行时沙箱和节点隔离。反过来,移除 Unmasked 也不等于工作负载自动安全;它只是把一个容易被忽略的隔离细节收回到默认基线。评估时应把 procMount 和同一容器中的 privileged、hostPID、hostPath、能力集合一起看,而不是只盯一个字段。
上游准入实现并非永远静止。围绕 Unmasked 与用户命名空间条件,Kubernetes 社区有过准入调整;不同集群版本、特性门控和 PSA 配置可能表现不同。因此不要只凭记忆判断“baseline 一定拦”或“restricted 一定放行”,应在目标集群上用 dry-run 或审计模式确认实际行为。官方参考至少包括 Pod 安全性标准 和 为 Pod 或容器配置安全上下文。
审计:找出显式放开 /proc 的工作负载
第一步不是改配置,而是盘点。需要同时覆盖普通容器、初始化容器和临时容器,因为 PSS 对三类字段都有限制。使用 jq 对集群内 Pod 做一次结构化扫描,比逐一看 YAML 更可靠:
kubectl get pods -A -o json | jq -r '
.items[] as $p
| (($p.spec.containers // [])
+ ($p.spec.initContainers // [])
+ ($p.spec.ephemeralContainers // []))
| .[]
| select(.securityContext.procMount != null)
| [$p.metadata.namespace, $p.metadata.name, .name,
.securityContext.procMount] | @tsv
'输出中 Unmasked 是重点,Default 也应记录,因为它说明该工作负载曾被显式配置过,可能伴随其他安全上下文调整。若集群规模较大,可把结果按命名空间、工作负载类型和负责人聚合,优先处理面向外部流量、处理凭据或挂载敏感卷的负载。
还要检查准入层的现状:
kubectl get ns --show-labels | grep pod-security如果命名空间只有 warn 或 audit 标签,说明违规配置可能已被记录但未被阻止;如果只有 enforce,则新创建或重建的 Pod 会被拦截。注意 PSA 不会追溯修改已经运行的 Pod,收敛配置后必须通过重建让新 Pod 生效。
收敛:准入层与工作负载层同时处理
准入层适合建立统一底线。对普通业务命名空间,可先以审计模式观察,再切到阻止模式:
apiVersion: v1
kind: Namespace
metadata:
name: prod-app
labels:
pod-security.kubernetes.io/audit: baseline
pod-security.kubernetes.io/warn: baseline
pod-security.kubernetes.io/enforce: baseline生产环境建议把版本标签固定到与集群匹配的 PSS 版本,而不是长期依赖浮动默认值;切换 enforce 前先用 --dry-run=server 验证现有清单是否会被拒绝。若命名空间内确有需要 Unmasked 的例外,不应直接把整个命名空间降到 privileged,而应评估单独命名空间、豁免策略和审批记录,把例外范围压到最小。
工作负载层则移除不必要的 Unmasked。若字段本来省略,保持省略即可;若需要显式表达意图,可写 Default:
spec:
containers:
- name: app
securityContext:
procMount: Default
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]这里的关键不是把 Default 当成新的“安全开关”,而是让清单明确表达使用默认掩码。变更前先保存原始清单,例如:
kubectl get deployment app -n prod-app -o yaml > app-before-procmount.yaml如果工作负载模板由 Helm、Kustomize 或平台控制器生成,要改模板而不是只改运行中的 Pod,否则下一次发布会把 Unmasked 带回来。
验证:看准入结果,也看容器内 /proc
变更后至少做三层验证。第一层是准入与对象状态:确认新 Pod 已被创建,且容器字段中不再出现 Unmasked。
kubectl get pod <pod-name> -n prod-app -o json | jq -r '
(.spec.containers + (.spec.initContainers // []))
| .[] | [.name, (.securityContext.procMount // "unset")] | @tsv
'第二层是容器内可见性。默认掩码的具体实现由容器运行时决定,不要假设某个路径在所有运行时下表现完全一致;应针对运行时的已知基线做对照检查。下面的命令用于观察 /proc 中若干常见敏感节点是否仍以普通可读文件形态暴露:
kubectl exec -n prod-app <pod-name> -- sh -c '
for p in /proc/kcore /proc/keys /proc/timer_list /proc/sched_debug; do
if [ -e "$p" ]; then
ls -l "$p" 2>&1
head -c 64 "$p" 2>&1 | od -An -tx1 | head -n 1
else
echo "missing: $p"
fi
done
'判定时不要只看“命令是否报错”。默认掩码可能把路径绑定覆盖为只读或空设备,表现为可访问但内容异常;也可能由权限位拒绝读取。更稳妥的做法是记录变更前和变更后的输出,与运行时基线比较。若应用依赖 /proc/self、/proc/cpuinfo、/proc/meminfo 等常规节点,通常不受影响;若应用读取 /proc/kcore、/proc/keys 之类节点,则应先确认这是业务必需还是历史遗留。
第三层是应用与监控观察。变更后检查 Pod 是否反复重启、应用日志是否出现权限错误、性能采集或诊断 sidecar 是否失效。把准入拒绝事件、Pod 重建时间和应用错误率放在同一个观察窗口内,避免把应用自身故障误判为 /proc 收敛导致。
异常排查与回滚
常见异常可以用下表快速定位:
| 现象 | 可能原因 | 处理方向 |
|---|---|---|
| 新 Pod 被准入拒绝 | enforce 已切到 baseline,清单仍含 Unmasked | 修正模板并重新发布;不要直接降级整个命名空间 |
| Pod 正常启动但诊断工具失效 | 工具依赖被掩码的 /proc 节点 | 确认是否业务必需;改用受控诊断 Pod 或专用节点工具 |
应用读取 /proc 报权限错误 | 默认掩码或能力裁剪生效 | 对照变更前后输出,确认具体路径和运行时行为 |
| 回滚后仍被拒绝 | PSA 仍处于 enforce,旧清单含 Unmasked | 临时调整准入策略并记录审批,完成回滚后恢复 |
回滚应优先回到变更前的工作负载清单,而不是在运行中的 Pod 上手工修补:
kubectl apply -f app-before-procmount.yaml
kubectl rollout status deployment/app -n prod-app如果使用 Deployment,也可以使用 kubectl rollout undo deployment/app -n prod-app,但前提是历史版本确实保留了变更前配置。回滚后要再次检查 procMount 字段和容器内 /proc 可见性,确认应用恢复。
如果准入层阻止了回滚,说明策略正在按预期工作。此时不应长期关闭 enforce;可在受控时间窗内把命名空间切到 warn/audit,或对单独命名空间使用豁免,并记录原因、范围、审批人和恢复时间。回滚只是恢复业务可用性,不是取消加固目标;恢复后仍应查清应用为什么依赖 Unmasked,再决定是改造应用、调整运行时基线,还是保留一个有明确边界的例外。
最后提醒两个限制:这套讨论仅适用于 linux 节点;procMount 的行为和默认掩码内容最终由容器运行时与内核共同决定。把它纳入发布前检查和准入策略,比一次性“扫一遍集群”更有持续价值。

- it2021
- it2021.com
- Kubernetes





1F
这个字段真容易忽略