自助服务的围栏挡住的是什么
一句话总结
schema 管请求内容,RBAC 管主体权限,ResourceQuota 管 Namespace 上限。获准的请求仍可能被配额拒绝;查询失败也不是安全拒绝的证据。
为什么需要它
假设 blue-dev 的 Role 只有 AppClaim 读取与创建权限,但它仍能读取 Secret。不要立即断定 Role 应用错误,应查看同一主体关联的其他 binding。RBAC 权限会合并所有允许规则,从一个 Role 删除 verb 并不会撤销其他 Role 的允许,它不是 deny。
RoleBinding 也可引用 ClusterRole,此时权限只在该 RoleBinding 的 Namespace 内生效。不能只看 ClusterRole 名称就认定为全集群权限,必须看哪个 binding 以什么范围连接。参阅官方 RBAC 规则与绑定。
工作原理
区分权限查询和真实请求
kubectl auth can-i 查询 authorization 判定。“可以 create”不表示输入 schema 和 ResourceQuota 也会通过。最终行为应以该主体真实请求或安全的 server dry-run 验证。server dry-run 经过 API 验证路径但不保存对象,并不执行所有应用逻辑。参阅官方 API dry-run。
在练习管理员上下文可执行:
kubectl auth can-i get appclaims.platform.labhub.io \
-n tenant-blue --as=system:serviceaccount:tenant-blue:blue-dev
kubectl auth can-i patch appclaims.platform.labhub.io \
--subresource=status -n tenant-blue \
--as=system:serviceaccount:tenant-blue:blue-dev
普通用户不会自动获得对任意主体使用 --as 的权限。第二条若省略 --subresource=status,问的就是另一件事;把 status 写在 resource/name 的 name 位置也不等于查询子资源权限。参阅官方 can-i 用法。
本练习验证的 kubectl 中,明确允许输出 yes 并返回 0,明确拒绝输出 no 并返回 1。不能把空 stdout、认证错误、连接失败统统解释成“不是 yes,所以是 no”。应先用正常 get 作为对照,再准确判断拒绝;CLI 或鉴权方式变化时要重新确认输出格式。
分离 API 使用权限和策略管理权限
| 请求 | 本练习策略 | 原因 |
|---|---|---|
| AppClaim get·list·watch·create·update·patch | 允许 | 团队申请、观察、修改 |
| AppClaim status patch·update | 拒绝 | 分离用户与观测结果写入者 |
| quota create·patch | 拒绝 | 用户不能修改自己的上限 |
| Role·RoleBinding create | 拒绝 | 策略管理与自助 API 分离 |
| Secrets get、其他 Namespace AppClaim list | 拒绝 | 限制凭据与租户范围 |
| AppClaim delete | 拒绝 | 本练习采用运维回收策略 |
获得 Role 创建权限不等于立即能创建管理员权限。Kubernetes 会限制把自己没有的权限写入或绑定 Role;escalate 和 bind 是越过相关检查的特殊权限,应更谨慎。本练习不关闭该防御,同时把 Role 管理排除在租户业务之外。参阅官方权限提升防护。
通配符可能把未来新增资源也纳入权限。默认 edit 角色不能只凭名字判断安全,它可能影响 Secret 等资源。应以具体 API group、resource、verb 描述工作,并审查实际 binding。参阅官方 RBAC 最佳实践。
对象数量配额不测 CPU 或外部成本
count/appclaims.platform.labhub.io: "2" 只限制该类对象数量。一个 claim 即使创建十个外部数据库,也不会自动计算其成本。对象数限制用于防止控制面对象无限增长;工作量、成本、过期策略需另行设计。非 CRD 的 aggregation API 配额还要确认扩展 API server 的责任。参阅官方对象数配额。
诊断配额时要区分 spec.hard(期望上限)、status.hard(已应用上限)、status.used(观测用量)。没有用量字段不等于 0。参阅官方 ResourceQuota 字段。
若 used 为空,先检查 CRD Established、API discovery、真实 AppClaim 列表和 quota status,等待同步后重读;持续异常则由管理员调查控制器。exceeded quota、status unknown、Forbidden 和连接错误不是同一种失败。提高上限或删除 quota 不能代替诊断。
禁止删除不是 Kubernetes 的必然规则
本练习禁止租户 delete,由运维回收;实际平台也可允许用户删除,再由控制器通过 finalizer 清理外部资源。finalizer 不是执行代码,只是表示清理责任的键。删除请求设置 deletionTimestamp,控制器完成清理并移除 finalizer 后对象才删除。没有负责控制器,仅添加键不会执行清理。参阅官方 finalizer 行为。
现场表现
向旧评分器注入权限查询错误时,空响应也曾被当作“确认拒绝”。修复后要求同时存在正常 get 和明确 no。配额也要核对实际数量 2、上限 2、used 2,并确认第三次请求确实因 quota 失败。只记录“被拒绝”无法区分认证故障与正确策略。
下一步
下一练习会填写 blue-dev 的允许与拒绝清单,并分别检查 status 和其他 Namespace。quota 满后会通过两个 served 版本发送第三个 claim。最终报告只记录实际查询值,不能猜测无法读取的数据。