Kubernetes实现SSO登录之命令行体验


上一篇文章中,我们讨论了Kubernetes的几种用户认证方法,还说了我的团队在Pusher希望为我们的工程师创建一个无缝的SSO(单点登录)环境,以及是如何开始对Open ID Connect(OIDC)进行调查并找出解决方案的。

这其中有个问题是Kubernetes没有登录的过程。通常,客户端软件会启动登录,但kubectl没有内置该功能。Kubernetes留给你去设计你自己的登录方式。

这篇文章,我将阐述如何实现让工程师从终端登录以及我们在这过程中趟过的坑。

我们的身份提供商

实现SSO的第一步是把Dex设置为我们的身份提供商。Dex充当认证流程的代理,用Google GSuite帐户对用户进行身份验证。

我们在Elastic Load Balancer后面使用AWS EC2实例集运行Dex,暴露一台Dex来验证所有Pusher内部的Kubernetes集群。虽然可以在Kubernetes中运行Dex,在各个集群分别验证,但我们选择了集中的方式。这意味着允许一个令牌访问所有群集,但考虑到想用Dex撤销令牌的功能,我们决定接受这个折衷的结果。

Kubernetes集群连接到Dex,只在Kubernetes API服务器的配置中添加一些参数:

# The URL where Dex was available
--oidc-issuer-url=https://auth.example.com/dex
# The client ID we configured in dex. Kubernetes will compare this to the `aud` field
# in any bearer token from Dex before accepting it.
--oidc-client-id=kubernetes
# Since Dex is configured with TLS, add the CA cert to initiate trust
--oidc-ca-file=/etc/kubernetes/ssl/dex-ca.pem
# The claim field to identify users. For us this means users are granted the username # of their Pusher email address
--oidc-username-claim=email

当使用Dex集群生成的ID令牌时,Kubernetes可以验证令牌并使用令牌验证用户。

当前的Dex版本不支持用OIDC连接器进行令牌刷新,所以Dex不会返回Google去确认该用户是否还具备登录权限。对此,我们已经在Github提交了请求,并且目前用我们的自定义实现。

连接kubectl——错误的打开放式

开始接触Dex,我用他们的示例程序生成了第一个ID令牌。
staticClients:
- id: kubernetes
redir 'http://127.0.0.1:5555/callback' # Allowed redirect URI
name: 'Kubernetes API'
secret: <SOME_SUPER_SECRET_STRING> # Pre-shared client-application secret

通过给Dex添加静态客户端并回调到127.0.0.1,我可以在笔记本电脑上运行示例程序,并用它生成我的第一个令牌。注意,Dex不会直接与应用程序交互,因此可以在回调地址上配置客户端。

Dex(和其他OIDC提供商)使用redirectURI的白名单来验证请求用户令牌的软件身份。认证过程的令牌交换阶段,通过向Dex发送包含redirectURI的初始请求,Dex向其已知的客户端(这次的场景是使用ID kubernetes)签发ID令牌,并期待客户端软件提供匹配的共享密钥。这保证了可信度并防止中间过程的人为攻击。
./example-app -client-id=kubernetes -client-secret=<SOME_SUPER_SECRET_STRING> -issuer=https://auth.example.com/dex -issuer-root-ca=ca.pem

上述命令启动了一个Web服务器,并监听127.0.0.1:5555(你可能注意到这正是Dex中redirectURI的一部分)。通过访问该地址,我可以开始登录流程,并生成一个ID令牌和一个刷新令牌。

有了这些信息,我在kubeconfig文件中添加了如下内容:

- name: joel.speed@pusher.com
user:
auth-provider:
config:
client-id: kubernetes
client-secret: <SOME_SUPER_SECRET_STRING> # Pre-shared client auth
id-token: <TOKEN_RETRIEVED_FROM_THE_EXAMPLE_APP>
idp-issuer-url: https://auth.example.com/dex
refresh-token: <REFRESH_TOKEN_RETRIEVED_FROM_THE_EXAMPLE_APP>
name: oidc

kubectl可以用该配置与Kubernetes群集交互,当ID令牌过期时,可以用刷新令牌获取新的ID令牌。

虽然这次尝试还算成功,但我不想推广这种登录方式,而想创建一个用户友好的登录方式。对我而言,这种需要检索密钥,运行一个工具,然后将信息从浏览器复制到kubeconfig的方式,算不上用户友好的方式。

连接kubectl——用户友好的方式

为了改善用户体验,我通过gcloud身份验证登录流程找寻灵感。如果你没有体验过gcloud登录,则可以在终端用命令打开浏览器的方式,打开Google的登录画面。登录后,它会指示您返回终端,告知您已登录且您的环境已配置。从Dex示例应用程序开始一步一步,我创建了一个工具(称为k8s-auth)。

作为入职的一部分,Pusher的工程师需要签入Vault。k8s-auth正是利用了这一点。我们在Vault中存储了k8s-auth的配置,在运行时使用工程师的Vault令牌将其加载到程序。因此,假如我们要改共享的客户端密钥,我们只需要更新Vault。

k8s-auth使用kubernetes客户端库中的代码为该用户配置kubeconfig,而不是在Web浏览器中出示令牌。由于我们的集群遵循命名规则,因此我还添加了一项功能,将新集群和相应上下文配置为同一应用程序的一部分。

当新工程师加入时,为了配置kubectl并连接到我们的集群,他们按照以下说明操作:
  • 按照我们的入职说明登录Vault
  • 安装k8s-auth和kubectl
  • 运行k8s-auth cluster1 cluster2 <想要连接的集群名>
  • 运行kubectl config set-context来选择群集。


如果我们撤销了他们的令牌,他们只需要运行一次k8s-auth来生成一个新的ID令牌和refresh令牌。
961a7f68-kube-sso.gif

总结

我们希望用户友好的SSO登录,能让我们的工程师可以更好的使用kubectl。我们发现我们喜欢gcloud的身份验证登录方式,并成功实现了。

通过对原有的扩展以及将集群的配置整合到同一个工具,我们的工程师现在可以通过一种简单的方式,对现有的及以后的集群进行kubectl配置。

虽然我无法开源我们特定版本的k8s-auth,但我创建了一个抽象版的例子。你可以原封不动使用该例子来体验OIDC登录流程,也可以将其作为你自己创建集群登录工具的范本。

话说,kubectl并不是工程师们访问API的唯一途径。Kubernetes Dashboard也不提供OIDC的登录方法。在下一篇文章中,我将介绍我们设计的Dashboard SSO登录方式,以及它的实现方法。

原文链接:Single Sign-On for Kubernetes: The Command Line Experience (翻译:Tiny Guo)

0 个评论

要回复文章请先登录注册