每一次 kubectl apply 都要依次通过三道关卡:认证(Authentication,验证你是谁)、授权(Authorization,判定你能否对这个资源执行这个动作)、准入(Admission,对提交内容做最后的修改或否决)。本节逐关拆解,并给出生产可用的 RBAC 最小权限配置。
声明抵达 API Server 后并不会直接入账,2.1 节的窗口只是前台,窗口后面还有三道安检。这一节是集群安全的入口章:读懂三道关卡,403 报错、权限设计、准入副作用这三类日常问题就都有了坐标系。更深的密钥管理话题留待第7章运行安全时展开。
先给三道关卡一张总览表,记住它们各自回答的问题与失败时的报错特征:
| 关卡 | 回答的问题 | 典型机制 | 失败时的表现 |
|---|---|---|---|
| 认证 | 你是谁 | 客户端证书、令牌、kubeconfig | 401,匿名身份被拒 |
| 授权 | 你能做什么 | RBAC 的 Role 与 RoleBinding | 403,指出缺哪个动词 |
| 准入 | 这次提交要不要改 | 变异准入与校验准入插件 | 422 或声明被静默修订 |
顺序不可颠倒:先有身份才谈权限,先有权限才轮到内容审查。三道全过,声明才获得入账资格。

kubectl 的身份来自 kubeconfig 文件里的凭证——通常是一张客户端证书。证书里的 CN 字段就是你的用户名,O 字段是组名:
# 查看当前生效的身份与上下文 kubectl config get-contexts # CURRENT NAME CLUSTER AUTHINFO NAMESPACE # * prod-ctx prod alice production # 模拟查看自己的身份(权限模拟,需要管理员预先授权) kubectl auth whoami # Attribute: Username # Value: alice
身份只是入场券,权限由 RBAC 决定。RBAC 的核心是两份 YAML 的组合:Role 说"在这个空间里,哪些动词可以作用于哪些资源";RoleBinding 说"把这些能力授予谁"。给平台组配一个生产空间的只读角色:
apiVersion: rbac.authorization.k8s.io/v1 kind: Role # 命名空间级的权限范围 metadata: name: orders-reader namespace: production rules: - apiGroups: ["", "apps"] # 空串代表核心组,apps 是应用组 resources: ["pods", "pods/log", "deployments"] verbs: ["get", "list", "watch"] # 只读三件套,不含 create/update/delete --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding # 把角色与用户缝合 metadata: name: read-orders namespace: production subjects: - kind: User name: alice # 授权对象:用户 alice roleRef: kind: Role name: orders-reader apiGroup: rbac.authorization.k8s.io
申请了只读权限的人试图改副本数,会被关卡二拦下,报错信息相当体贴:
kubectl scale deployment orders-api --replicas=5 -n production # Error from server (Forbidden): deployments.apps "orders-api" is forbidden: # User "alice" cannot update resource "deployments" in API group "apps" # in the namespace "production"
报错把缺的三要素全说出来了:谁(alice)、缺哪个动词(update)、在哪个空间(production)。读 403 的套路固定:从报错里反查该补哪条规则,而不是盲目给人绑 cluster-admin。
⚠️ 常见坑:为了省事把同事都绑成 cluster-admin(全集群超级权限)。一旦某个人的 kubeconfig 泄露,攻击者等于拿到整个集群。最小权限原则在 Kubernetes 里是可执行的,RoleBinding 精确到 verbs 与 resources。
过了授权,声明的内容还要被准入控制器审一遍。准入分两类,先变异、后校验,都通过才落账。常见的守门动作:
变异准入的效果可以直接观察。提交一个没写资源限制的 Pod,然后看入账后的它:
# 提交前先问一声:如果通过全部安检,最终入账的对象长什么样 kubectl apply -f bare-pod.yaml --dry-run=server -o yaml | grep -A6 resources: # resources: # limits: # cpu: "1" # memory: 1Gi # 这两行不是我写的,是变异准入补的 # requests: # cpu: 500m # memory: 512Mi
dry-run 配合 -o yaml 是观察准入改写的最佳姿势:你提交的 YAML 与集群记住的 YAML 可能有差异,差异就来自这双看不见的手。第6章讲 ConfigMap 注入、第7章讲安全基线时,都会与准入插件打交道。
背景:新同事 bob 要参与订单服务的日常观测,需要能看 Pod、日志与事件,但不能改动任何东西。
操作:三步走——签发身份(由集群管理员配 kubeconfig)、套用 2.2 节的 Role、绑定时把 subjects 换成 bob,随后用模拟命令验证权限边界:
# 不切换身份,直接模拟 bob 能否执行两个动作 kubectl auth can-i get pods -n production --as bob # yes kubectl auth can-i delete pods -n production --as bob # no # 两行输出就是权限设计的验收单
结果:bob 的所有读操作畅通,任何写操作在关卡二被拒,报错格式与前面 alice 的完全一致。
解读:认证解决"进门",授权解决"能碰哪些东西",两者解耦意味着同一个身份在不同空间可以有完全不同的权限画像。can-i 模拟是发布权限变更前的标准自检,比"配完让用户试"体面得多。
变式:CI 流水线需要部署权限时,把 subjects 的 kind 换成 ServiceAccount,授权对象从人变成服务账号,权限边界更清晰;跨空间的权限(如平台组要看所有空间)则用 ClusterRole 配合 RoleBinding,规则复用而范围仍受控。
声明过了三关、即将落账。下一节看它落入的这本账——etcd 为什么是唯一真相源,以及 Watch 广播如何让调度器和控制器在秒级知晓新声明的到来。