网络、存储和监控经常出现在 Kubernetes 集群的 day-zero 清单里,身份接入却容易被拖到上线之后。托管 Kubernetes 通常已经连接云 IAM 或企业 SSO,而自建集群如果继续依赖共享 kubeconfig、长期客户端证书或静态 Token,不仅离职回收困难,审计也很难回答“谁在什么时间操作了集群”。
通过 OIDC 把 Kubernetes API Server 接入身份提供商(IdP),可以让开发者使用企业账号登录,再由 Kubernetes RBAC 决定他们能做什么。其中一个容易配错的关键点是:供 kubectl 使用的 OIDC 应用通常应该注册成 Public Client,而不是 Confidential Client。
kubectl 无法安全保管客户端密钥
Confidential Client 适合运行在受控服务器上的后端应用。服务器可以把 client_secret 放进 Secret Manager、Vault 或受保护的环境变量,并阻止终端用户读取它。
kubectl 则运行在工程师自己的电脑上。无论把密钥写入 kubeconfig、环境变量还是插件配置,用户都能够读取和复制它。把同一个 client_secret 分发给几百名开发者,并不会让 CLI 变成“机密客户端”,只会制造一个难以轮换的共享凭据。
因此,更合理的组合是:
- 在 IdP 中为 Kubernetes CLI 单独创建 Public Client;
- 使用 Authorization Code Flow;
- 启用 PKCE,并优先要求
S256; - 只注册本机回调地址,例如插件实际使用的
http://localhost:<port>; - 不在 kubeconfig 中保存
client_secret; - 将 Web 后端等真正能保管密钥的应用注册为独立的 Confidential Client。
Public Client 并不表示“任何人都能进入集群”。用户仍然必须在 IdP 完成认证,Token 的签发者、受众和有效期也必须通过 API Server 校验。Public 与 Confidential 描述的是客户端能否安全保存密钥,不是授权强弱。
身份认证与 Kubernetes 授权要分开设计
OIDC 解决的是认证:API Server 能确认请求来自哪个用户、用户属于哪些组。RBAC 解决的是授权:这个用户或组可以读取、修改哪些 Kubernetes 资源。
一条典型链路如下:
kubectl的 exec credential 插件打开浏览器;- 用户在企业 IdP 登录并完成 MFA;
- CLI 通过 Authorization Code + PKCE 换取 Token;
kubectl携带 Token 请求 Kubernetes API;- API Server 校验 issuer、签名、过期时间和 audience;
- API Server 从声明中提取用户名与组;
- RBAC 根据用户或组完成授权。
这也意味着“成功登录”不应自动等于拥有权限。尤其不要为了验证 OIDC 是否工作,就把所有登录用户绑定到 cluster-admin。
一套可以改造的 OIDC 接入配置
下面是一份通用实践示例,假设:
- IdP 的 issuer 为
https://sso.example.com/realms/platform; - Public Client ID 为
kubernetes-cli; - IdP 在 Token 的
groups声明中返回用户组; - 本地已经安装支持 OIDC 的
kubeloginkubectl 插件; - API Server 的部署方式允许增加启动参数。
不同 IdP 和插件对回调 URI、PKCE、scope 的命名可能不同,运行前应按实际产品文档修改。
先检查 issuer 是否提供标准的 OIDC Discovery 文档:
export OIDC_ISSUER="https://sso.example.com/realms/platform"
curl --fail --silent --show-error \
"${OIDC_ISSUER}/.well-known/openid-configuration" | python3 -m json.tool
在 IdP 中创建客户端时,可以按下面的约束配置:
Client ID: kubernetes-cli
Client type: Public
Authorization Code: Enabled
PKCE: Required, S256
Client secret: None
Scopes: openid profile email groups
Redirect URI: 插件文档指定的 localhost 回调地址
然后让 Kubernetes API Server 信任这个 issuer。对于使用启动参数配置 OIDC 的集群,可以这样调整参数;这只是可改造示例,修改控制平面前应先备份清单并准备回滚:
spec:
containers:
- name: kube-apiserver
command:
- kube-apiserver
- --oidc-issuer-url=https://sso.example.com/realms/platform
- --oidc-client-id=kubernetes-cli
- --oidc-username-claim=email
- --oidc-username-prefix=oidc:
- --oidc-groups-claim=groups
- --oidc-groups-prefix=oidc:
这里显式添加了 oidc: 前缀,避免外部身份与 Kubernetes 内置用户名或组名发生碰撞。生产环境还应确认 issuer 使用受信任的 HTTPS 证书,并根据 Kubernetes 版本评估启动参数或结构化认证配置的适用方式。
在现有 kubeconfig 中,可以增加一个 exec 用户。下面的片段可复制后合并到 users 列表中:
users:
- name: company-oidc
user:
exec:
apiVersion: client.authentication.k8s.io/v1
command: kubectl
args:
- oidc-login
- get-token
- --oidc-issuer-url=https://sso.example.com/realms/platform
- --oidc-client-id=kubernetes-cli
- --oidc-extra-scope=groups
interactiveMode: IfAvailable
provideClusterInfo: false
注意配置中没有 client_secret。将对应 context 的 user 改为 company-oidc 后,可以测试登录:
kubectl config use-context my-onprem-cluster
kubectl auth whoami
kubectl auth can-i get pods --all-namespaces
如果当前 Kubernetes 版本不支持 kubectl auth whoami,可以直接执行一个只读请求验证身份与权限:
kubectl get namespaces
用 IdP 组映射 RBAC,而不是逐个绑定用户
逐个维护邮箱地址会迅速失控。更容易审计的方式是在 IdP 中维护组,再把组映射到 Kubernetes Role 或 ClusterRole。
例如,让 platform-readers 组只读查看 staging 命名空间中的常用工作负载:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: workload-reader
namespace: staging
rules:
- apiGroups: [""]
resources: ["pods", "pods/log", "services", "configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets", "statefulsets"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: platform-readers
namespace: staging
subjects:
- kind: Group
name: oidc:platform-readers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: workload-reader
apiGroup: rbac.authorization.k8s.io
保存为 staging-readers.yaml 后执行:
kubectl apply -f staging-readers.yaml
kubectl auth can-i list pods \
--namespace staging \
--as-group=oidc:platform-readers \
--as=oidc:test@example.com
第二条命令通常需要管理员权限进行模拟。真正验收时,还应让测试账号完成一次浏览器登录,确认 IdP 实际签发的 groups 声明与 RoleBinding 完全一致。
上线前不要漏掉这些边界
把身份提供商接入 Kubernetes 不是只添加几个 API Server 参数。更稳妥的上线检查包括:
- 为 CLI 创建独立 Public Client,不复用带密钥的 Web 应用客户端;
- 强制 PKCE、MFA 和较短的 Token 有效期;
- 严格限制 localhost redirect URI,避免宽泛通配符;
- 校验 Token audience,避免其他应用的 Token 被集群接受;
- 使用带前缀的用户名和组名,防止与内置身份碰撞;
- 通过 IdP 组授予最小 RBAC 权限,不默认绑定
cluster-admin; - 明确本地 Token 缓存的位置、文件权限和退出登录方式;
- 保留紧急管理通道,但将凭据离线保存、定期轮换并记录使用;
- 在非生产集群测试 issuer 不可用、证书轮换和 IdP 故障时的行为。
身份接入应与网络和存储一样成为集群创建时的基础设计。选择 Public Client 的核心原因并不复杂:桌面 CLI 没有能力保守共享密钥。承认这个边界,再用 PKCE、短期 Token、MFA 和最小权限 RBAC 补齐安全链路,通常比把一个“秘密”复制到所有开发者电脑上可靠得多。