基础设施层:Kubernetes RBAC 与 POSIX 权限位
前几页的实例都在 web 一侧。把尺度换到基础设施层,同一个 decide 仍然成立,而且这两套系统的取舍与前面的页面正好互为对照:Kubernetes 砍掉了 deny,POSIX 砍掉了「取并集」。
1 · Kubernetes RBAC 的 verb 与 namespace
一条 k8s 权限规则由 apiGroup、resources、verbs 三段构成,与 Permission 的身份 的 module:resource:action 几乎逐段对应;绑定则由 RoleBinding 完成,把 subject 连到 Role 上。
# Role 只在自己的 namespace 里有效: namespace 就是 k8s 的租户边界
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: team-a
name: pod-reader
rules:
- apiGroups: [""] # 核心 API 组, pods 属于它
resources: ["pods"] # what
verbs: ["get", "list", "watch"] # action
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: team-a
name: alice-pod-reader
subjects: # who
- kind: User
name: alice
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
verbs 也不只有读写:get / list / watch / create / update / patch / delete / deletecollection 之外,还有 impersonate(扮演另一个身份)、bind 与 escalate 两个专门约束权限管理动作的 verb。默认情况下,一个人不能创建出权限超过自己的 Role,除非他持有
escalate:治理 §2 那条「继承边带来意外提权」被 API server 直接拦在了创建那一步。
注 · resourceNames 能把规则收窄到具体几个对象名,这是 k8s 唯一的对象级授权手段,但它对 list 与 watch 无效(按名字过滤不了集合),对 create 也无效(那一刻名字还不存在)。于是 k8s 里没有比 namespace 更细的数据范围:给了
list pods,本 namespace 的全部 pod 就都看得见。对照 AllowedScope 的五档,k8s 实际只有 Full(本 namespace)和按名点选两种形态。这一条据官方文档(核对于 2026-08)。
2 · additive-only:没有 deny 的判定
k8s RBAC 里不存在 deny 规则。判定就是把所有命中 binding 的权限求并集,任一条放行即放行,没有任何东西能把它减回去。这正是 决策与组合算法 的 permit-overrides 加 closed world:默认拒绝,规则只负责加。
代价是「除了某人以外」这类策略写不出来,只能靠拆 namespace、拆 Role 绕开。AWS IAM 走的是另一条路,用显式 Deny 做一票否决;两者的差别不在表达力强弱,而在可推理性——没有 deny 的系统里,一个人的权限等于他所有 binding 的并集,读完 binding 就能算准,不必再去搜有没有一条 deny 埋在别处。
3 · POSIX 权限位与命中即终止
文件权限是九个位:owner、group、other 三档,每档 rwx。chmod 644 写成 -rw-r--r--。这套模型有一个容易记错的地方:判定不取三档的并集,而是按 owner → group → other 的顺序找第一个匹配的身份,只用那一档,缺位也不回落。
注 · 「命中即终止」可以直接实测:chmod 077 得到 ----rwxrwx,文件主自己 cat 立刻拿到 Permission denied,尽管后两档写着 rwx。另一处不在九个位里的权限是「改权限」本身:chmod 000 之后文件主读不了,却照样能把 mode
改回去,这项权力来自 ownership,mode 位里没有它的位置(macOS 26.5 实测,核对于 2026-08)。
警示 · 目录的读位与执行位是两把不同的钥匙。chmod 400 的目录仍能列出条目名,但 ls 自己会报 fts_read: Permission denied(拿到了名字、stat 不到),读其中的文件直接得到
EACCES。缺了执行位,这个目录名下的一切元数据都取不到,而「能列出名字」这件事仍然成立——两种能力分属两个位,不能互相替代。
4 · ACL 的顺序即优先级
九个位表达不了「只给这两个人」,于是有了 ACL。macOS 的 ACE 按序编号,裁决走 first-applicable:把 allow read 插到 deny read 之前(chmod +a# 0),文件主读得到;两条交换位置,同一次读被拒。
值得注意的是 +a 不按书写顺序追加:先加 allow、再加 everyone deny read,列出来的顺序是 deny 在前、allow 在后,man page 称之为插入 canonical location,效果上等于替使用者把 deny 提前,让默认行为落回 deny-overrides。要真正拿到 allow 优先,必须用
+a# 指定位置(macOS 26.5 实测,核对于 2026-08)。
5 · 两套系统映回四元组
| 轴 | Kubernetes RBAC | POSIX 权限位 |
|---|---|---|
| who | RoleBinding 的 subject(User / Group / ServiceAccount) | 进程的 uid 与 gid 集合 |
| what | apiGroup + resource + namespace(+ resourceNames) |
inode 的 owner / group 与 mode 位 |
| action | verb | rwx 三位 |
| when/where | 无 | 无 |
| 组合算法 | 并集,无 deny | 命中的那一档说了算;ACL 走 ACE 顺序 |
两者都缺 when 这一轴。想按时间、来源网络或设备状态收紧,只能在外面另加一层:k8s 靠 admission webhook 或 ValidatingAdmissionPolicy,文件系统靠挂载选项与 PAM。这也解释了为什么这两套系统看起来比 XACML 与 IAM 简单——它们把情境判断整个推给了别人。
6 · 参考文献
- The Kubernetes Authors. Using RBAC Authorization. Role 与 RoleBinding 的字段语义、verb 清单、
escalate与bind的提权防护,以及resourceNames的适用范围。kubernetes.io - Apple Inc. chmod(1) macOS man page.
+a/+a#的 ACL 语法与 canonical location 的措辞。 - 本系列。决策与组合算法。additive-only 与
first-applicable各自对应哪一种裁决。