Kubernetes 基础体系 · 第 43/83 篇。示例基于 Kubernetes 当前稳定 API;弃用、版本偏差、云厂商差异和生产风险会明确说明。
Kubernetes 认证:证书、Token、OIDC、Webhook 和用户生命周期
Kubernetes 的“登录”不是一个独立的用户系统,而是 API Server 对每个请求执行的一组判断:
- 请求是否携带了某种可验证的凭据;
- 凭据验证后,对应的用户名和用户组是什么;
- 该身份是否有权执行目标操作;
- 请求是否还受到准入控制、审计和其他策略约束。
其中,**认证(Authentication)**回答“你是谁”,**授权(Authorization)**回答“你能做什么”。证书、Token、OIDC 和认证 Webhook 都属于认证机制;Role、ClusterRole 和各种 Binding 属于授权机制。认证成功并不意味着请求一定能执行。
可以把一次 API 请求抽象为:
其中:
- 是用户名;
- 是用户组集合;
extra是认证器可能附加的扩展属性;- 授权器根据请求动作、资源和这些身份属性作出判断。
例如,一个客户端使用客户端证书访问:
GET /api/v1/namespaces/dev/pods
Authorization: 通过客户端证书完成 TLS 认证
认证器可能得到:
username = alice
groups = [developers]
随后 RBAC 检查 alice 或 developers 是否拥有:
get pods -n dev
如果没有,即使证书完全有效,最终仍然会得到 403 Forbidden。
一次 Kubernetes API 请求经过哪些认证组件
通常客户端先通过 TLS 连接 API Server。API Server 可以配置多个认证器,例如:
- X.509 客户端证书;
- 静态 Token 文件;
- Bearer Token;
- ServiceAccount Token;
- OIDC;
- 认证 Webhook;
- 匿名请求。
认证器的具体启用方式由 kube-apiserver 参数或结构化认证配置决定。不同认证器的组合方式、优先级和失败处理受 Kubernetes 版本与启动参数影响,不能假设所有发行版都启用了相同配置。
典型请求路径如下:
sequenceDiagram
participant C as 客户端
participant A as kube-apiserver
participant X as 证书认证器
participant O as OIDC/JWT 认证器
participant W as 认证 Webhook
participant Z as 授权器
participant K as Kubernetes API
C->>A: HTTPS 请求 + 证书或 Bearer Token
A->>X: 尝试验证客户端证书
X-->>A: 成功:username/groups,或不适用
A->>O: 尝试验证 JWT
O-->>A: 成功:username/groups,或不适用
A->>W: TokenReview(必要时)
W-->>A: authenticated + identity,或失败
A->>Z: 检查身份和请求权限
Z-->>A: allow 或 deny
A->>K: 执行 API 操作
K-->>C: 200/201,或 401/403 等响应
这里的“尝试”不等于所有认证器都会顺序访问。某些认证器可以根据请求特征直接判断是否适用,例如没有 Bearer Token 时不会进入 Token 认证流程。认证成功后,API Server 使用得到的身份继续授权;认证失败通常是 401 Unauthorized,授权失败通常是 403 Forbidden。
认证身份不是 Kubernetes 中的 User 对象
Kubernetes 原生 API 没有一个类似数据库 users 表的内置 User 资源。User 和 Group 在认证阶段通常只是字符串:
subjects:
- kind: User
name: alice
- kind: Group
name: developers
RBAC 并不验证 alice 是否真的存在。它只会把认证结果中的用户名或组名与 Binding 中的字符串进行匹配。
这带来一个重要后果:
- 删除一个外部 IdP 用户,不会自动删除 Kubernetes 中的
RoleBinding; - 修改 OIDC 的用户名映射,可能让原权限失效,也可能把旧权限绑定“遗留”给另一个身份字符串;
- 一个被回收的客户端证书,如果仍未过期,Kubernetes 本身通常不会知道它已经被撤销。
因此,用户生命周期必须由证书 CA、身份提供商、Webhook 后端以及 RBAC 清理流程共同管理。
X.509 客户端证书认证
认证原理
X.509 客户端证书认证使用双向 TLS。API Server 信任由某个客户端 CA 签发的证书;客户端在 TLS 握手中提交证书链,API Server 验证:
- 证书是否由配置的客户端 CA 签发;
- 证书是否在有效期内;
- 证书用途是否允许客户端认证;
- TLS 握手是否成功。
认证成功后,Kubernetes 通常使用证书的 Subject 字段映射身份:
Common Name(CN)映射为用户名;Organization(O)映射为用户组。
例如证书的 Subject 为:
Subject: CN=alice, O=developers, O=project-a
常见认证结果相当于:
username = alice
groups = [developers, project-a]
这不是 RBAC 的特殊语法,而是认证器将证书字段转换成身份字符串。
用 OpenSSL 生成测试证书
以下示例用于理解机制,不应直接替代生产 CA 管理。假设已经有一个可用于签发客户端证书的 CA:
# 生成客户端私钥
openssl genrsa -out alice.key 2048
# 生成 CSR:
# CN 是用户名,O 是组名
openssl req -new \
-key alice.key \
-out alice.csr \
-subj "/CN=alice/O=developers"
# 为客户端证书声明 clientAuth 用途
cat > client-ext.cnf <<'EOF'
extendedKeyUsage = clientAuth
EOF
# 使用 CA 签发证书
openssl x509 -req \
-in alice.csr \
-CA client-ca.crt \
-CAkey client-ca.key \
-CAcreateserial \
-out alice.crt \
-days 30 \
-sha256 \
-extfile client-ext.cnf
需要满足以下前提:
client-ca.crt已配置给 API Server 的客户端 CA 参数;client-ca.key必须受到严格保护;- API Server 的地址和 CA 配置正确;
- 客户端私钥文件权限不能让无关用户读取。
将证书写入 kubeconfig:
kubectl config set-credentials alice \
--client-certificate=alice.crt \
--client-key=alice.key \
--embed-certs=true
kubectl config set-context alice \
--cluster=my-cluster \
--user=alice \
--namespace=dev
kubectl config use-context alice
kubectl auth whoami
kubectl auth can-i get pods -n dev
kubectl auth whoami 用于查看 API Server 返回的认证身份;kubectl auth can-i 用于检查授权结果。前者成功不代表后者一定成功。
如果没有为 alice 绑定任何权限,常见结果是:
kubectl auth whoami
# User: alice
# Groups:
# developers
# ...
kubectl get pods -n dev
# Error from server (Forbidden): pods is forbidden ...
这说明 TLS 证书验证成功,但 RBAC 拒绝了操作。
证书认证的边界
客户端证书适合需要长期、强约束、由组织 CA 管理的客户端,例如:
- 集群管理员的受控工作站;
- 节点或系统组件;
- 由企业 PKI 签发的运维身份。
但它有几个关键限制。
第一,Kubernetes 通常只验证证书有效性和签发关系,不提供通用的在线证书撤销检查。证书被盗后,删除对应的 RoleBinding 只能阻止绑定到该用户名或组的权限;如果攻击者仍能使用证书,而且该身份还通过其他组获得权限,风险仍然存在。紧急处置通常需要撤销或替换信任 CA、停止接受该证书对应的身份,或者在外层网络设备阻断访问。
第二,证书中的用户名和组是身份字符串,不是动态查询结果。用户从 developers 离职后,旧证书在有效期内仍可能携带 developers 组。
第三,不能把客户端证书私钥放入镜像、Git 仓库或普通 ConfigMap。kubeconfig 中若使用 --embed-certs=true,文件本身会包含私钥,必须按凭据处理。
Token 认证
Bearer Token 的基本形式
Token 认证通常通过 HTTP Header 发送:
Authorization: Bearer eyJ...
Bearer 的含义是“持有者即可使用”。服务器不需要证明请求者是哪个人,只要 Token 有效就接受它。因此 Token 的泄露等价于凭据泄露。
Token 可以是:
- 不透明随机字符串;
- JWT;
- ServiceAccount Token;
- 外部身份系统签发的访问令牌;
- 静态 Token 文件中的字符串。
API Server 具体能验证哪一种 Token,取决于启用的认证器。
静态 Token 文件
静态 Token 文件通常是 API Server 本地的 CSV 配置,包含 Token、用户名和组等字段。它的概念形式类似:
token123,alice,1001,"developers,project-a"
这类方式适合非常有限的引导或实验环境,但生产中风险较大:
- Token 通常是长期凭据;
- 修改文件需要重新加载配置或重启,具体行为取决于实现和版本;
- 文件本身就是高价值秘密;
- 缺少成熟的单个 Token 撤销和轮换机制;
- Token 泄露后难以追踪真实持有者。
不要把静态 Token 当作普通配置文件提交到版本控制系统。
JWT Token 的验证条件
JWT 通常由三部分组成:
header.payload.signature
认证器验证的不是“字符串看起来像 JWT”,而是至少需要检查:
- 签名算法和签名是否正确;
- 签发者
iss是否是受信任的发行者; - 受众
aud是否包含 API Server 所接受的受众; - 时间字段,如
exp、nbf、iat,是否满足有效期要求; - 用户名和组声明是否按配置映射;
- 必要的声明是否存在且类型正确。
形式化地说,对一个 Token ,认证成功至少需要:
并且:
其中:
- 是受信任的签名密钥集合;
- 是配置的发行者;
- 是 API Server 接受的 audience 集合。
只验证签名而不检查 aud,可能导致“发给服务 A 的 Token 被服务 B 接受”的混淆代理问题。
ServiceAccount Token:工作负载身份
ServiceAccount 是 Kubernetes 中面向 Pod 的身份。Pod 中的进程通过 ServiceAccount Token 访问 API Server 或其他支持该 Token 的服务。
当前推荐的是 Bound ServiceAccount Token,通常通过 Projected Volume 注入 Pod。它与早期长期存在于 Secret 中的 ServiceAccount Token 不同:
- Token 具有有限有效期;
- Token 与 Pod、ServiceAccount 等对象建立绑定关系;
- 可以指定 audience;
- kubelet 负责在接近过期时轮换投影文件;
- 删除 Pod 后,绑定关系可使旧 Token 失效或不再被接受,具体验证行为由发行者和 API Server 实现共同决定。
一个显式配置的投影卷示例:
apiVersion: v1
kind: Pod
metadata:
name: token-demo
namespace: dev
spec:
serviceAccountName: app
containers:
- name: app
image: curlimages/curl:8.10.1
command: ["sleep", "3600"]
volumeMounts:
- name: api-token
mountPath: /var/run/secrets/tokens
readOnly: true
volumes:
- name: api-token
projected:
sources:
- serviceAccountToken:
path: token
expirationSeconds: 3600
audience: https://kubernetes.default.svc
前提是命名空间中存在 app:
kubectl -n dev create serviceaccount app
kubectl apply -f token-demo.yaml
进入容器后,可以使用 Token 访问 API:
kubectl -n dev exec -it token-demo -- sh
TOKEN="$(cat /var/run/secrets/tokens/token)"
curl --fail-with-body \
--cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
-H "Authorization: Bearer ${TOKEN}" \
https://kubernetes.default.svc/api
这里每一步的因果关系是:
serviceAccountName: app使 Pod 使用app身份;- projected volume 请求 kubelet 获取指定 audience 和有效期的 Token;
- 容器读取文件,而不是把 Token 固化到镜像;
- API Server 验证签名、发行者、有效期和 audience;
- 认证得到的用户名通常形如:
system:serviceaccount:dev:app - RBAC 再判断这个 ServiceAccount 是否拥有访问
/api或其他资源的权限。
给它最小的只读权限:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: dev
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-pod-reader
namespace: dev
subjects:
- kind: ServiceAccount
name: app
namespace: dev
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pod-reader
验证:
kubectl auth can-i \
--as=system:serviceaccount:dev:app \
list pods -n dev
# yes
kubectl auth can-i \
--as=system:serviceaccount:dev:app \
get secrets -n dev
# no
--as 是管理员或具有 impersonation 权限的客户端模拟身份进行检查,不是普通用户可以任意伪造身份。实际 Pod 中的 Token 仍由 API Server 独立验证。
audience 和轮换不能省略
audience 表示 Token 预期被哪个服务接受。一个面向 Kubernetes API 的 Token 不应默认被任意内部服务接受;外部 Workload Identity 系统也不应盲目接受 Kubernetes API Token。
应用必须能够重新读取投影文件,或者使用支持文件轮换的凭据加载方式。错误做法是:
容器启动时读取 Token
→ 保存到进程内存
→ 永远不再读取文件
这样 Token 轮换后,应用仍使用旧 Token,最终可能收到 401 Unauthorized。推荐应用在请求失败或定期刷新时重新读取文件;具体刷新策略应服从客户端库的实现。
早期 Secret 自动生成的长期 ServiceAccount Token 在现代集群中不再是推荐方式。版本升级、发行版默认设置和兼容性策略可能不同;排查时应确认集群是否启用了 TokenRequest API 以及 projected service account token。
OIDC:把外部身份提供商接入 Kubernetes
OIDC 的角色
OIDC(OpenID Connect)是在 OAuth 2.0 之上定义的身份层。对 Kubernetes 来说,典型流程是:
- 用户在外部身份提供商(IdP)登录;
- IdP 签发 ID Token 或访问 Kubernetes 的 JWT;
kubectl把 JWT 作为 Bearer Token 发送给 API Server;- API Server 根据 OIDC 配置验证 JWT;
- API Server 将声明映射为 Kubernetes 用户名和组;
- RBAC 根据这些字符串授权。
OIDC 并不把用户同步进 Kubernetes。Kubernetes 仍然只看到认证结果中的用户名和组。
API Server 如何验证 OIDC Token
API Server 通常需要知道:
issuer URL;- 客户端 ID或受众;
- 用户名声明;
- 组声明;
- 可选的用户名和组前缀。
发行者的发现文档通常位于:
https://idp.example.com/.well-known/openid-configuration
其中可能提供 JWKS 地址。API Server 使用 JWKS 中的公钥验证 JWT 签名,并根据 kid 选择密钥。密钥轮换时,发现文档和 JWKS 缓存更新是认证可用性的关键。
一个 JWT 负载可能是:
{
"iss": "https://idp.example.com",
"sub": "00u123",
"aud": ["kubernetes"],
"exp": 1735689600,
"email": "alice@example.com",
"groups": ["platform", "developers"]
}
如果配置:
username claim = email
groups claim = groups
则可能得到:
username = alice@example.com
groups = [platform, developers]
如果多个身份系统都可能产生相同的用户名或组名,应使用前缀区分,例如把组映射为:
oidc:platform
oidc:developers
否则,绑定到 developers 的 RBAC 规则可能同时影响来自不同身份源的用户。
OIDC 配置的版本和云厂商差异
OIDC 的 API Server 参数和结构化认证配置在 Kubernetes 版本中持续演进。常见发行版可能通过:
- 托管控制平面选项;
- 集群创建参数;
- 身份代理;
- 云厂商专用集成;
- 反向代理或外部认证层
来配置 OIDC。参数名称、可用声明、前缀规则和密钥刷新行为不能仅凭某个云厂商文档推断为通用 Kubernetes 行为。
生产配置至少要验证以下事实:
kubectl auth whoami
kubectl auth can-i get pods -n dev
kubectl auth can-i --list
还应实际检查:
- Token 的
iss、aud、exp; - 组声明是否是字符串数组,而不是逗号拼接字符串;
- IdP 密钥轮换后 API Server 是否能获取新 JWKS;
- 用户被禁用后,已有 Token 在剩余有效期内是否仍然有效;
- RBAC 是否绑定了稳定的
sub,还是绑定了可能变化的邮箱地址。
OIDC 用户生命周期
OIDC 的生命周期由多个时间尺度组成:
用户在 IdP 中创建
→ 获得组成员关系
→ 登录获取 Token
→ Token 在有效期内使用
→ 用户被禁用或移出组
→ 新 Token 不再包含身份/组
→ 旧 Token 是否立即失效,取决于 IdP 和验证方式
→ Kubernetes 中旧 RoleBinding 是否仍需清理
如果 RBAC 使用 email 作为用户名,邮箱变更可能导致权限绑定断裂;如果邮箱被重新分配给另一个人,也可能造成身份语义风险。更稳定的 sub 通常更适合作为用户名,但其可读性较差。实际选择应同时考虑 IdP 保证、审计可读性和迁移策略。
认证 Webhook:把认证决策委托给外部服务
Webhook 与 OIDC 的区别
OIDC 要求 API Server 自己理解并验证 JWT。认证 Webhook 则把 Token 认证请求发送给外部 HTTPS 服务,由该服务返回:
- Token 是否有效;
- 用户名;
- 用户组;
- 额外属性;
- 可选的过期时间。
Webhook 适合以下情况:
- Token 是非 JWT 的不透明字符串;
- 凭据验证需要调用企业会话服务;
- 需要集中撤销和实时策略;
- 身份系统已有 Kubernetes 不直接支持的认证协议。
它的代价是:API Server 的认证路径依赖外部服务的网络、证书、性能和可用性。
TokenReview 请求和响应
API Server 会向 Webhook 发送 authentication.k8s.io 组中的 TokenReview。概念上的请求如下:
{
"apiVersion": "authentication.k8s.io/v1",
"kind": "TokenReview",
"spec": {
"token": "opaque-token-from-client",
"audiences": [
"https://kubernetes.default.svc"
]
}
}
Webhook 成功验证后返回:
{
"apiVersion": "authentication.k8s.io/v1",
"kind": "TokenReview",
"status": {
"authenticated": true,
"user": {
"username": "alice@example.com",
"uid": "idp-00u123",
"groups": ["oidc:developers"],
"extra": {
"example.com/tenant": ["team-a"]
}
},
"audiences": [
"https://kubernetes.default.svc"
]
}
}
Webhook 必须把 authenticated、用户身份和 audience 作为一个一致的验证结果返回。若 Token 无效,应返回:
{
"apiVersion": "authentication.k8s.io/v1",
"kind": "TokenReview",
"status": {
"authenticated": false
}
}
不能仅因为能解析 Token 就返回用户名;外部服务必须验证签名、会话状态、有效期、audience 和撤销状态。
Webhook 的数据流和故障路径
sequenceDiagram
participant K as kube-apiserver
participant W as 认证 Webhook
participant I as 外部 IdP/会话库
K->>W: POST TokenReview
W->>I: 查询或验证 Token
I-->>W: 有效/无效、用户、组
W-->>K: TokenReview status
K->>K: 认证后执行授权
可能的故障包括:
- Webhook TLS 证书过期;
- API Server 无法解析 Webhook 地址;
- 网络策略阻断访问;
- Webhook 响应超时;
- IdP 不可用;
- Webhook 返回格式不符合
TokenReview; - Webhook 误把 audience 忽略;
- 缓存使撤销后的 Token 在短时间内仍被接受。
认证 Webhook 通常支持超时和缓存配置。缓存能减少外部调用,但会延迟撤销生效;超时时间过长会把 API Server 请求延迟传递给所有客户端,过短则可能在短暂网络抖动时造成大量 401。这些参数应结合认证服务的延迟分布和故障策略验证,不能只追求“更快”或“更安全”。
如果 Webhook 不可用,认证失败可能表现为:
401 Unauthorized
也可能表现为 API Server 侧错误或明显延迟,具体取决于配置和实现。排查时应同时查看:
kubectl get --raw='/readyz?verbose'
kubectl get events -A
并检查 API Server 日志、Webhook 服务日志、TLS 信任链和网络连通性。不要通过临时开启匿名认证来“修复”问题;那会改变整个 API Server 的安全边界。
认证之后:RBAC 如何消费身份
RBAC Binding 中的 subjects 只匹配认证阶段产生的身份字符串。例如:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: platform-readonly
subjects:
- kind: Group
name: oidc:platform
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: view
apiGroup: rbac.authorization.k8s.io
如果 OIDC 配置最终返回的组是 platform 而不是 oidc:platform,该 Binding 不会生效。认证配置中的前缀、大小写、组声明格式和 RBAC 中的名称必须完全一致。
授权计算可以简化为:
其中:
- 是资源;
- 是 API Group;
- 是命名空间;
- 是动作,如
get、list、create; - 只要用户名或任意用户组匹配某条允许规则,RBAC 就可能允许请求。
因此,把用户加入一个高权限组,效果可能远大于给用户增加一条单独的 RoleBinding。认证组声明必须视为高敏感输入。
特别需要区分:
Role只在一个命名空间内授权;ClusterRole可以描述集群范围资源,也可被 RoleBinding 引用以授予某命名空间内权限;ClusterRoleBinding把权限授予整个集群范围;system:masters等系统组具有极高权限,不应作为普通业务组使用。
用户生命周期与权限回收
人类用户的生命周期
一个完整的人类用户生命周期通常是:
入职
→ IdP/PKI 创建身份
→ 配置组或签发证书
→ Kubernetes RBAC 绑定组
→ 日常认证和审计
→ 岗位变化,组成员变化
→ 凭据轮换
→ 离职,撤销登录和凭据
→ 清理或保留审计所需的 RBAC 记录
每种认证方式的回收速度不同:
| 认证方式 | 回收主要依赖 | 常见延迟来源 |
|---|---|---|
| 客户端证书 | CA、证书有效期、Binding | 已签发证书通常不会自动在线撤销 |
| OIDC | IdP 会话和 Token 策略 | 旧 Token 在过期前可能仍有效 |
| Webhook | 外部验证服务和缓存 | Webhook 缓存、网络和后端状态 |
| 静态 Token | 删除或更换静态 Token 配置 | 配置加载、API Server 重启 |
| ServiceAccount Token | ServiceAccount、Pod 绑定和 TokenRequest | 应用缓存旧 Token、验证端缓存 |
这张表的关键不是“哪种方式一定更安全”,而是明确:身份回收不是 RBAC 单独完成的事情。
工作负载的生命周期
工作负载不应共享人类管理员凭据。推荐为每个应用或信任边界创建独立 ServiceAccount:
apiVersion: v1
kind: ServiceAccount
metadata:
name: billing-reader
namespace: finance
然后只授予需要的资源和动作。应用删除、迁移或换租户时,应同步处理:
- Deployment 或 Job 使用的 ServiceAccount;
- RoleBinding;
- 外部 Workload Identity 映射;
- 云厂商 IAM 角色;
- 外部服务允许的 audience;
- 旧 Pod 和旧 Token。
如果多个租户共用一个 ServiceAccount,审计只能看到同一个身份,权限回收也会牵连多个应用,导致隔离边界模糊。
诊断:从 HTTP 状态和身份开始
401 Unauthorized
通常表示认证失败,重点检查:
- 是否发送了
Authorization: Bearer; - Token 是否过期;
- JWT 的
iss和aud是否正确; - 签名密钥是否更新;
- 客户端证书是否过期;
- 客户端证书是否由正确 CA 签发;
- Webhook 是否可达并返回有效响应;
- ServiceAccount Token 是否仍对应有效 Pod 或 ServiceAccount。
可以先查看客户端身份:
kubectl auth whoami
对于 ServiceAccount,检查 Pod 中实际读取的 Token,而不是只查看 Secret:
kubectl -n finance exec deploy/billing -c app -- \
sh -c 'test -s /var/run/secrets/kubernetes.io/serviceaccount/token && echo token-present'
不要把 Token 内容打印到共享日志或聊天系统。
403 Forbidden
通常表示认证已经成功,但授权失败。使用:
kubectl auth can-i get deployments -n finance
kubectl auth can-i --list -n finance
如果是管理员进行排查,可以指定身份:
kubectl auth can-i \
--as=alice@example.com \
--as-group=oidc:developers \
get pods -n dev
重点核对:
- 用户名和组是否与 RBAC Binding 完全一致;
- RoleBinding 是否位于正确命名空间;
roleRef是否引用了预期的 Role 或 ClusterRole;- API Group、资源名和动词是否正确;
- 是否误用了
ClusterRoleBinding; - 是否因为聚合 ClusterRole 自动获得了额外权限。
kubectl auth whoami 不能显示完整安全事实
它能帮助确认 API Server 解析出了什么用户名和组,但不能证明:
- Token 的来源可信;
- 当前权限符合最小权限;
- 外部 IdP 已经完成用户回收;
- 证书没有被复制;
- Webhook 缓存已经刷新。
必要时应结合 API Server 审计日志。审计记录中的 user.username、user.groups、源地址和请求资源,可以确认实际到达授权层的身份,而不是只看客户端配置文件。
常见误解和反例
“证书有效,所以用户一定有权限”
反例:证书由受信任 CA 签发,CN 为 alice,但没有任何 RoleBinding。结果是认证成功、授权失败,即 403。
“JWT 能解码,所以它是真的”
反例:攻击者构造一个没有有效签名的 JWT,或者使用签发给另一个 audience 的合法 JWT。若服务只解码 payload,不验证签名和 aud,就会接受错误身份。
“删除 RoleBinding 就完成了用户离职处理”
反例:用户仍持有有效 OIDC Token 或客户端证书,并通过另一个组获得权限。RBAC 中删除一条 Binding 并不能撤销所有外部凭据。
“ServiceAccount Token 放在 Secret 中最方便”
反例:长期 Token 被复制到日志、备份或开发者电脑,Pod 删除后仍可能被使用。Projected Token 的短期有效期、绑定关系和 kubelet 轮换更适合现代工作负载。
“认证 Webhook 返回 username 就够了”
反例:Webhook 不验证 audience,导致面向其他系统的 Token 也能调用 Kubernetes;或者 Webhook 缓存撤销结果过久,离职用户在缓存有效期内仍能访问。
生产取舍
人类用户通常更适合使用企业 IdP 的 OIDC 或受控的短期凭据流程,因为用户生命周期、组管理、多因素认证和登录审计可以集中处理。客户端证书适合 PKI 已成熟、需要强客户端身份并能可靠管理私钥和轮换的场景。
工作负载应优先使用短期、受 audience 限制、可轮换的 ServiceAccount Token,并通过 Workload Identity 与云厂商或外部服务建立明确的信任关系。不要让应用依赖管理员 kubeconfig,也不要把人类 Token 嵌入镜像。
认证 Webhook 提供了实时控制和协议适配能力,但它把 API Server 的可用性依赖扩展到了外部系统。启用前必须验证 TLS、超时、缓存、密钥轮换、后端故障和恢复路径。
最终,Kubernetes 认证设计的核心不是在证书、Token、OIDC 和 Webhook 中选择一个“万能方案”,而是明确三条边界:
- 认证器如何证明凭据有效,并映射出稳定的用户名和组;
- RBAC 如何根据这些身份授予最小权限;
- 外部身份、凭据、Token、Binding 和审计记录如何随用户或工作负载生命周期同步变化。
只有这三条链路同时成立,401、403、凭据泄露和离职回收等问题才不会被误认为是同一个“权限配置错误”。
系列导航与关联阅读
- 系列入口:Kubernetes 完整学习路线:从 Pod 与控制面到安全、运维和 Operator
- 上一篇:Kubernetes 备份与 Velero:资源、卷、Hook、恢复顺序和演练
- 下一篇:Kubernetes RBAC:Role、ClusterRole、Binding、聚合和最小权限
- 延伸:Kubernetes ServiceAccount:Projected Token、Audience、轮换和 Workload Identity
官方资料
本文依据 Kubernetes、CNCF 与相关项目官方文档重新梳理;正文和生产清单由 WR BLOG 编写。

评论
0 条讨论