自建 K8s 接 OIDC:三个前提、三个组件与一份落地清单
自建 Kubernetes 集群默认发的是一张静态客户端证书或长期 token,签发之后几乎不再回收,人走了凭证还在。把认证交给身份提供商(如 Keycloak)能让权限变更变成一次加组操作,代价是配置面变多。本文先讲清做这件事的三个前提,再拆解 kubectl、身份提供商与 kube-apiserver 三方如何分工,并给出先 IdP、再 apiserver、后客户端的落地顺序,以及 secret 分发、自签名 CA、组声明三个最容易踩的坑。
作者:核流编辑 · 栏目:资源
如果你所在的自建集群还是靠一张 kubeconfig 分发权限,大概会熟悉这样的场面:某位同事三个月前已经离职,但他那份客户端证书照样能连上 API server,因为签发之后没人回收过它。这类集群默认拿到的是静态客户端证书或长期 token,集群的认证链路不会检查持有人是否还应该在编;要吊销,就得把文件在每台机器上的每一份拷贝都找出来,实际做全的很少。换成身份提供商(Keycloak 或任何兼容 OIDC 的服务)接管认证之后,权限变更会变成一次加组操作。下面先说清什么情况下值得现在做。 先判断:三个前提成立再动手 第一,集群确实是自建的。托管云 Kubernetes 开箱就带 IAM 或 SSO 集成,认证与用户生命周期由云厂商负责,不需要再自己接一套身份提供商;这套改造面向的是 on-prem 或自管的集群。 第二,需要不同权限的人已经超过一两个。只有一两个人、权限长期不变时,按人按文件各自维护尚且能承受;人一多,这份维护工作本身就是持续的,而静态证书的麻烦在于人事变动之后它不会给出任何提示。 第三,接受把认证前移到集群之外。改造后访问权限跟随账号与其用户组,不再跟随某个文件——这是收益,也意味着身份提供商的可用性从此进入集群的登录路径。 三个组件如何分工:一次登录里谁做什么 整套集成由三方配合,缺一不可。客户端这一侧是 kubectl 搭配 kubelogin 插件:由它发起登录、拿到 token,并把 token 附在每个 API 请求上。身份提供商负责认证用户,签发携带用户名与组信息的 ID token。集群这一侧是 kube-apiserver,通过 --oidc-issuer-url、--oidc-client-id、--oidc-groups-claim 三个参数校验 token、提取身份,再交给 RBAC 决定这个身份能做什么。 理解数据流能省掉不少排查时间:kubectl 先向身份提供商认证,从不先找 API server;API server 直接用身份提供商的公钥验签,除了一次性获取签名公钥之外并不需要回连对方。客户端配置里最关键的一条,是把它注册为 public client 而不是 confidential client:机密客户端会签发 client secret,而 secret 要写进每台机器的插件配置——需要分发到所有客户端才生效的 secret 已经不是秘密,而是一份共享的静态凭证,轮换它等于给每台机器做一次协同的配置推送。OAuth 2.1 对原生与命令行应用已经给出结论:用 public client,不签发 secret,改用 PKCE(S256),由客户端在本地生成随机值,登录时只发送它的哈希,换取 token 时再证明自己持有原值,只截获授权码的人无法完成这一步。 落地清单与三个最容易踩的坑 这份清单用来按依赖顺序推进,最省返工:先身份提供商、再 API server、后客户端。Kubernetes 官方鉴权文档里说得很明确——Kubernetes 没有一等公民的「用户」对象,RBAC 只认 token 里声明的用户名与组,所以身份提供商必须真的把组信息写进 token,否则后面按组授权会落空。 准备一个 OIDC 身份提供商,例如 Keycloak。 在管理后台注册 public client:关闭 Client authentication,把重定向 URI 与 Web origins 限制在回环地址(127.0.0.1、localhost),开启 PKCE。 为该 client 添加 Group Membership 类型的映射器,把组信息写入 ID token 的 groups 声明。坑一:映射器只加到 access token、忘了 ID token,集群侧就拿不到组,表现为登录成功但权限全无。 给 kube-apiserver 加上三个 OIDC 参数;身份提供商若用自签名证书,必须追加 --oidc-ca-file 指向 CA 证书。坑二:漏掉它时会先撞上一条与登录流程毫不相干的 TLS 校验错误,第一次排查相当费解。 把 kubeconfig 里的静态证书或 token 换成 kubelogin 的 exec 凭证条目,条目里没有任何 secret 字段;首次登录会拉起浏览器,之后的请求复用缓存 token,过期时由刷新令牌静默续期。坑三:仍旧走 confidential client 加 secret 的做法,等于把共享凭证从证书原封不动换成了 secret。 登录后确认落到 token 里的身份与组是否符合预期,再按组完成 RBAC 绑定。 改完之后,权限变更全部发生在身份提供商内部:把某人加入 platform-viewer 组,他下一次换到的 token 就会带上这个组,集群侧无需改动,也没有新的 kubeconfig 需要分发。审计上的差别同样直接:共享 kubeconfig 的做法会让所有人在 API server 日志里呈现为同一个泛化身份,其中最常见的写法就是 cluster-admin,日志等于白记;身份联邦之后,每条请求记录都能对上具体的人。需要留意客户端这一侧的缓存:token 过期前仍会被复用,刚被收回权限的人手上若有有效 token,并不会立刻失效。按原文作者的说法,这套改造大约花费一个下午。完整参数与流程以 Kubernetes 官方鉴权文档为准(见参考资料)。 参考资料 CNCF Blog:Kubernetes access via an identity provider: Public client, not confidential Kubernetes Documentation:Authenticating