系统设计 / 访问控制 · 从 RBAC 查表到 policy 判定函数 / 基础设施层:Kubernetes RBAC 与 POSIX 权限位 待审核 23 / 23
实例 · k8s / POSIX

基础设施层: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(扮演另一个身份)、bindescalate 两个专门约束权限管理动作的 verb。默认情况下,一个人不能创建出权限超过自己的 Role,除非他持有 escalate治理 §2 那条「继承边带来意外提权」被 API server 直接拦在了创建那一步。

注 · resourceNames 能把规则收窄到具体几个对象名,这是 k8s 唯一的对象级授权手段,但它对 listwatch 无效(按名字过滤不了集合),对 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 三档,每档 rwxchmod 644 写成 -rw-r--r--。这套模型有一个容易记错的地方:判定不取三档的并集,而是按 owner → group → other 的顺序找第一个匹配的身份,只用那一档,缺位也不回落。

图 3-1 · 九个权限位与某个身份实际拿到的能力。可单击切换位、切换对象类型与访问者身份,并观察 umask 折算出的新建 mode。

注 · 「命中即终止」可以直接实测: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 · 两套系统映回四元组

表 5-1 · 两套基础设施权限系统的四个轴。
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 · 参考文献

  1. The Kubernetes Authors. Using RBAC Authorization. Role 与 RoleBinding 的字段语义、verb 清单、escalatebind 的提权防护,以及 resourceNames 的适用范围。kubernetes.io
  2. Apple Inc. chmod(1) macOS man page. +a / +a# 的 ACL 语法与 canonical location 的措辞。
  3. 本系列。决策与组合算法。additive-only 与 first-applicable 各自对应哪一种裁决。