2. API Server 请求流程:认证、鉴权、准入控制三个阶段详解
Kubernetes API Server 是集群所有操作的唯一入口。任何对集群状态的查询或变更请求,在到达 etcd 持久化存储之前,都必须依次通过三个严格的拦截阶段:认证(Authentication)、鉴权(Authorization) 和 准入控制(Admission Control)。理解这三个阶段的职责、顺序和交互方式,是构建安全、可靠的后端服务的基础。
2.1 三阶段总览与职责划分
下表清晰对比了三个阶段的核心职责、输入输出与典型组件:
| 阶段 | 核心职责 | 输入 | 输出 | 典型组件 |
|---|---|---|---|---|
| 认证 | 验证“你是谁?” | HTTP 请求(证书、Token、Basic Auth) | 用户名、UID、用户组 | X.509 证书、Service Account、OIDC、Webhook Token |
| 鉴权 | 验证“你能做什么?” | 用户身份 + 请求动作(资源、命名空间、操作) | 允许 / 拒绝 | RBAC、ABAC、Node Authorization、Webhook |
| 准入控制 | 验证“请求是否符合集群策略?” | 经过鉴权的请求对象 | 修改 / 拒绝 / 通过 | MutatingWebhookConfiguration、ValidatingWebhookConfiguration、内置插件(如 NamespaceLifecycle) |
2.2 第一阶段:认证(Authentication)
认证阶段是请求进入 API Server 的第一道防线。API Server 会依次尝试配置的所有认证模块,只要有一个模块认证成功,请求即进入下一阶段。如果所有模块都认证失败,则返回 401 Unauthorized 错误。
常见的认证方式包括:
- X.509 客户端证书: 通过 TLS 握手时提供的客户端证书中的 CN(Common Name)和 O(Organization)字段提取用户名和组。这是最常用的组件间认证方式。
- Service Account Token: Pod 内挂载的 JWT Token,用于 Pod 与 API Server 交互。Token 中包含了 Service Account 的身份信息。
- 静态 Token / 密码文件: 通过 CSV 文件预定义 Token 或密码与用户的映射关系,适用于测试或简单场景。
- OpenID Connect (OIDC): 集成外部身份提供商(如 Keycloak、Azure AD),实现单点登录。
- Webhook Token 认证: 将 Token 验证委托给外部认证服务。
401 状态码和 Unauthorized 消息。后端服务在捕获 401 错误时,应检查客户端证书是否过期、Token 是否有效或是否被吊销。
2.3 第二阶段:鉴权(Authorization)
请求通过认证后,API Server 会提取用户的身份信息(用户名、组、UID),并连同请求的详细信息(资源类型、命名空间、操作动词)发送给鉴权模块。鉴权模块决定该用户是否有权限执行该操作。
Kubernetes 支持多种鉴权模式,通常以 RBAC(基于角色的访问控制) 为主:
- RBAC: 通过
Role/ClusterRole定义权限集合,再通过RoleBinding/ClusterRoleBinding将角色绑定到用户或组。这是生产环境的标准选择。 - ABAC(基于属性的访问控制): 通过 JSON 策略文件定义权限,灵活性高但管理复杂,已逐渐被 RBAC 取代。
- Node Authorization: 专门为 kubelet 设计的鉴权模式,允许节点访问其自身相关的资源。
- Webhook: 将鉴权决策委托给外部服务,适用于自定义复杂的鉴权逻辑。
鉴权失败时,API Server 返回 403 Forbidden 错误,并在响应体中包含详细的拒绝原因,例如 User "system:serviceaccount:default:my-sa" cannot list resource "pods" in API group "" in the namespace "default"。
403 错误时,应记录详细的错误信息,用于审计和权限调整。
2.4 第三阶段:准入控制(Admission Control)
准入控制是请求到达 etcd 前的最后一道关卡。它由一系列准入控制器(Admission Controller) 组成,这些控制器可以验证(Validating) 或修改(Mutating) 请求对象。Mutating 控制器先执行,Validating 控制器后执行。
准入控制器的类型:
- 内置准入控制器: 如
NamespaceLifecycle(防止在删除中的命名空间创建资源)、LimitRanger(设置默认资源限制)、ResourceQuota(强制执行资源配额)。 - 动态准入控制(Webhook): 通过
MutatingWebhookConfiguration和ValidatingWebhookConfiguration将请求发送到外部 HTTP 服务进行处理。这是实现自定义策略(如镜像签名验证、Sidecar 注入)的核心机制。
准入控制失败时,API Server 返回 403 Forbidden 或 422 Unprocessable Entity,具体取决于控制器返回的错误类型。响应体中会包含控制器的名称和拒绝原因。
2.5 完整请求流程 SVG 图
下图展示了 API Server 处理一个 kubectl create pod 请求的完整三阶段流程:
2.6 错误处理与接口调用实践
后端服务在调用 API Server 时,必须根据不同的 HTTP 状态码采取相应的处理策略:
| HTTP 状态码 | 失败阶段 | 典型原因 | 后端处理建议 |
|---|---|---|---|
| 401 Unauthorized | 认证 | Token 过期、证书无效、Token 被吊销 | 刷新 Token 或重新获取客户端证书;记录审计日志 |
| 403 Forbidden | 鉴权 / 准入控制 | RBAC 权限不足、资源配额超限、Webhook 拒绝 | 检查 Service Account 权限;查看 Webhook 日志;调整资源配额 |
| 422 Unprocessable Entity | 准入控制 | ValidatingWebhook 拒绝(如镜像签名验证失败) | 解析响应体中的 message 字段,获取具体拒绝原因 |
| 429 Too Many Requests | API Server 流控 | 请求速率超过 API Server 配置的 QPS 限制 | 实现指数退避重试机制;增加客户端 QPS 配置 |
errors.IsForbidden()、errors.IsUnauthorized() 等工具函数进行类型判断,而不是直接比较状态码字符串。
import (
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// 创建 Pod 并处理错误
pod, err := clientset.CoreV1().Pods("default").Create(ctx, podObj, metav1.CreateOptions{})
if err != nil {
if errors.IsUnauthorized(err) {
// 处理认证失败:刷新 Token
} else if errors.IsForbidden(err) {
// 处理鉴权或准入控制失败:记录详细错误
log.Printf("Forbidden: %v", err)
} else if errors.IsTooManyRequests(err) {
// 处理限流:等待后重试
time.Sleep(time.Duration(1) * time.Second)
} else {
// 处理其他错误
}
}
2.7 三阶段交互细节 SVG 图
下图展示了认证、鉴权、准入控制三个阶段内部更详细的交互流程,包括多认证模块的尝试顺序和动态准入 Webhook 的调用:
2.7 总结
API Server 的三阶段请求处理流程是 Kubernetes 安全架构的基石。后端开发人员必须深刻理解每个阶段的职责、失败时的错误码以及对应的处理策略。在实际开发中,应充分利用 RBAC 的最小权限原则、合理配置动态准入 Webhook,并在代码中实现健壮的错误重试和日志记录机制,以确保后端服务与 Kubernetes 集群的稳定、安全交互。