土法炼钢 · 系统与基础设施

【kube-apiserver】Authorization 与 Audit:RBAC、SAR 与 403 分列

文章导航

分类入口
kubernetesdistributed
标签入口
#kubernetes#apiserver#rbac#authorization#audit#subjectaccessreview#v1.30.3

目录

第 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.gounionAuthzHandler 串联多个 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 访问与其节点直接关联的资源:

这防止了一个 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:
  - RequestReceived

5.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


六、403 与 etcd 权限的分列

一句话K8s 用户收到的 403 永远来自 K8s 授权链(RBAC/Node/Webhook),从不来自 etcd 的权限控制。

原因:

  1. apiserver 与 etcd 之间用 mTLS client 证书认证(--etcd-certfile / --etcd-keyfile)。etcd v3 auth 若未启用,etcd 对 apiserver 的连接完全开放;etcd v3 auth 若启用,认证失败表现为 apiserver 无法完成 etcd gRPC 调用,结果是 apiserver 返回 500/503,而不是 403。
  2. 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

排障口令:


七、谱系与开放问题

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)

论文 / 规范(A/B)

站内对照

实验台账


上一篇Authentication:SA、Bearer、OIDC 边界

下一篇APF 与 max-in-flight:公平排队、504 与 etcd lag 分列

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。


By .