2. API请求生命周期:认证、授权、准入控制、资源持久化流程
Kubernetes API Server 是集群所有操作的唯一入口。每个 API 请求从到达 API Server 到最终写入 etcd,会依次经过四个核心阶段:认证(Authentication)、授权(Authorization)、准入控制(Admission Control)、资源持久化(Persistence)。理解这个生命周期是掌握 K8s 事务边界与一致性设计的基础。
2.1 请求生命周期全景图
下图展示了 API 请求从客户端发起至 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 文件中的用户名:密码 | 仅用于测试或遗留系统 | 低 |
TokenRequest API 获取绑定 Pod 生命周期的临时令牌。
2.2.2 认证链执行逻辑
API Server 启动时通过 --authentication-token-webhook-config-file、--oidc-issuer-url 等参数配置认证模块。认证链的执行顺序是固定的:
- X.509 客户端证书认证 — 检查 TLS 连接中的客户端证书,提取 CN 作为用户名,O 作为组。
- 静态令牌认证 — 匹配
--token-auth-file指定的 CSV 文件。 - Bootstrap 令牌认证 — 用于集群初始化阶段的节点加入。
- ServiceAccount 令牌认证 — 验证 JWT 签名,提取 ServiceAccount 身份。
- OIDC 认证 — 验证 JWT 的签名、issuer、audience。
- Webhook 令牌认证 — 将令牌发送给外部服务验证。
- 匿名请求 — 如果启用了
--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 是生产环境最常用的授权模式。其决策过程如下:
- 提取请求中的
user、group、verb(get/list/create/update/delete/...)、resource、namespace。 - 查找该用户所属的所有 RoleBinding 和 ClusterRoleBinding。
- 收集绑定的 Role 或 ClusterRole 中定义的规则(rules)。
- 逐条规则匹配:如果 verb、resource、namespace 全部匹配,则返回 Allow。
- 如果所有规则都不匹配,返回 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
2.5 资源持久化(Persistence)
当请求通过认证、授权和准入控制后,API Server 将对象序列化并写入 etcd。持久化阶段涉及以下关键步骤:
- 序列化:将 Go 对象转换为 protobuf 或 JSON 格式(默认使用 protobuf 以提高性能)。
- 版本号校验:对于更新操作,检查请求中的
resourceVersion是否与 etcd 中当前版本一致(乐观锁机制)。 - etcd 事务写入:使用 etcd 的 Txn 接口保证原子性写入,同时更新资源版本号。
- Watch 事件通知:写入成功后,API Server 向所有 Watch 该资源的客户端发送事件通知(ADDED/MODIFIED/DELETED)。
- 返回响应:向客户端返回 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
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(版本冲突) | 乐观锁,单资源原子性 |