第
10 篇
确认了请求的身份(user.Info)。本篇接着回答:这个身份被允许执行这个操作吗?——这是
Authorization 轴的职责。最常见的混淆是把 403 归因到 etcd
权限,或把 Admission 拒绝(500)误判为 RBAC
问题。本篇分列这三条路径,并钉 Audit
策略与授权失败在日志中的落格。
本篇在系列中的位置
篇目 核心内容 第 10 篇 · Authentication 认证链、SA token、401 边界 第 11 篇 · Authorization 与 Audit RBAC、SAR、403 分列、Audit 四级 第 12 篇 · APF 公平排队、504 与 etcd lag 分列 系列目录 五轴、阅读路径
版本锚定:Kubernetes v1.30.3(tag
v1.30.3)。授权链实现见staging/src/k8s.io/apiserver/pkg/authorization/;RBAC 见plugin/pkg/auth/authorizer/rbac/;Audit 见staging/src/k8s.io/apiserver/pkg/audit/。无真实集群则不粘贴伪造 RBAC 错误日志或 audit event。
一、授权链结构
staging/src/k8s.io/apiserver/pkg/authorization/union/union.go
的 unionAuthzHandler 串联多个
Authorizer,任一返回 Allow 即允许,全部返回
Deny/NoOpinion 则拒绝(403):
flowchart LR
req["Authenticated Request (user.Info + resource + verb)"]
req --> node["Node Authorizer"]
node -- "Allow" --> admitted["Admitted → Admission 链"]
node -- "Deny/NoOpinion" --> rbac["RBAC Authorizer"]
rbac -- "Allow" --> admitted
rbac -- "Deny/NoOpinion" --> webhook["Webhook Authorizer(若配置)"]
webhook -- "Allow" --> admitted
webhook -- "Deny/NoOpinion" --> forbidden["403 Forbidden"]
ABAC(基于属性的访问控制)在 v1.30 中仍保留 flag
--authorization-mode=ABAC,但需重启 apiserver
才能更新策略文件,生产集群实际已弃用;下文不展开 ABAC。
二、Node Authorizer
plugin/pkg/auth/authorizer/node/
实现。专为 kubelet 设计,仅对
system:nodes group 下的
system:node:<nodeName> 用户生效。
Node Authorizer 只允许 kubelet 访问与其节点直接关联的资源:
- 读取本节点上调度的 Pod
定义(
GET pods) - 读取 Pod 引用的 ConfigMap、Secret(限绑定到本节点)
- 读/写 Node 对象(仅本节点)
- 写 NodeStatus、PodStatus
这防止了一个 kubelet 读取任意节点的 Secret,是 K8s
最小权限模型的核心之一。Node Authorizer 依赖
NodeRestriction Admission
插件一起工作:Admission 层额外检查 kubelet
写入的字段是否在允许范围内。
三、RBAC Authorizer
plugin/pkg/auth/authorizer/rbac/rbac.go
是生产集群的主要授权路径。RBAC 是纯 Allow
模型:不存在明确 Deny
规则;资源的任何访问,只要没有 Allow rule
覆盖,都默认拒绝。
核心对象:
| 对象 | 作用域 | 说明 |
|---|---|---|
ClusterRole |
集群级 | 定义动词+资源+apiGroup 规则 |
Role |
Namespace 级 | 同上,作用域限定在一个 Namespace |
ClusterRoleBinding |
集群级 | 将 ClusterRole 绑定给 user/group/SA(集群范围) |
RoleBinding |
Namespace 级 | 将 ClusterRole 或 Role 绑定给 user/group/SA(ns 范围) |
RoleBinding 可以引用
ClusterRole:此时 ClusterRole 定义的规则仅在该
RoleBinding 所在的 Namespace 内生效。
RBAC Authorizer 在每次请求时查询
ClusterRole/Role/Binding 对象,v1.30 apiserver 内部有 RBAC
rule
cache(staging/src/k8s.io/apiserver/pkg/authorization/
相关路径)。apiserver 重启不会清空 etcd 中的 RBAC
对象,但修改 RBAC 对象后无需重启
apiserver(这是与 ABAC 的根本区别)。
Aggregated ClusterRole
aggregationRule 字段允许 ClusterRole
自动聚合多个带特定 label 的 ClusterRole 规则,用于扩展
admin/edit/view
等内置角色。CRD 默认为 cluster.local 下的资源创建对应的
aggregated ClusterRole。
四、SubjectAccessReview 与 SelfSubjectAccessReview
authorization.k8s.io/v1 API
提供两种访问检查接口,底层都走 RBAC/Node/Webhook Authorizer
链,不额外绕过:
SubjectAccessReview(SAR):由有权限的调用者(通常是控制器或
operator)检查任意 user/SA 的权限。POST 到
/apis/authorization.k8s.io/v1/subjectaccessreviews:
apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
user: "alice"
groups: ["system:authenticated"]
resourceAttributes:
namespace: default
verb: get
resource: pods返回 status.allowed(布尔)与
status.reason。
SelfSubjectAccessReview(SSAR):只能检查当前认证用户自己的权限,不需要额外
RBAC
授权。kubectl auth can-i get pods -n default
本质上是向
/apis/authorization.k8s.io/v1/selfsubjectaccessreviews
POST 一个 SSAR。status.allowed 为 false
时,status.reason 字段由 Authorizer 填写(RBAC
会给出 rule 级别的说明,Webhook Authorizer
给出的说明依赖外部实现)。
LocalSubjectAccessReview:Namespace-scoped,等同于带命名空间范围的 SAR,返回结果等价。
SAR/SSAR 可用于 operator 在 reconcile 前确认所需权限是否就绪,属于 Guard pattern——先检查权限,避免 Reconcile 死循环。
五、Audit:策略与落格
Audit 独立于 Authorization:认证成功但 AuthZ 拒绝(403)、Admission 拒绝(500/422)、以及成功的请求,均可被 Audit 记录。
5.1 Policy 四个级别
Audit Policy(--audit-policy-file 指向的
YAML)对每个规则指定 level:
| Level | 记录内容 | 适用场景 |
|---|---|---|
None |
不记录 | 噪音高、无诊断价值的请求(如 leader election) |
Metadata |
请求元数据(user、verb、resource、ns、状态码) | 默认最低代价记录 |
Request |
Metadata + 请求 body | 需要看入参的场景(如 ConfigMap 写入内容) |
RequestResponse |
Metadata + 请求 body + 响应 body | 排查细节,代价高,慎用于高频资源 |
Policy 规则按 rules
列表从上到下匹配,第一个匹配生效:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: None
users: ["system:kube-proxy"]
verbs: ["watch"]
resources:
- group: ""
resources: ["endpoints", "services", "services/status"]
- level: RequestResponse
resources:
- group: ""
resources: ["secrets", "configmaps"]
- level: Metadata
omitStages:
- RequestReceived5.2 Audit 阶段(Stage)
每次请求最多产生 4 个阶段的 Audit event:
| Stage | 含义 |
|---|---|
RequestReceived |
apiserver 收到请求但尚未处理 |
ResponseStarted |
开始写响应头(streaming 请求如 Watch) |
ResponseComplete |
响应完成(status code 已知) |
Panic |
apiserver panic(内部错误) |
实际排障常用 ResponseComplete stage,此时
responseStatus.code 已有值(200/403/500
等)。
5.3 Backend
--audit-log-path:写本地文件;可配合--audit-log-maxage、--audit-log-maxbackup、--audit-log-maxsize轮转。--audit-webhook-config-file:批量 POST 到外部 HTTP 接收器(如 Fluentd/Falco);批次大小与重试由相关 batch 参数控制。
六、403 与 etcd 权限的分列
一句话:K8s 用户收到的 403 永远来自 K8s 授权链(RBAC/Node/Webhook),从不来自 etcd 的权限控制。
原因:
- apiserver 与 etcd 之间用 mTLS client
证书认证(
--etcd-certfile/--etcd-keyfile)。etcd v3 auth 若未启用,etcd 对 apiserver 的连接完全开放;etcd v3 auth 若启用,认证失败表现为 apiserver 无法完成 etcd gRPC 调用,结果是 apiserver 返回 500/503,而不是 403。 - etcd 没有 K8s user/namespace 概念;它只看到 apiserver 的 TLS 证书与 etcd user(若启用 etcd auth)。
| 返回码 | 落格 | 不是 |
|---|---|---|
| 403 | K8s RBAC/Node/Webhook Authorizer 拒绝 | etcd 权限 |
| 500 | apiserver 内部错误(含 etcd 错误传播) | 用户 RBAC 问题 |
| 503 | etcd 不可达或 webhook 不可用 | RBAC miss |
排障口令:
- 看 Audit log 中
responseStatus.code=403+user:目标 user 到底是谁? - 看
status.reason:RBAC 会写"pods \"mypod\" is forbidden: User \"alice\" cannot get resource \"pods\" in API group \"\" in the namespace \"default\""。 kubectl auth can-i get pods -n default --as alice验证 RBAC 规则是否生效(内部走 SSAR)。- 若 403 发生在 kubelet 访问路径,先检查 Node
Authorizer(
system:node:格式 user + 节点资源关联)。
七、谱系与开放问题
NIST RBAC 模型(Ferraiolo & Kuhn, NIST 1992)→ Role + Assignment + Permission
→ K8s RBAC:纯 Allow(无 Deny)+ 聚合 ClusterRole
→ 仍开放:K8s RBAC 无 Deny 规则(不同于 AWS IAM Deny),复杂场景需靠 Admission 层补充限制
开放问题:K8s RBAC 缺乏 Explicit
Deny 语义(与 AWS IAM/OPA Rego
对比)——要拒绝某个角色对某个资源的访问,只能收紧
Binding,而无法覆盖更宽的规则。生产中常见
cluster-admin
授权过宽但无法精细吊销的场景,需靠 Admission Webhook 或
OPA/Kyverno 补充细粒度拒绝。Webhook Authorizer 支持 Deny
语义,但外部调用的延迟与可用性风险与 Admission Webhook
相同。
本篇不写什么:OPA/Gatekeeper/Kyverno
全书;Keycloak/LDAP group 同步;伪造
kubectl get clusterrolebindings 截图;etcd v3
auth 配置全书(仅在 etcd/14 操作门列举)。
参考资料
规范 / 源码(A)
- Kubernetes v1.30.3(tag
v1.30.3):staging/src/k8s.io/apiserver/pkg/authorization/union/union.goplugin/pkg/auth/authorizer/rbac/rbac.goplugin/pkg/auth/authorizer/node/node_authorizer.gostaging/src/k8s.io/apiserver/pkg/audit/
- K8s · Authorization(v1.30)
- K8s · Auditing(v1.30)
论文 / 规范(A/B)
- Ferraiolo & Kuhn, Role-Based Access Controls, NIST 1992(RBAC 模型奠基)
- NIST SP 800-207 · Zero Trust Architecture(AuthZ 设计背景)
站内对照
实验台账
- 无集群实测;无伪造 RBAC 错误日志或 audit event。
上一篇:Authentication:SA、Bearer、OIDC 边界
下一篇:APF 与 max-in-flight:公平排队、504 与 etcd lag 分列
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【kube-apiserver】控制面全景:缺口、五轴坐标系与 16 篇路线
相对 etcd/13、distributed/50、k8s-network 补齐 kube-apiserver 生产内核缺口;以 Storage/Watch/Admission/Auth/APF 五轴为坐标系定义 16 篇阅读路线;版本锚定 Kubernetes v1.30.3。
【kube-apiserver】进程与请求路径:generic apiserver、HandlerChain 与 REST 路由
拆解 kube-apiserver 进程模型与 generic apiserver 框架;钉 HandlerChain 各插槽顺序与失败落点;说明 GVR 路由机制与请求在到达 storage 前可能被拦截的位置。版本锚定 Kubernetes v1.30.3。
【kube-apiserver】storage.Interface 与 etcd3:codec、prefix 与 CRUD 路径
拆解 kube-apiserver 的 storage.Interface 契约与 etcd3 实现:codec 序列化、pathPrefix/resourcePrefix、value.Transformer 加密边界、GuaranteedUpdate 乐观并发,以及 Watch 到 etcd3 的完整路径。版本锚定 Kubernetes v1.30.3 / etcd v3.5.33。
【kube-apiserver】resourceVersion 与 Revision 映射:mod revision、continue 与一致性读期望
钉 Kubernetes resourceVersion 字段与 etcd mod revision 的对应关系;分析 continue token 的分页语义与成本;说明不同 List 路径的一致性期望差异;以及 410 Gone 与 ErrCompacted 的分列。版本锚定 Kubernetes v1.30.3 / etcd v3.5.33。