如果把 Kubernetes 集群比作一座现代化的办公楼,那么 RBAC 就是这栋楼的门禁系统。想象一下:普通员工只能刷开自己工位的楼层闸机,运维工程师能进入服务器机房,保洁阿姨只能进入公共区域——每个人手里的门禁卡都写入了与岗位匹配的权限。在 K8s 的世界里,用户和 ServiceAccount 就是员工,Role 就是岗位说明书,RoleBinding 就是 HR 的绑定记录。没有这套门禁系统,任何人都能进出所有房间,集群安全将形同虚设。这篇文章会从“门禁系统”的视角,带你逐步理解 RBAC 的四大核心组件、权限规则的写法、ServiceAccount 的身份机制,以及如何落地最小化授权和审计合规。你将学会像安全主管一样,给每个角色发放恰到好处的门禁权限。

岗位关联

对 AI 从业者而言,掌握 RBAC 意味着你能在真实生产环境中安全地管理 K8s 集群权限,避免因配置不当导致的越权与安全事故——这是云原生工程师的核心竞争力之一。

目录
  1. 可视化演示
  2. RBAC基础认知
  3. Role与ClusterRole
  4. RoleBinding绑定
  5. ServiceAccount
  6. 权限规则语法
  7. 最小化授权
  8. 审计与合规
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

演示K8s基于角色的访问控制:Role/ClusterRole与RoleBinding/ClusterRoleBinding的授权链路,展示角色与资源动词的权限矩阵,并模拟最小权限与审计检查流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

RBAC 授权闭环 Role/ClusterRole:定义权限集合 RoleBinding:绑定主体 最小权限:按需授权 verbs×resources 构成授权策略

RBAC基础认知

一家大型公司的门禁系统里,安全主管不会为每位员工单独设置开门规则——那样太容易出错。他的做法是先把员工划分成角色(普通员工、部门经理、IT运维),再为每个角色配置岗位权限。RBAC(Role-Based Access Control,基于角色的访问控制)正是这一哲学在 Kubernetes 中的完整落地:通过角色中转,让权限分配变得可维护、可扩展。

在 K8s 集群中,RBAC 通过“主体→绑定→角色→规则”四层结构控制访问。主体(Subject)是发起请求的对象,可以是用户(User)、组(Group)或服务账户(ServiceAccount);绑定(Binding)充当连接器,将角色赋予主体;角色(Role)则封装了一组具体的权限规则。这四个组件协作,构成了集群的授权决策链路。

K8s 的授权决策发生在 API Server 层。每个请求到达后,认证模块先确认“你是谁”,随后授权模块遍历与该主体绑定的所有角色,逐一匹配规则中的动作与资源。只要有一个角色允许该操作,请求就被放行。如果没有任何角色匹配,请求将被拒绝并返回 Forbidden。

回到门禁系统的场景:保安查到你拥有“IT 运维岗”的门禁卡(绑定),就能刷开机房门(资源),即使你同时也是“普通员工”(另一个绑定),也不影响你进入机房——这也正是 RBAC 中任何一个角色匹配就放行的设计逻辑。

Access(s,v,r)=⋁b∈Bindings(s)Match(b.role,v,r)Access(s, v, r) = \bigvee_{b \in Bindings(s)} Match(b.role, v, r)
该公式表示:主体 \(s\) 对资源 \(r\) 执行操作 \(v\) 的权限,等于其所有绑定角色匹配结果的逻辑或——任何一个角色放行即可。
  1. 主体 \(s\)发起访问请求的对象,代表用户、服务账户或用户组。
    s∈{User, ServiceAccount, Group}s \in \{User,\ ServiceAccount,\ Group\}
  2. 操作 \(v\) 与资源 \(r\)被访问的具体动作与目标对象,如 get、delete 操作作用于 pods、deployments。
    v∈Verbs,r∈Resourcesv \in Verbs,\quad r \in Resources
  3. 绑定集合主体 \(s\) 的全部角色绑定关系,可能来自 RoleBinding 或 ClusterRoleBinding。
    Bindings(s)={b∣b.subject=s}Bindings(s) = \{b \mid b.subject = s\}
  4. 匹配判定只要存在一个绑定使角色规则与 \((v, r)\) 匹配,权限即成立。
    Match(b.role,v,r)=∃rule∈b.role: v∈rule.verbs∧r∈rule.resourcesMatch(b.role, v, r) = \exists rule \in b.role:\ v \in rule.verbs \land r \in rule.resources

Role与ClusterRole

门禁卡有“楼层卡”和“全楼卡”之分:楼层卡只能刷开指定楼层的房门,全楼卡则能进出整栋办公楼的所有房间。Role 和 ClusterRole 就是这两种门禁权限模板。它们在规则书写语法上完全一致,真正的区别在于作用范围。

Role 定义在某个命名空间(Namespace)内,只对该命名空间内的资源生效。例如,为 dev 命名空间创建的 Role 只允许读取 dev 下的 Pod,对其他命名空间没有任何影响。ClusterRole 则属于集群级别,可以访问集群级资源(如 Node、PersistentVolume),也可以在所有命名空间中生效,是跨 namespace 授权的关键工具。

在 YAML 中,Role 和 ClusterRole 的规则结构相同,都包含 apiGroups、resources、verbs 三个核心字段。K8s 的 RBAC 引擎会用这些字段逐一匹配请求。需要注意的是,ClusterRole 本身不能直接“使用”,它必须通过 RoleBinding 或 ClusterRoleBinding 绑定到主体后才能授予权限。

你可以把 Role 理解为“三层财务室门禁卡”,把 ClusterRole 理解为“全楼机房万能卡”。运维工程师需要访问整栋楼的网络设备时,就发一张 ClusterRole 门禁卡;而某个项目组只需要管理自己的空间时,Role 就足够。这种分层设计,让权限管理既灵活又安全。

Rule={apiGroups:[g1,…,gn], resources:[r1,…,rn], verbs:[v1,…,vn]}Rule = \{apiGroups: [g_1, \ldots, g_n],\ resources: [r_1, \ldots, r_n],\ verbs: [v_1, \ldots, v_n]\}
一条规则声明了该角色可以在哪些 API 组中对哪些资源执行哪些操作,三者共同构成权限判断依据。
  1. apiGroups 字段声明资源所属的 API 组,空字符串 "" 代表核心组 v1。
    g∈{apps, batch, networking.k8s.io, "", …}g \in \{apps,\ batch,\ networking.k8s.io,\ "",\ \ldots\}
  2. resources 字段列举目标资源类型,如 Pod、Deployment、Service、Node 等。
    r∈{pods, deployments, services, nodes, …}r \in \{pods,\ deployments,\ services,\ nodes,\ \ldots\}
  3. verbs 字段声明允许的操作动词集合,对应 HTTP 动作语义。
    v∈{get, list, watch, create, update, patch, delete}v \in \{get,\ list,\ watch,\ create,\ update,\ patch,\ delete\}
  4. 作用域语义Role 仅限单个命名空间,ClusterRole 面向整个集群。
    Scope(Role)=Namespace,Scope(ClusterRole)=ClusterScope(Role) = Namespace,\quad Scope(ClusterRole) = Cluster

RoleBinding绑定

有了门禁卡模板(Role),还需要把卡发到具体人手里,这个“发卡”动作就是 RoleBinding。它像一个连接器,把主体(谁)和角色(拥有哪些权限)绑定在一起。如果员工离职,HR 只需要销毁绑定记录,门禁权限立刻失效——不必重新设计门禁规则。

RoleBinding 在命名空间内绑定 Role 或 ClusterRole。一个常见的场景是:管理员创建一个 pod-reader 角色,再把 ServiceAccount app-bot 绑定到该角色。此后该 SA 发起的请求就拥有了读取 Pod 的权限。ClusterRoleBinding 则用于在集群范围内授权,通常将用户绑定到具有集群级管理权限的角色,如 cluster-admin。

K8s 支持一个主体同时拥有多个绑定,最终权限是这些角色权限的并集。这也就意味着,如果一个用户被绑定到了 view 角色,同时又被绑定到 edit 角色,他既拥有只读权限,也拥有修改权限——权限取并集而非交集。

回到门禁的例子:如果你同时持有“技术部员工卡”和“机房维护卡”,那么你既拥有技术部办公区的通行权,又拥有机房进入权。HR 的绑定记录在 RBAC 里就是那一张张“卡片发放记录”,它们是权限得以生效的桥梁。

EffectivePerm(s)=⋃b∈Bindings(s)Perm(b.role)EffectivePerm(s) = \bigcup_{b \in Bindings(s)} Perm(b.role)
主体的有效权限是其所有绑定角色权限的并集——任何一个角色拥有的权限,最终都会累积到该主体身上。
  1. 绑定集合主体 \(s\) 对应的所有 RoleBinding 与 ClusterRoleBinding。
    Bindings(s)={b1, b2, …, bn}Bindings(s) = \{b_1,\ b_2,\ \ldots,\ b_n\}
  2. 角色权限提取每个绑定都对应一个角色对象,提取其全部规则。
    Perm(b.role)={rule1, rule2, …, rulem}Perm(b.role) = \{rule_1,\ rule_2,\ \ldots,\ rule_m\}
  3. 权限合并将全部绑定角色的权限规则做并集运算。
    ⋃b∈Bindings(s)Perm(b.role)=Perm1∪Perm2∪⋯∪Permn\bigcup_{b \in Bindings(s)} Perm(b.role) = Perm_1 \cup Perm_2 \cup \cdots \cup Perm_n

ServiceAccount

办公楼里除了正式员工,还有临时访客和外包人员,他们需要一张“访客卡”才能进出。Kubernetes 中的 ServiceAccount(服务账户,简称 SA)就相当于 Pod 的访客卡——它是 Pod 内进程与 API Server 通信时使用的身份凭证。

每个命名空间创建时都会自动生成一个名为 default 的 ServiceAccount。如果 Pod 没有显式指定 spec.serviceAccountName,系统会自动挂载 default SA 的 Token,并使用它的身份访问 API。这意味着,如果管理员给 default 绑定了过大的权限,那么所有未指定 SA 的 Pod 都将携带这个高风险身份。

因此,实践中的安全配置要求是:为每个工作负载创建专用 SA,并通过 RoleBinding 绑定最小权限。同时,可以通过 automountServiceAccountToken: false 关闭自动挂载,避免不需要访问 API 的 Pod 暴露 Token。SA 是 RBAC 体系中最常见的“主体”,也是权限控制的关键入口。

把 ServiceAccount 类比为访客卡会更容易理解:访客卡上写明了“你可以进入哪几间会议室”。同样,SA 的 Token 里携带了身份信息,K8s 会依据这个身份去查询绑定关系,最终决定 Pod 发出的请求是否被放行。

Identity(pod)=SA(pod.spec.serviceAccountName)Identity(pod) = SA(pod.spec.serviceAccountName)
Pod 的身份由其 spec.serviceAccountName 字段决定的 ServiceAccount 提供;若不指定则使用默认 SA。
  1. SA 身份选择Pod 通过字段显式或隐式指定使用的服务账户。
    Identity(Pod)=SA(spec.serviceAccountName)Identity(Pod) = SA(spec.serviceAccountName)
  2. 默认 SA 规则未显式指定时,系统自动使用命名空间内的 default SA。
    SAdefault={token, ca.crt, namespace}SA_{default} = \{token,\ ca.crt,\ namespace\}
  3. 身份映射该 SA 就是 RBAC 授权时的主体标识。
    Subject(kube−apiserver)=SAname+SAnamespaceSubject(kube-apiserver) = SA_{name} + SA_{namespace}

权限规则语法

门禁系统的每条规则都像一句“准入条款”:允许哪些人、进哪扇门、做什么动作。RBAC 权限规则的语法同样精炼,一条规则由 apiGroups、resources、verbs 三个核心字段,以及可选的 resourceNames 字段构成。掌握了这四个字段,就能读懂任何一份 Role 清单。

apiGroups 指定 API 组,"" 代表核心组,apps 对应 Deployment 等应用资源;resources 指定资源类型;verbs 指定操作动词。当 resources 或 verbs 使用 ["*"] 时,表示匹配所有资源或所有动作——这种通配符写法固然方便,但也隐藏着巨大的越权风险。

resourceNames 是最后一道精细控制手段,它可以将权限限定到指定的具名资源上。例如,只允许 get 名为 mysql-pod 的特定 Pod。这种“白名单”式的写法在最小权限实践中非常实用。K8s 的 RBAC 引擎对规则的匹配采用“存在即允许”策略:只要请求的 verb、resource、resourceName 同时命中规则列表中的任意一项,授权即通过。

规则语法就像门禁系统里的“准入条款”。条款写得越具体,门禁就越安全;如果规则写成 apiGroups: ["*"], resources: ["*"], verbs: ["*"],等于发了一张万能卡,任何房间都能进——在生产环境中应当极力避免。

Allow(v,r,n)=(v∈Vrule∨v=∗)∧(r∈Rrule∨r=∗)∧(n∈Nrule∨Nrule=∅)Allow(v, r, n) = (v \in V_{rule} \lor v = \ast) \land (r \in R_{rule} \lor r = \ast) \land (n \in N_{rule} \lor N_{rule} = \emptyset)
允许的条件是操作、资源、资源名三类条件全部命中;如果规则未限定资源名,则资源名条件恒为真。
  1. 操作匹配请求的动词必须出现在规则的 verbs 列表中,或 verbs 含通配符。
    v∈Vrule∨v=∗v \in V_{rule} \lor v = \ast
  2. 资源匹配请求的资源类型必须出现在规则的 resources 列表中,或含通配符。
    r∈Rrule∨r=∗r \in R_{rule} \lor r = \ast
  3. 资源名匹配若规则存在 resourceNames,请求的资源名必须在其中;未限定则为通配。
    n∈Nrule∨Nrule=∅n \in N_{rule} \lor N_{rule} = \emptyset

最小化授权

安全主管永远遵循一个原则:给员工恰好够用的门禁权限,多一分不需要,少一分则影响工作。这就是最小化授权(Least Privilege)。在 K8s 中,最小化授权要求每个角色只配备完成工作所必需的资源与动词,杜绝“顺手多给”的权限。

实践中,最小化授权通过三条路径落地:一是逐个角色收紧 verbs,只保留 get、list、watch 等必要读取动词,而不给 delete、create;二是利用 resourceNames 限定只能操作特定资源;三是通过命名空间隔离,让不同团队各居一隅,互不干涉。K8s 内置的角色(如 view、edit)虽方便,但往往不够“紧”,按需自定义角色才是最佳实践。

相比之下,常见的反面案例是将用户直接绑定到 cluster-admin 内置角色。cluster-admin 拥有集群一切资源的全部操作权限,一旦凭据泄露,攻击者可以窃取整个集群。最小化授权不仅是安全规范,更是生产事故的第一道防线。

回到门禁场景:给快递员只发“一楼前台”的门禁权限,而不是整栋楼的万能卡。即便出了安全问题,攻击者能造成的破坏也是有限的。最小化授权不是限制效率,而是把风险控制在可控半径内。

Pleast=arg⁡min⁡P∈P∣P∣s.t.P⊇PrequiredP_{least} = \arg\min_{P \in \mathcal{P}} |P| \quad \text{s.t.} \quad P \supseteq P_{required}
最小权限集是在满足任务需求(包含全部必需权限)的前提下,权限数量最少的那一组。
  1. 权限集合空间\(\mathcal{P}\) 是所有可能授权策略的集合。
    P={P1,P2,…,Pk}\mathcal{P} = \{P_1, P_2, \ldots, P_k\}
  2. 需求约束选择的权限集必须涵盖完成工作所需的全部权限。
    P⊇PrequiredP \supseteq P_{required}
  3. 最小化目标在满足约束的所有权限集中,选出数量最少的一个。
    ∣Pleast∣=min⁡P∈P, P⊇Prequired∣P∣|P_{least}| = \min_{P \in \mathcal{P},\ P \supseteq P_{required}} |P|

审计与合规

安全主管不仅要设置门禁,还要每天检查门禁记录,看看有没有异常进出。K8s 的审计(Audit)机制与此类似,它会记录所有对 API Server 的请求,包括谁在什么时间对什么资源做了什么操作、最终是允许还是拒绝。

审计日志是权限安全的重要数据源。通过分析拒绝记录,可以发现权限不足的配置错误;通过分析放行记录,可以识别异常行为。合规检查则更进一步:定期扫描集群中的 Role/Binding 配置,检查是否存在过度授权的角色、是否有人绑定了高风险角色、是否关闭了不必要的 SA Token 挂载。

安全扫描工具(如 kubeaudit、kube-bench)可以自动化执行合规检查。它们会检查集群的 RBAC 配置、内置角色的使用情况、ServiceAccount 的权限范围等,并输出风险报告。在生产环境中,审计日志的保留与合规扫描的周期性执行,是安全运营的必备动作。

门禁记录让安全主管能随时调出“昨晚谁在什么时间进了机房”这样的信息。K8s 的审计日志就是同样意义上的“门禁回放系统”,它在安全事故发生时提供第一手证据,也为权限优化提供数据支撑。

AuditLog(e)={timestamp, user, verb, resource, namespace, decision}AuditLog(e) = \{timestamp,\ user,\ verb,\ resource,\ namespace,\ decision\}
一条审计记录包含请求的完整上下文:何时、谁、对什么资源、发起了什么操作、结果如何。
  1. 时间戳字段记录请求到达的具体时间,用于追溯与时间窗口分析。
    timestamp∈R≥0timestamp \in \mathbb{R}_{\geq 0}
  2. 主体字段记录发起请求的用户或 ServiceAccount 标识。
    user=identity(e)user = identity(e)
  3. 操作与资源记录请求的动词、资源类型及命名空间,构成行为描述。
    (verb, resource, namespace)=target(e)(verb,\ resource,\ namespace) = target(e)
  4. 决策结果API Server 对该请求的授权结论,允许或拒绝。
    decision∈{Allow, Deny}decision \in \{Allow,\ Deny\}

AI 应用场景

云原生平台团队权限治理

阶段:数据与模型部署阶段的平台安全治理

解决的问题:AI 平台的模型训练、推理服务通常部署在同一个 K8s 集群中,不同算法团队、运维团队之间存在越权风险。传统做法是“大家共用 cluster-admin 账号”,一旦凭据泄露会波及全集群。通过 RBAC,平台团队可以为每个算法组创建独立命名空间,并绑定只读/写入各自命名空间的 Role,实现“各管各的地盘”。

具体案例:某 AI 团队在训练大模型时,允许数据标注组只能 get、list 标注数据的 ConfigMap,而模型训练组可以 create、update Pod 和 Job。通过 ClusterRoleBinding 将平台管理员限定在集群运维命名空间,彻底隔离算法与运维权限。

CI/CD 流水线的 ServiceAccount 隔离

阶段:模型自动训练与发布流水线(CI/CD)执行阶段

解决的问题:CI/CD 流水线(如 Jenkins、GitLab CI)中的自动化任务通常通过 ServiceAccount 与集群交互。如果直接使用集群管理 SA,流水线的任一步被攻破都会导致整个集群沦陷。通过为每条流水线创建独立 SA 并绑定最小权限角色,可以限制流水线只能操作指定命名空间的特定资源。

具体案例:某公司的 AI 模型发布流水线创建了 ml-pipeline SA,仅绑定到 ml-prod 命名空间的 deployment-operator 角色,允许 get/update Deployment 和 Service,但不允许删除操作。即使流水线脚本被注入恶意代码,攻击者也无法破坏集群核心组件。

多租户 SaaS 平台租户隔离

阶段:AI 平台对外提供多租户服务时的权限隔离

解决的问题:当 AI 能力以 SaaS 形式对外输出时,不同客户的模型和推理资源存放在同一个集群中,客户之间的数据必须严格隔离。RBAC 的命名空间级 Role 天然适合多租户场景——每个租户一个命名空间、一个专属 SA 和 RoleBinding。

具体案例:某 AI 开放平台为每个企业租户创建 tenant-xxx 命名空间,并绑定 tenant-user Role,限制只能读取本租户的模型配置与日志,无法访问其他租户的数据。审计日志同时记录每次跨租户访问尝试,确保租户数据零泄漏。

Python 演示

python80 行
class RBACManager:    def __init__(self):        self.roles = {}        self.bindings = []        self.audit_log = []     def create_role(self, name, namespace, rules):        role = {"name": name, "namespace": namespace, "rules": rules}        self.roles[(namespace, name)] = role        return role     def bind_role(self, user, role_name, namespace):        self.bindings.append({"user": user, "role": role_name, "namespace": namespace})     def check_permission(self, user, verb, resource, namespace):        for b in self.bindings:            if b["user"] != user or b["namespace"] != namespace:                continue            role = self.roles.get((namespace, b["role"]))            if not role:                continue            for rule in role["rules"]:                verbs = rule.get("verbs", [])                resources = rule.get("resources", [])                if verb in verbs or "*" in verbs:                    if resource in resources or "*" in resources:                        self.audit_log.append({                            "user": user, "verb": verb, "resource": resource,                            "namespace": namespace, "decision": "allow"                        })                        return True        self.audit_log.append({            "user": user, "verb": verb, "resource": resource,            "namespace": namespace, "decision": "deny"        })        return False     def get_effective_permissions(self, user, namespace):        perms = set()        for b in self.bindings:            if b["user"] != user or b["namespace"] != namespace:                continue            role = self.roles.get((namespace, b["role"]))            if not role:                continue            for rule in role["rules"]:                for v in rule.get("verbs", []):                    for r in rule.get("resources", []):                        perms.add((v, r))        return perms  if __name__ == "__main__":    rbac = RBACManager()    # 定义 pod-reader 角色: 只允许读取 pods    rbac.create_role("pod-reader", "dev", [        {"verbs": ["get", "list", "watch"], "resources": ["pods"]}    ])    # 定义 pod-editor 角色: 可对 pods 做写操作    rbac.create_role("pod-editor", "dev", [        {"verbs": ["create", "update", "delete"], "resources": ["pods"]}    ])    # 绑定角色    rbac.bind_role("alice", "pod-reader", "dev")    rbac.bind_role("alice", "pod-editor", "dev")    rbac.bind_role("bob", "pod-reader", "dev")     # 验证权限    print("alice get pods  ->", rbac.check_permission("alice", "get", "pods", "dev"))    print("alice delete pods ->", rbac.check_permission("alice", "delete", "pods", "dev"))    print("bob delete pods ->", rbac.check_permission("bob", "delete", "pods", "dev"))    print("alice access prod namespace ->", rbac.check_permission("alice", "get", "pods", "prod"))     # 查看 alice 在 dev 命名空间的所有权限    print("alice effective perms:", rbac.get_effective_permissions("alice", "dev"))     # 输出审计日志    print("--- audit log ---")    for entry in rbac.audit_log:        print(entry)
目的:用 Python 简版实现 RBAC 的“角色-绑定-权限检查”核心流程,对应 Kubernetes RBAC 的授权判定逻辑。
  1. self.roles[(namespace, name)] = role用元组作为键来存储角色,区分不同命名空间中同名角色,模拟 K8s 中 Role 与命名空间的绑定关系。
  2. def bind_role(self, user, role_name, namespace)记录“用户-角色-命名空间”三元绑定关系,相当于 kubectl create rolebinding 做的事。
  3. if verb in verbs or "*" in verbs检查操作动词是否在允许列表中,同时支持通配符语义,对应 RBAC 规则中的 verbs 匹配。
  4. if resource in resources or "*" in resources检查资源类型是否在允许列表中,对应 resources 匹配。
  5. rbac.check_permission("alice", "delete", "pods", "dev")这条调用验证了“并集”特性:alice 同时被绑定 read 和 edit 角色,因此具备删除权限。
  6. self.get_effective_permissions(user, namespace)汇总一个用户在某命名空间下的全部权限集合,视作权限审计的直观输出。
  7. for entry in rbac.audit_log打印每次授权判定的日志记录,模拟 K8s 审计日志的“谁在何时对什么做了什么”。

常见误区

误区“Role 和 ClusterRole 不都是权限模板吗?我随便用一个不就行了。”有些初学者在创建一个只需要访问单个命名空间资源的权限时,直接写了 ClusterRole,以为效果一样。

正解Role 的作用范围严格限制在单个命名空间,离开该命名空间就完全失效;ClusterRole 则作用于整个集群,不仅覆盖所有命名空间资源,还能访问 Node、PersistentVolume 等集群级资源。如果误把 Role 当作 ClusterRole 使用,权限会过小;反之则权限过大。打个比方:楼层卡只能刷一层楼,全楼卡能刷整栋楼——两者绝不能随意互换。

为何常见:两者的 YAML 字段几乎完全一致,初学者只看语法不看作用域,因此容易混淆。

误区“我建了 ClusterRole,再用 ClusterRoleBinding 绑定,那用户就能在所有命名空间里为所欲为了。”实际上很多人在 cluster-admin 权限泄漏事故后才意识到问题。

正解ClusterRoleBinding 确实能让权限在所有命名空间生效,但前提是绑定的 ClusterRole 里真的包含了足够宽泛的规则。如果你把一个只允许读 dev 命名空间的 ClusterRole 通过 ClusterRoleBinding 绑定到用户,用户也不会获得其他命名空间的访问权。权限的最终范围取决于“角色里写了什么”和“绑定方式如何作用”的组合。

为何常见:人们习惯性认为“集群级绑定 = 全权限”,而忽略了角色规则本身的限制。

误区“我写的 Pod 没指定 ServiceAccount,那它就没有身份,应该什么权限都没有吧?”这是对默认 SA 机制的误解。

正解每个命名空间都有一个默认的 default ServiceAccount,未指定 SA 的 Pod 会自动使用它并挂载对应 Token。如果管理员给 default 绑定了较高权限,那么所有“裸奔”的 Pod 都将继承这份权限。正确做法是为每个工作负载创建专用 SA 并绑定最小权限,必要时设置 automountServiceAccountToken: false 关闭自动挂载。

为何常见:K8s 的自动挂载机制偏“隐式”,新手看不到 Pod 里多出的 Token 文件,自然意识不到身份已经存在。

误区“把所有 resources 和 verbs 都写成 `*` 不是更省事吗?以后加什么资源都不用改。”一些开发者为图省事,直接套用全通配角色。

正解* 意味着对该维度的一切目标放行。apiGroups: ["*"], resources: ["*"], verbs: ["*"] 实际上就是内置的 cluster-admin 权限。一旦角色被绑定给某个被攻破的服务账户,攻击者就能删除集群中的所有资源。最小授权实践明确反对滥用通配符,要求按需枚举资源与动词。

为何常见:通配符写起来省事、读起来“短”,让人觉得它是精简配置的捷径,却忽略了它带来的权限面爆炸。

误区“配置好 RBAC 之后,集群安全就万事大吉了。”持此观点的人将权限控制等同于安全本身。

正解RBAC 只是授权环节的一层控制。它不负责认证(Authentication),也不处理网络安全策略(NetworkPolicy)、Pod 安全标准(PSS)或镜像安全。即使 RBAC 配置完美,如果容器以 root 运行、镜像存在漏洞、或者没有开审计日志,集群依然面临巨大风险。RBAC 是安全体系的重要支柱,但不是唯一支柱。

为何常见:RBAC 是入门者最常接触的 K8s 安全概念,容易让人产生“学了 RBAC 就掌握了 K8s 安全”的错觉。

面试题

Q1. RBAC 中,Role 和 ClusterRole 的主要区别是什么?

单选题 · easy

  • A.Role 用于小型集群中
  • B.Role 限单个命名空间← 正确答案
  • C.ClusterRole 要求配绑定
  • D.Role 不支持配置规则

答案:B。Role 是命名空间级别的资源,只对其所在命名空间内的资源生效;ClusterRole 是集群级别的角色,可作用于集群级资源和所有命名空间。选项 B 准确描述了 Role 的核心特性。A 说“小集群”显然不对,D 否定 Role 的规则配置能力也不成立,C 中 ClusterRole 确实需要绑定,但这不是它与 Role 的“主要区别”。

Q2. 以下哪个主体不能被 RoleBinding 直接绑定?

单选题 · mid

  • A.集群中的 User 账号
  • B.一个用户组 Group
  • C.命名空间 Namespace 本身← 正确答案
  • D.ServiceAccount 服务账户

答案:C。RoleBinding 的 subjects 字段允许绑定 User、Group 和 ServiceAccount 三类主体,唯独不能绑定 Namespace——命名空间是资源容器而不是身份对象,它无法“发起请求”。想象门禁系统里,你能给员工(User)、部门(Group)和访客卡(SA)授权,但不能给“楼层”授权。

Q3. 关于 ServiceAccount 的说法正确的有哪些?

多选题 · mid

  • A.每个命名空间会自动创建 default SA← 正确答案
  • B.Pod 可通过字段指定使用某 SA← 正确答案
  • C.SA 可以被 RoleBinding 正常绑定← 正确答案
  • D.SA 只能绑定集群级别权限

答案:ABC。每个命名空间创建时自动生成 default SA,Pod 通过 spec.serviceAccountName 显式指定 SA,SA 也能作为主体被 RoleBinding 绑定。D 错在 SA 同样可以绑定命名空间级 Role。类比访客卡,前台可以给访客发不同楼层的权限,而不是只能发全楼通卡。

Q4. 在 RBAC 规则中,哪个字段用来描述操作动作?

单选题 · easy

  • A.resources 字段
  • B.verbs 动词字段← 正确答案
  • C.apiGroups 组字段
  • D.resourceNames 名

答案:B。verbs 字段定义了允许的操作类型,如 get、list、create、delete。resources 表示资源对象,apiGroups 表示 API 组,resourceNames 限定具体资源名。可以把 verbs 理解为“能做什么动作”,把 resources 理解为“对什么东西做动作”。

Q5. 以下哪条命令用于创建集群级角色绑定?

单选题 · mid

  • A.kubectl create rolebinding
  • B.kubectl create clusterrolebinding← 正确答案
  • C.kubectl create clusterrole
  • D.kubectl create sa

答案:B。kubectl create clusterrolebinding 是创建集群级绑定的命令,将 ClusterRole 绑定到用户或 SA,权限全网生效。A 创建的是命名空间级绑定,C 创建的是集群角色模板但未做绑定,D 创建服务账户。一句话记忆:绑定命令里带 cluster 前缀的就是作用于全集群。

Q6. 最小授权原则的落地实践包括哪些?

多选题 · hard

  • A.只为角色配置必需的动词← 正确答案
  • B.用 resourceNames 限名← 正确答案
  • C.团队间命名空间隔离← 正确答案
  • D.直接绑定 cluster-admin

答案:ABC。最小授权要求权限尽量小:控制动词范围、用 resourceNames 规则限定具体资源、用命名空间隔离团队。D 完全违背最小授权——cluster-admin 拥有集群全部操作权限,是典型反例。相当于把万能卡发给了所有员工,一旦丢失后果不堪设想。

Q7. apiGroups 字段中空字符串 "" 表示什么?

单选题 · mid

  • A.匹配所有 APi 组
  • B.核心 API 组 v1← 正确答案
  • C.apps 扩展资源组
  • D.batch 批处理组

答案:B。在 K8s 的 API 组体系中,空字符串 "" 特指核心组 v1,它包含 Pod、Service、ConfigMap、Secret 等最基础的内置资源。而 apps 对应 Deployment、StatefulSet,batch 对应 Job、CronJob。想要表示“所有组”应写 ["*"],而不是空字符串。

Q8. 排查 RBAC 权限拒绝问题时,正确的做法有哪些?

多选题 · hard

  • A.用 kubectl auth can-i 验证← 正确答案
  • B.查看审计日志拒绝记录← 正确答案
  • C.检查角色绑定匹配关系← 正确答案
  • D.直接升级为管理员权限

答案:ABC。kubectl auth can-i 可以快速验证当前用户是否有权限执行操作;审计日志记录了请求被拒绝的详细信息;检查绑定关系能定位是角色没写对还是绑定没配上。D 是典型的“掩耳盗铃”——跳过问题而非解决问题,会让权限失控。

Q9. 当一个用户同时被绑定到多个角色时,其有效权限是?

单选题 · hard

  • A.多个角色的权限交集
  • B.多个角色的权限并集← 正确答案
  • C.最近绑定的角色生效
  • D.系统拒绝用户访问

答案:B。RBAC 的授权模型是“任一允许即放行”,有效权限等于所有绑定角色权限的并集。这与防火墙“默认拒绝、显式允许”的思路一致——只要任一角色允许该操作,请求就被放行。交集模型会限制权限,与 RBAC 的累加语义不符。

Q10. K8s 中认证(Authentication)与授权(Authorization)的关系是?

单选题 · extreme

  • A.认证先于授权被检查← 正确答案
  • B.授权先于认证被检查
  • C.两者同时并行执行
  • D.认证通过后直接放行

答案:A。API Server 处理请求时,首先执行认证模块确认“你是谁”,拿到身份信息后才交给授权模块判定“你能做什么”。认证失败直接拒绝,根本不会进入授权阶段。这就像门禁系统先刷脸(认证)确认身份,再判断你的门禁卡权限等级(授权)——顺序颠倒则一切无从谈起。