2. API请求生命周期:认证、授权、准入控制、资源持久化流程

Kubernetes API Server 是集群所有操作的唯一入口。每个 API 请求从到达 API Server 到最终写入 etcd,会依次经过四个核心阶段:认证(Authentication)、授权(Authorization)、准入控制(Admission Control)、资源持久化(Persistence)。理解这个生命周期是掌握 K8s 事务边界与一致性设计的基础。

核心原则:API Server 采用“先认证、再授权、后准入、最后持久化”的严格流水线顺序。任一阶段拒绝,请求立即终止,不会进入后续阶段。

2.1 请求生命周期全景图

下图展示了 API 请求从客户端发起至 etcd 持久化的完整路径,以及各阶段的关键组件与拦截点。

API 请求生命周期全景图 ① 认证 Authentication ② 授权 Authorization ③ 准入控制 Admission Control ④ 持久化 Persistence 认证模块链 • X.509 客户端证书 • Bearer Token • 静态密码文件 • OpenID Connect • Webhook 令牌认证 授权模块链 • ABAC • RBAC(推荐) • Node 授权 • Webhook 授权 • AlwaysDeny / Allow 准入控制器链 • 变更(Mutating) • 验证(Validating) • NamespaceLifecycle • ResourceQuota • PodSecurity etcd 存储 • 序列化 • 版本号校验 • 乐观锁 • 事务提交 • Watch 通知 任一阶段拒绝 → 立即返回 HTTP 错误(401/403/422) 不写入 etcd,不产生资源版本变更 全部通过 → 资源持久化 → 返回 200/201/202 触发 Watch 事件,通知所有监听该资源的客户端
关键理解:认证阶段确定“你是谁”,授权阶段确定“你能做什么”,准入控制阶段确定“你做的请求是否合规”,持久化阶段将最终状态写入 etcd。前三个阶段都是“校验”,只有最后一个阶段是“写入”。

2.2 认证(Authentication)

认证是请求生命周期的第一道关卡。API Server 通过配置的认证模块链依次尝试验证请求携带的身份信息。只要有一个模块认证成功,请求即进入下一阶段;如果所有模块都失败,返回 401 Unauthorized。

2.2.1 认证模块对比

认证方式 身份载体 适用场景 安全等级
X.509 客户端证书 TLS 证书中的 CN/O kubelet、kube-controller-manager 等组件间通信 高
Bearer Token(静态) HTTP Header: Authorization: Bearer <token> ServiceAccount 自动挂载的令牌 中
OpenID Connect (OIDC) JWT 令牌(由外部 IdP 签发) 企业 SSO、云平台 IAM 集成 高
Webhook Token 远程认证服务验证令牌 自定义认证后端 中高
静态密码文件 CSV 文件中的用户名:密码 仅用于测试或遗留系统 低
安全提示:静态密码文件认证方式已不推荐在生产环境使用。K8s 1.24+ 默认不再自动生成永久 ServiceAccount Secret,推荐使用 TokenRequest API 获取绑定 Pod 生命周期的临时令牌。

2.2.2 认证链执行逻辑

API Server 启动时通过 --authentication-token-webhook-config-file、--oidc-issuer-url 等参数配置认证模块。认证链的执行顺序是固定的:

  1. X.509 客户端证书认证 — 检查 TLS 连接中的客户端证书,提取 CN 作为用户名,O 作为组。
  2. 静态令牌认证 — 匹配 --token-auth-file 指定的 CSV 文件。
  3. Bootstrap 令牌认证 — 用于集群初始化阶段的节点加入。
  4. ServiceAccount 令牌认证 — 验证 JWT 签名,提取 ServiceAccount 身份。
  5. OIDC 认证 — 验证 JWT 的签名、issuer、audience。
  6. Webhook 令牌认证 — 将令牌发送给外部服务验证。
  7. 匿名请求 — 如果启用了 --anonymous-auth=true,未认证请求被映射为 system:anonymous 用户。
# API Server 启动参数示例(认证相关)
kube-apiserver \
  --client-ca-file=/etc/kubernetes/pki/ca.crt \
  --token-auth-file=/etc/kubernetes/token.csv \
  --service-account-key-file=/etc/kubernetes/pki/sa.pub \
  --oidc-issuer-url=https://accounts.google.com \
  --oidc-client-id=kubernetes \
  --authentication-token-webhook-config-file=/etc/kubernetes/webhook-auth.yaml \
  --anonymous-auth=true

2.3 授权(Authorization)

认证通过后,API Server 提取请求的 用户、组、操作(verb)、资源(resource)、命名空间(namespace) 等属性,发送给授权模块链进行决策。授权模块按配置顺序依次评估,第一个返回 Allow 或 Deny 的模块决定结果。

2.3.1 授权模式对比

授权模式 策略定义方式 粒度 推荐度
RBAC Role / ClusterRole + RoleBinding / ClusterRoleBinding API 组级别、资源级别、非资源 URL ★★★★★
ABAC JSON 策略文件(每行一个策略对象) 属性级(用户、资源、命名空间) ★★☆☆☆
Node 自动由 kubelet 身份触发 仅限 kubelet 对自身节点资源的读写 内置使用
Webhook 外部 HTTP 服务返回 allow/deny 完全自定义 ★★★★☆
AlwaysDeny / AlwaysAllow 无策略 全局 仅测试

2.3.2 RBAC 授权决策流程

RBAC 是生产环境最常用的授权模式。其决策过程如下:

  1. 提取请求中的 user、group、verb(get/list/create/update/delete/...)、resource、namespace。
  2. 查找该用户所属的所有 RoleBinding 和 ClusterRoleBinding。
  3. 收集绑定的 Role 或 ClusterRole 中定义的规则(rules)。
  4. 逐条规则匹配:如果 verb、resource、namespace 全部匹配,则返回 Allow。
  5. 如果所有规则都不匹配,返回 Deny(403 Forbidden)。
# RBAC 示例:授予用户 dev-user 在 default 命名空间对 Pod 的读写权限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list", "create", "update", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-user-pod-binding
  namespace: default
subjects:
- kind: User
  name: dev-user
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

2.4 准入控制(Admission Control)

准入控制是请求持久化之前的最后一道校验关卡。与认证和授权不同,准入控制器可以 修改(Mutate) 请求对象,也可以 验证(Validate) 请求对象的合规性。准入控制器分为两类:

  • 变更准入控制器(Mutating Admission Controller):在对象持久化之前修改请求内容,例如注入 Sidecar、设置默认值、添加标签。
  • 验证准入控制器(Validating Admission Controller):检查对象是否符合集群策略,例如资源配额、Pod 安全标准、网络策略。
执行顺序:所有变更准入控制器先执行,然后所有验证准入控制器执行。如果变更控制器修改了对象,验证控制器看到的是修改后的版本。

2.4.1 常用准入控制器

控制器名称 类型 功能
NamespaceLifecycle 验证 拒绝在正在删除的命名空间中创建新资源
ResourceQuota 验证 检查命名空间资源配额是否超限
LimitRanger 变更 + 验证 为未设置资源限制的 Pod 设置默认值
PodSecurity 验证 强制执行 Pod 安全标准(基线/受限)
MutatingAdmissionWebhook 变更 调用外部 Webhook 修改对象
ValidatingAdmissionWebhook 验证 调用外部 Webhook 验证对象
DefaultStorageClass 变更 为未指定 StorageClass 的 PVC 添加默认 StorageClass
NodeRestriction 验证 限制 kubelet 只能修改自身节点和绑定的 Pod

2.4.2 动态准入 Webhook

K8s 1.9+ 引入了动态准入控制机制,允许集群管理员通过 MutatingWebhookConfiguration 和 ValidatingWebhookConfiguration 注册外部 Webhook 服务。这是实现自定义策略、安全扫描、配置注入的标准方式。

# ValidatingWebhookConfiguration 示例
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: pod-policy-validator
webhooks:
- name: pod-policy.example.com
  clientConfig:
    service:
      name: admission-webhook
      namespace: default
      path: /validate
    caBundle: <base64-encoded-ca-cert>
  rules:
  - operations: ["CREATE", "UPDATE"]
    apiGroups: [""]
    apiVersions: ["v1"]
    resources: ["pods"]
  admissionReviewVersions: ["v1"]
  sideEffects: None
  timeoutSeconds: 5
性能与可靠性:Webhook 超时默认 10 秒,如果 Webhook 服务不可用或响应超时,默认行为是 失败(Failure Policy: Fail),会导致整个集群的创建/更新操作被阻塞。生产环境建议设置合理的超时、重试和降级策略。

2.5 资源持久化(Persistence)

当请求通过认证、授权和准入控制后,API Server 将对象序列化并写入 etcd。持久化阶段涉及以下关键步骤:

  1. 序列化:将 Go 对象转换为 protobuf 或 JSON 格式(默认使用 protobuf 以提高性能)。
  2. 版本号校验:对于更新操作,检查请求中的 resourceVersion 是否与 etcd 中当前版本一致(乐观锁机制)。
  3. etcd 事务写入:使用 etcd 的 Txn 接口保证原子性写入,同时更新资源版本号。
  4. Watch 事件通知:写入成功后,API Server 向所有 Watch 该资源的客户端发送事件通知(ADDED/MODIFIED/DELETED)。
  5. 返回响应:向客户端返回 HTTP 200(更新)、201(创建)或 202(异步操作),响应体中包含完整的对象及其最新的 resourceVersion。

2.5.1 乐观锁与资源版本

K8s 使用 乐观并发控制(Optimistic Concurrency Control) 来避免写冲突。每个资源对象都有一个 metadata.resourceVersion 字段,它是一个单调递增的字符串(实际是 etcd 的 revision 号)。

  • 创建操作:不携带 resourceVersion,etcd 自动分配新版本。
  • 更新操作:必须携带当前 resourceVersion。如果 etcd 中的版本号与请求中的版本号不一致,返回 409 Conflict,客户端需要重新获取最新版本后重试。
  • 删除操作:可以携带 resourceVersion 实现“精确删除”,也可以不携带(强制删除)。
# 更新操作示例:携带 resourceVersion
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  resourceVersion: "12345"  # 必须与 etcd 当前版本一致
data:
  key: value
事务边界:K8s 的每个 API 请求(create/update/delete)在 etcd 层面是一个独立的事务。但跨多个资源的操作(例如创建 Deployment 及其 ReplicaSet)不是原子事务——如果中间步骤失败,已创建的资源不会自动回滚。这是 K8s 事务边界设计的重要约束,后续章节会深入讨论。

2.6 请求生命周期总结

下表汇总了 API 请求各阶段的输入、输出、失败响应及关键特性:

阶段 输入 输出 失败 HTTP 状态码 关键特性
认证 HTTP 请求(TLS 证书/Token/密码) 用户身份(UserInfo) 401 Unauthorized 模块链短路执行
授权 用户身份 + 请求属性(verb/resource/ns) Allow / Deny 决策 403 Forbidden RBAC 最常用,支持自定义 Webhook
准入控制 请求对象(可能已被 Mutating Webhook 修改) 修改后的对象 / 拒绝原因 422 Unprocessable Entity 先变更后验证,支持动态 Webhook
持久化 最终对象 + resourceVersion etcd 写入 + Watch 通知 409 Conflict(版本冲突) 乐观锁,单资源原子性