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

💡 原文中文,约7800字,阅读约需19分钟。
📝

内容提要

本文介绍Kubernetes v1.30.3的授权与审计机制。授权链依次为Node、RBAC、Webhook Authorizer,任一允许即放行,否则返回403。RBAC为纯Allow模型,无显式Deny规则。SAR/SSAR接口用于权限检查。Audit分四级记录请求,403仅来自K8s授权链,非etcd权限。排障需查Audit日志和status.reason。

🔎

延伸解读

403 的真正来源

很多 Kubernetes 用户遇到 403 时,第一反应是 etcd 权限问题,但本文明确指出:K8s 用户收到的 403 永远来自 K8s 授权链(Node、RBAC、Webhook),而不是 etcd。etcd 的权限控制(如果启用)失败时,apiserver 返回的是 500 或 503,而不是 403。理解这一点,可以避免在排障时走弯路,直接聚焦于 RBAC 规则和 Audit 日志。

RBAC 的纯 Allow 模型

K8s RBAC 是纯 Allow 模型,没有显式 Deny 规则。这意味着任何未被 Allow 规则覆盖的访问都会被默认拒绝。这种设计简化了权限管理,但也带来一个局限:无法直接表达“拒绝某个角色对某资源的访问”,只能通过收紧绑定或借助 Admission Webhook、OPA 等外部机制实现。生产环境中常见的 cluster-admin 权限过宽问题,正是这一模型的典型痛点。

Audit 日志的排障价值

当遇到 403 时,Audit 日志是定位问题的关键。通过查看 responseStatus.code=403 的 Audit event,可以确认请求的用户、资源、动词和命名空间,再结合 status.reason 字段(RBAC 会给出具体规则说明),就能快速判断是 RBAC 规则缺失还是 Node Authorizer 限制。此外,kubectl auth can-i 命令(内部走 SSAR)也是验证权限的有效工具。

Q&A

Kubernetes 中 403 Forbidden 错误通常由什么原因引起?

Kubernetes 中的 403 错误通常由授权链拒绝引起,即 Node、RBAC 或 Webhook Authorizer 均未允许该请求。etcd 权限问题不会导致 403,而是可能导致 500 或 503 错误。

Kubernetes RBAC 授权模型有什么特点?

Kubernetes RBAC 是纯 Allow 模型,没有显式的 Deny 规则。任何访问,只要没有 Allow 规则覆盖,默认拒绝。Role 和 ClusterRole 定义权限,RoleBinding 和 ClusterRoleBinding 将权限绑定到用户、组或服务账户。

如何检查某个用户是否有权限执行特定操作?

可以使用 kubectl auth can-i 命令,它内部通过 SelfSubjectAccessReview (SSAR) 检查当前用户的权限。也可以使用 SubjectAccessReview (SAR) 检查任意用户的权限,但需要相应的 RBAC 权限。

Kubernetes Audit 日志有哪几个级别?分别记录什么内容?

Audit 日志有四个级别:None(不记录)、Metadata(记录请求元数据,如用户、资源、状态码)、Request(记录元数据和请求体)、RequestResponse(记录元数据、请求体和响应体)。级别越高,记录的信息越详细,但开销也越大。

Node Authorizer 的作用是什么?

Node Authorizer 专门为 kubelet 设计,只允许 kubelet 访问与其节点直接关联的资源,例如读取本节点 Pod 定义、Pod 引用的 ConfigMap 和 Secret,以及读写本节点的 Node 对象和状态。这防止了 kubelet 读取任意节点的 Secret。

Kubernetes RBAC 与 ABAC 有什么区别?

RBAC 是 Kubernetes 中主要的授权机制,基于角色和绑定,支持动态更新,无需重启 apiserver。ABAC 是基于属性的访问控制,在 v1.30 中仍保留但已弃用,更新策略需要重启 apiserver,因此生产环境很少使用。

如何通过 Audit 日志排查 403 错误?

查看 Audit 日志中 responseStatus.code=403 的记录,关注 user 字段确认请求者身份,并查看 status.reason 字段获取拒绝原因。RBAC 会提供类似 'User "alice" cannot get resource "pods"' 的说明。

🏷️

标签

➡️

继续阅读