CNCF 博客上发表的一篇文章建议,将 Kubernetes 集群的访问控制作为基础配置清单的一部分,与网络和存储并列,尤其是在自托管环境中,因为这类环境通常不像托管 Kubernetes 服务那样提供现成的 IAM 或 SSO 集成。核心思路是使用兼容 OIDC 的身份提供商(如 Keycloak),并将客户端注册为使用 PKCE 的公共客户端,而不是持有共享密钥的机密客户端。
在许多本地集群中,访问依赖于固定的客户端证书或一次性签发的长期有效令牌。即使员工离职、角色发生变化,或丢失了存有这些凭据的设备,这些数据仍然有效。此外,撤销访问需要找到证书或令牌文件的每个副本;当设备和用户数量增加时,很难确保这一过程完整无遗漏。随着人员数量增加以及权限级别出现差异,文件的分发和管理会变成一项持续性的运维任务。
OIDC 会带来哪些变化?
权限不再与证书文件绑定,而是与用户账户及其在身份提供商中的组成员关系绑定。该集成由三个相互关联的参与方组成:带有kubelogin或kubectl oidc-login插件的kubectl工具、负责验证用户并签发身份令牌的身份提供商,以及负责验证令牌、提取用户名和组信息,再交由 Kubernetes RBAC 确定允许执行哪些操作的kube-apiserver。
kubectl 不会先连接 API 服务器来启动登录。exec-credential 插件会在身份提供商处通过浏览器启动登录,然后将身份令牌返回给 kubectl,由 kubectl 将其作为持有者令牌凭据发送。API 服务器使用身份提供商的公共签名密钥验证令牌。根据该文章,服务器不需要与身份提供商保持持续连接,只有在需要时获取这些密钥即可。
为什么客户端必须是公共客户端?
机密客户端会签发一个密钥,将其添加到 kubelogin 插件的配置中,并分发到每台需要访问的设备。文章认为,必须分发给所有客户端的密钥实际上已不再是真正的秘密,而是一种难以轮换的共享固定凭据。对于命令行工具和原生应用,更合适的选择是使用不含机密的公共客户端,并启用PKCE,即 Proof Key for Code Exchange。
客户端会在本地生成一个随机值,并在初始登录请求中发送该值的哈希;随后在将授权码兑换为访问令牌时证明自己拥有原始值。因此,仅拦截授权码的攻击者无法完成该流程。文章中给出的 Keycloak 设置建议包括:禁用客户端身份验证、启用标准流程、禁用直接访问授权,并使用 S256 强制启用 PKCE;同时将重定向地址和 Web 源限制为127.0.0.1和localhost等回环地址。
基本设置步骤
- 向 Keycloak 中的客户端范围添加组成员关系映射器,使身份令牌中出现名为groups的声明。
- 使用 oidc-issuer-url、oidc-client-id、oidc-username-claim 和 oidc-groups-claim 等标志配置 kube-apiserver。
- 如果身份提供商使用的证书不是由公共可信机构签发,则添加 oidc-ca-file,以便 API 服务器验证 TLS 连接并获取签名密钥。
- 修改 kubeconfig,通过 kubectl oidc-login 使用 exec-credential 条目,而不是嵌入固定证书或令牌,并且不添加机密字段。
- 将身份提供商的组绑定到 Kubernetes RBAC 角色,例如将 platform-viewer 组绑定到 view 角色。
实际影响与限制
完成这一绑定后,访问权限的变更在身份提供商中进行:将用户加入某个组或从中移除,而不是修改集群或重新分发 kubeconfig。用户随后获得的新令牌会包含新的组成员关系,并应用与该组关联的 RBAC 规则。文章指出,首次登录会打开浏览器,而 kubelogin 会重复使用缓存的令牌,直到其过期;随后使用刷新令牌,无需再次打开浏览器。可以通过 kubectl auth whoami 命令检查实际身份和组信息。
这并不意味着该集成没有运维要求。必须准确配置组声明、验证身份提供商的证书、限制重定向地址,并确认 RBAC 角色反映所需权限。此外,文章没有提供关于设置时间或运行成本的独立测量,而是估计准备工作可能在一个工作时段内完成,而不需要进行完整的平台迁移。
其最重要的安全和管理优势是,Kubernetes 日志能够与实际用户身份关联。依赖 cluster-admin 等公共账户的日志无法区分请求的执行者,而通过 OIDC 发出的每个请求都会携带用户名及其关联的组信息。这是基于文章细节得出的编辑性解读:改进之处不只是登录方式,还在于能够将操作归属到具体人员,同时将权限授予和撤销变成集中式身份管理流程,而不必寻找分散的凭据文件。