LabHub
学习 学习路径 课程

KCSA — Kubernetes 安全助理

Secret 读取、Pod 创建与运行安全是不同的边界

在 LabHub 中继续学习

一句话总结

读取 Secret API 的权限、创建 Pod 的权限、Pod 的运行安全设置,是三个不同的边界。即使是 Restricted Pod,也能通过卷读取同一命名空间中的 Secret。

概念图: 一句话总结 · 为什么需要它 · 工作原理 · 连续提出三个问题

为什么需要它

假设有如下场景:从部署服务账户中删除了 get secretskubectl auth can-i 也回答 no,于是报告称它无法访问秘密。但该账户仍保留 create pods。攻击者没有选择读取 Secret 的 API,而是选择创建一个挂载 Secret 卷的 Pod。kubelet 准备好卷后,容器通过普通文件读取就能取得值。直接访问被拒绝,并不等于间接访问已被阻止。

工作原理

连续提出三个问题

边界 提出的问题 本实验观察的内容
认证 请求者是谁? 区分管理员证书与被模拟的 runner SA
授权 是否允许这个动词、资源和范围? 拒绝查询 Secret,允许创建 app 的 Pod
准入 是否接受这个已获授权创建请求中的对象? 检查 Pod 是否满足 Restricted 运行条件

Pod 创建请求的主体与 Pod 的 serviceAccountName 不是同一概念。管理员创建一个指定 runner 的 Pod,并不表示使用了 runner 的创建权限。下一项实验会使用 --as=system:serviceaccount:app:runner 发送真实创建请求。这是利用管理员 impersonate 权限进行的教学模拟请求,并非窃取或伪造 SA 令牌。

Restricted 阻止什么、保留什么

Pod Security Standards 的 Restricted 会限制 privilege escalation、root 运行等容器执行设置。从 baseline 起,就会限制 hostPath、hostPID、hostNetwork、privileged 等危险配置。但 Restricted 允许的卷中包含 secretconfigMap。该策略不会判断某个用户在业务上是否可以使用特定 Secret。

即使同时设置 runAsNonRoot: true、capabilities drop ALL、allowPrivilegeEscalation: falseseccompProfile: RuntimeDefault,也不会禁止容器读取合法挂载的文件。automountServiceAccountToken: false 只是关闭 API 令牌自动挂载,不会阻止 Secret 卷。

因此,“create pods 总是等同于节点 root”这一说法也不正确。即使权限相同,可达范围仍取决于准入策略、可选择的 SA、命名空间范围和卷类型。pods/exec 受可以进入的现有容器的权限和数据影响。bindescalateimpersonate 也必须检查允许的资源与主体范围,不能因为存在其中一个动词,就一概断定为 cluster-admin。

防御必须同时确定数据边界与工作负载边界

不互相信任的任务,不应与敏感 Secret 放在同一命名空间,这是起点。应最小化工作负载创建权限和可选择的服务账户;必要时通过独立准入策略限制允许引用的 Secret 和 SA 选择。即使给直接 get 权限加上 resourceNames,也不会自动限制通过创建 Pod 引用的卷。NetworkPolicy 控制网络连接,无法阻止读取已经挂载的本地文件。

PSA 在此基础上仍然必要。既要应用降低危险执行设置越过节点边界的控制,也要应用决定谁能使用命名空间内业务数据的控制。关键是不能因为一个边界打了勾,就省略另一个边界的验证。

静态存储加密也是另一条边界

Secret API 的 data 值只是 base64 表示,并非加密。未配置静态存储加密时,存储系统中的数据无法保证机密性。本实验的 k3s/kine 环境会在 SQLite 中序列化的 Secret 里确认合成标记。这不表示所有发行版都使用相同文件和序列化格式;托管服务的默认加密设置也必须另行确认。

EncryptionConfiguration 使用第一个 provider 写入新值,再通过后续 provider 读取旧值。把 identity 放在前面,新数据也不会加密。启用配置或更换密钥,并不会自动重新保存现有对象,还需要重写、验证和删除旧读取路径。正常授权的 API 请求会取得解密后的值,因此静态存储加密不会阻断上述挂载路径。如果密钥和备份一起暴露,加密效果也会丧失。

实际现场中的情况

示例检查顺序如下:先为特定 SA 指定命名空间,分别询问 can-i get secretscan-i create pods;再结合准入策略与 SA 选择范围,检查它能创建怎样的 Pod;最后确认所创建工作负载挂载了哪些数据。can-i --list 只是起点,并不能完整解释所有外部授权和准入结果。必须同时查看实际请求与失败原因。

即使关闭服务账户的自动令牌挂载,Pod 中明确指定的设置仍可能优先。修改该选项不会立即改变所有正在运行的 Pod,应确认影响并通过新 Pod 应用。是否不需要令牌,与是否不需要 Secret,必须分别判断。

还要区分 401 与 403。允许匿名认证的路径中,无凭据请求可能作为 system:anonymous 用户和 system:unauthenticated 组处理。因此,匿名请求不一定总是 401;结果会随各路径的匿名许可、无效凭据与授权结论而变化。不能只看到 403 就断定已经通过了哪些准入控制,应同时确认响应原因和审计记录。

下一项实验要做什么

用合成 Secret 确认静态存储加密和重写,再在应用了 Restricted 的 app 中,比较 runner 创建的非 root Pod 所读取 Secret 文件的哈希。不要输出真实秘密值。把 API 直接查询被拒绝、Pod 创建成功、Secret 卷读取成功分别记录为独立证据,然后确认认证边界与不含正文的审计日志。该 VM 是教学用单节点环境,不能把结果扩大解释为其他租户或整个生产集群的安全保证。

通过官方文档继续确认