VMware Cloud 云计算管理平台 应用现代化 数字化工作空间 混合云平台

TKGS用户管理系统的集成方案

VMware越来越多的客户都在使用vSphere with Tanzu 中的Kubernetes的服务TKGS(原名Guest Cluster)来部署企业的Kubernetes工作负载。要在生产环境中使用K8S集群,一般来说需要和企业的其他系统环境进行有机的集成,例如网络,存储等硬件资源环境以及其他IT软件系统。有许多合作伙伴和客户最近向我咨询:如何将企业原有的用户身份管理系统和TKGS进行有机的集成。

这是一个非常合理的需求,谁也不会希望看到新上的系统和原有系统有两套不同的需要管理的用户访问控制系统。通常来说,企业用户会使用OIDC来集成Kubernetes的用户管理和认证系统。OIDC是(OpenID Connect)的缩写,是Kubernetes原生系统就支持的用户身份认证的扩展机制。不少其他的K8S系统都支持OIDC的扩展,例如IBM的OpenShift, VMware另一款的K8S产品(VMware Tanzu) (注意: VMWare Tanzu和vSphere with Tanzu是两个不同的产品)。

但是TKGS并不支持OIDC的扩展。在TKGS集群里,用户管理机制是vSphere SSO。(如果想详细了解vSphere with Tanzu,以及缺省用户管理机制的知识,请参考我之前的文章:vSphere with Kubernetes实战之:用户访问控制)。用户想要访问TKGS集群,一定要在vCenter Server中先创建SSO用户账号。

TKGS是款受管的K8S集群产品。所谓受管,意味着该集群的Master节点和worker节点都是系统替你维护的,集群网络配置,存储挂载,节点伸缩,扩展以及故障恢复这些高可用特性都是系统自动管理的。受管的K8S产品给客户带来很大的便利条件,让客户将关注的重点放在自己的工作负载就行了。但是受管的集群的缺点就是灵活性,它的Master节点和Worker节点的配置是实现定义好的,不能随意更改。这也是TKGS不能修改Master节点的配置使它支持OIDC的身份管理扩展的原因。其实很多受管的K8S产品也一样,例如Google的GKE,AWS的EKS等等,它们的K8S用户身份管理系统也只能使用自己的云管身份系统,也不能使用OIDC。

本文介绍了5种解决方案,在这种受管的TKGS环境中,如何来实现将企业原有的用户身份管理系统和TKGS集群(Guest Cluster)进行有机的集成:

  1. 等待vSphere7的未来版本中更强的Identity Provider Federation。
  2. 等待TKGS的未来版本中OIDC扩展的支持
  3. 等待TKGS的未来版本中Bring Your Own Image的特性
  4. 利用Service Account来进行用户管理
  5. 利用OIDC Proxy来进行用户管理的扩展和集成

当然,上面有很些方案当前还不具备条件,需要等待未来的某个vSphere版本或者TKGS的版本。本人最推荐的是利用OIDC Proxy的方案,同时兼备通用性和安全性的优势。在文中不仅介绍的这种方案的架构原理,还给出了在vSphere with Tanzu环境中详细的安装和部署过程,以供大家参考。

1. Kubernetes用户认证和授权系统


虽然这篇文章主要说的是Kubernetes的用户认证,但有意思的是,Kubernetes自己根本没有用户的概念。什么”User”,”Group”这些概念在Kubernetes内部是不存在的。Kubernetes内部只有”Service Accounts”,”Role”,”RoleBinding”这些概念。换句话说,Kubernetes内部只有鉴权的机制(RBAC),而没有用户管理和认证机制。用户管理和认证的功能被Kubernetes代理给其他的系统来完成,例如Service Account, X509 Client Certificates, Authenticating Proxy, OpenID Connect (OIDC), 或者Webhook Token Authentication等等。要想获得有关Kubernetes和认证相关的详细信息,请参考官方文档:https://kubernetes.io/docs/reference/access-authn-authz/authentication/

举个例子,下面定义的Role和RoleBinding资源,描述了一个典型的基于角色的权限控制(RBAC)。角色devrole在default命名空间里拥有对pods和deployments的一些操作权限。而用户[email protected] 被赋予了这个角色,拥有这些权限。

TextDescription automatically generated

而这个用户是哪来的,怎么认证的,Kubernetes集群会代理给其他系统来完成。例如,通过对请求里X509 Client Certificates的认证审核,在将证书里的cn字段取出来,如果cn里的用户名是[email protected], 那我们认为这个请求就是这个用户发出来的,可以允许在角色范围内对资源进行相应的操作。

要想将Kubernetes的用户认证功能和企业自己的用户系统结合起来,最流行的方式一般是OpenID Connect (简称OIDC), 或者Webhook Token Authentication。OpenID Connect 是将用户管理和认证的功能代理给符合OAuth2协议的身份提供者, 例如 Azure Active Directory, Salesforce, 和 Google等等。OIDC其实是OAuth2的一个扩展,它在认证后返回一个 ID Token。这个token的以JSON Web Token (JWT)为格式,包含了众所周知的字段,像用户名,邮件等。最重要的是这个Token是被身份提供者进行了数字签名的。可是一般国内用户很少会用Azure,谷歌的用户管理系统,企业一般要求使用自己内部的用户身份管理系统。因此另外一个开源的OIDC的身份提供者:Dex (https://dexidp.io/ ) 变得非常流行,Dex本身不提供用户管理,但它可以桥接到外面的身份系统,例如企业常用的LDAP。Dex和Kubernetes的OIDC认证功能结合在一起,就非常实用和强大了。

无论是OIDC还是Webhook Token Authentication,都需要改动API Server的配置文件和启动参数,这就给受管的Kubernetes集群带来了一定的阻力。因为受管的K8S服务群的配置一般都不在用户的控制之中。例如,OIDC的配置需要修改以下API Server的启动参数,而TKGS很难做到。

TextDescription automatically generated

2. TKGS 当前的用户认证系统


kubectl vsphere login
从下面是当前版本中,TKGS(Guest)进行用户登录的命令:

–server=SUPERVISOR-CLUSTER-CONTROL-PLANE-IP
–tanzu-kubernetes-cluster-name
TANZU-KUBERNETES-CLUSTER-NAME
–tanzu-kubernetes-cluster-namespace
SUPERVISOR-NAMESPAC-NAME
–vsphere-username
NAMESPACE-ADMIN-SSO-USER-NAME


可以看到虽然我们要登录的是TKGS(Guest),但我们在server的参数中需要输入supervisor cluster的地址。也就是说每次登录Guest,身份校验都是在Supervisor集群中进行的。事实上,整个TKGS的用户登录和验证系统由kubectl plugin,supervisor集群,VC SSO模块,和TKGS的Webhook Token Authentication模块组成。如下图所示:

DiagramDescription automatically generated
  • 用户登录的动作由kubectl的插件 (名为vsphere)发起,用户提供用户名和密码。①
  • Supervisor集群中Auth Proxy组件使用传入的用户名和密码发起VC SSO登录的请求。②
  • 登录成功后 VC SSO将返回一个JWT Token,并将TKGS的API Server的地址也一起返回给客户端。③
  • kubectl的vsphere插件将返回的Token保存到客户端kuebconfig配置文件中。④
  • kubectl的vsphere插件再向TKGS的API Server发出相应的请求。⑤
  • TKGS的API Server将请求中所带的Token交给Webhook Token Authentication进行验证。⑥
  • 验证通过后由API Server决定当前请求是否有权限执行。⑦
  • 在TKGS创建的时候,应该就将VC SSO的证书导入到TKGS里,以便Webhook Token Authentication进行Token校验。0️⃣

由上可见,TKGS的用户管理和认证是个深度定制的系统,这和其他受管的Kubernetes集群是一样的。而且当前只支持VC SSO的用户认证体系。

客户的担心主要有两个,一是vSphere SSO虽然支持身份联盟协议(Identity Provider Federation),但是目前只支持微软的ADFS(Active Directory Federation Services), 并不能很好的集成现有的用户身份管理系统。另外,从上图看出,这个高度定制化的受管集群并不支持OIDC扩展,来满足自定义用户身份验证的系统。

我有的朋友通过访问TKGS集群的节点服务器(如何访问节点,请详见:https://blogs.vmware.com/china/2020/05/02/vsphere-with-kubernetes-nodeaccess/),强行对API Server的配置信息进行修改,加入OIDC的配置,并且重启API Server。这种做法居然成功了,但是我们并不推荐。因为这不是优雅的解决方案,会带来很多问题。受管的集群会自动对你的节点进行管理,进行故障恢复或者跨域迁移。因此,你手动做的配置修改不会被持久保留。要想真正解决用户管理系统的集成,请参考下面的内容。

3. 五大集成方案解决TKGS的用户管理系统

3.1 等待vSphere7的未来版本中更强的Identity Provider Federation

在开发团队内部,对这个TKGS的自定义用户管理需求也有很激烈的讨论。当前TKGS的用户认证的功能有两个很迫切的需求,一是vSphere SSO对大多数不是微软AD的用户是不支持的,二是TKGS是个受管的Kubernetes集群,无法配置API Server的OIDC的参数。这两个问题只要解决一个就行了。讨论的主要焦点在于是用上面哪个解决方案。

更大的声音是支持第一种方案,也就是扩展vSphere SSO的能力,使它支持更多的Identity Provider。他们认为配置用户管理系统,认证系统这些任务,应该是系统管理员的职责,在整个集团层面上总体配置。而不是让每个创建的TKGS集群都自己配置OIDC,这样不仅配置工作量大,还容易出错。在整个vSphere集群统一配置Identity Provider,使受管TKGS集群的管理,配置和维护更加简单有效。

具体的架构设计如下:在vCenter Server中将内嵌了一个Identity Management系统(很大可能是VMware自己的IDM:WorkSpaceOne,简称WS1),使得vCenter Server成为一个OAuth2的客户端应用。因此vCenter Server可以用OAuth2标准的协议和后面各种OIDC的提供者相连,例如Dex。然后再修改之前的kubectl vsphere插件,让这个插件在本地打开用户桌面的浏览器,来完成用户登录过程,获得TKGS所需要的JWT Token。具体的流程如下图所示:

DiagramDescription automatically generated
  • Kubectl 的vsphere插件在发现本地kubeconfig配置文件中的Token不存在或者过期了,就会在本地桌面打开浏览器①,连接到Supervisor集群的Auth Proxy上②。
  • Supervisor集群的Auth Proxy会根据配置信息,将浏览器重新定向到WorkSpaceOne的登录页面③④
  • WorkSpaceOne会根据配置信息完成OIDC的登录过程⑤⑥
  • WorkSpaceOne将登录登录结果和用户信息封装成 WS1 Token。 ⑦
  • Supervisor集群的Auth Proxy将得到的WS1 Token到Token Exchange Service换成JWT Token。⑧⑨
  • Kubectl 的vsphere插件将获得的JWT Token保存到本地的kubeconfig文件里。(A)
  • Kubectl 向TKGS的API Server发出带有JWT Token的请求。(B)
  • TKGS的API Server从Supervisor集群中获得OIDC的证书,通过Webhook Token Authentication校验JWT Token。(CD)
  • 如果检验通过,返回执行的结果。(E)

这个解决方案的优势在于只需要对这个vSphere集群进行统一配置,而在创建TKGS服务的时候,不再需额外的配置步骤,大大简化了操作的复杂程度。但需要注意的是,这个解决方案当前并不可用,需要等到vSphere未来的某个版本(可能是vSphere7U3或以后),才能使用。

3.2等待TKGS的未来版本中对OIDC扩展的支持

在上节的内容中我介绍到,面对TKGS的用户管理功能的需求,研发团队有着激烈的讨论。更大的声音是支持第一种方案,也就是扩展vSphere SSO的能力。但是也有不少架构师认为,尽管扩展vSphere SSO的能力很重要,对于每个TKGS集群,也有个性化用户管理的需求。换句话说,数据中心管理员(VI Admin)在整个vSphere集群范围内设置了vSphere SSO,但某个部门的TKGS集群出于某种目的(例如,测试)仍然需要设置自己的用户管理系统。因此在未来的某个TKGS版本,也会出现对OIDC扩展的支持。例如,下图展示了一个可自定义OIDC的TKGS配置文件:

TextDescription automatically generated

这个解决方案的优势在于,可以为每个TKGS都配置不同的OIDC扩展。但需要注意的是,这个解决方案当前并不可用,需要等到vSphere未来的某个版本(可能是vSphere7U3或以后),才能使用。

3.3等待TKGS的未来版本中Bring Your Own Images的特性

在创建TKGS的时候,需要在vCenter Server的Content Library里导入指定的虚机模板,这个虚机模板里指定了相应的操作系统的类型和版本(当前只支持VMware自己的Linux操作系统:Photon OS),并且包含了所有需要运行TKGS服务的所有相关软件包。在当前版本中,这个虚机模板只能用VMware官方指定的镜像。

在未来的版本中,TKGS会提供”Bring your Own Images”的特性。你可以通过官方提供的“Image Builder”来打包你自己的虚机模板,包括不同于Photon OS的操作系统(例如Ubuntu),以及不同的组件的配置参数,还可以自己修改相应的启动脚本。

这个特性完全打开了自定义TKGS的想象空间,除了可以配置自定义的OIDC以外,还可以配置各种Kubernetes各种组件的性能参数,来满足个性化定制的需求。但需要注意的是,这个解决方案当前并不可用,需要等到TKGS未来的某个版本(可能是vSphere7U3或以后),才能使用。

3.4利用Service Account来进行用户管理

在当前的版本下,受管的TKGS集群是很难修改API Server的启动参数来配置相应OIDC Provider,但是还是有别的解决方案,可以实现自定义用户的认证系统。使用Service Account是其中的一个方法。

在前文中说过,其实Kubernetes内部根本没有User这个概念,有的只是Service Account。Service Account其实User的概念不一样,User是给人用的,而Service Account主要是给跑在Pod里的应用程序用的。要了解Service Account的详细信息,请参见Kubernetes官方文档:(https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/)看看下面的例子,来理解如何用Service Account来完成用户认证的功能。

  • ServiceAccount的对象并不是全局的,是属于每个namespace的。我们创建一个名为”users”的命名空间,专门用来存放用于认证的Service Accounts。
$ kubectl create ns users
  • 通过kubectl命令,创建一个名为”wangyu”的Service Account
$ kubectl -n users create serviceaccount wangyu
serviceaccount/wangyu created
  • 通过kubectl命令,给这个用户绑定一个角色,使得这个用户拥有一定的权限。
$ kubectl create clusterrolebinding new-admin --clusterrole=cluster-admin --serviceaccount=users:wangyu
clusterrolebinding.rbac.authorization.k8s.io/new-admin created
  • 通过kubectl命令,获取这个Service Account所对应的Token值。
$ kubectl -n users get serviceaccount/wangyu -o jsonpath='{.secrets[0].name}'
wangyu-token-bclth

$ kubectl -n users get secret wangyu-token-bclth -o jsonpath='{.data.token}'| base64 –decode
eyJhbGciOiJSUzI1NiIsImtpZCI6Img2bVdQbUxQOTBlXzZOTDhhLW9KVmg0TkxKNkdnVXN
ERHprRThpVng1RU0ifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3V
iZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJ1c2VycyIsImt1YmVybm
V0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJ3YW5neXUtdG9rZW4tYmNsd
GgiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1l
……
  • 构造一个kubeconfig.yaml配置文件,将上面的Token值写到文件中相应的位置,如下图所示。配置文件中Cluster的参数,例如API Server地址和证书,可以很容易从你的K8S的集群中获得。
TextDescription automatically generated
  • 使用当前这个配置文件,就可以让kubectl命令客户端来访问TKGS集群了。而且当集群里删除这个ServiceAccount的时候,当前的配置文件也会跟着失效。
$ export KUBECONFIG=kubeconfig.yaml

$ kubectl get nodes
NAME STATUS ROLES AGE
tkc-large-control-plane-ngzqw Ready master 9d
tkc-large-workers-r44kx-764978f997-gc9k2 Ready <none> 9d
tkc-large-workers-r44kx-764978f997-gsfzq Ready <none> 9d
$ kubectl -n users delete serviceaccount wangyu
serviceaccount "wangyu" deleted

$ kubectl get nodes
error: You must be logged in to the server (Unauthorized)

回顾一下上面使用Service Account的步骤。需要说明的是所有这些步骤都可以使用Kubernetes Client SDK编写程序来自动完成。使用Service Account作为用户管理和认证的机制如下:

  • 系统管理员会给用户配置的相应的权限信息,例如:张三能访问集群“Cluster1”的“dev”命名空间下的Pods和deployments资源。系统会根据这个配置信息自动生成一个kubeconfig的配置文件,将这个配置文件存储在用户数据库中,和当前的用户绑定在一起。
  • 用户登录到企业自己的登录系统,登录成功后,页面提供链接可以下载这个kubeconfig配置文件。
  • 用户设置kubectl的环境变量,使用这个配置文件来访问TKGS集群。
  • 管理员要收回这个用户的访问权限,只需在集群中要删除相应的Service Account。

这个解决方案的优势在于简单,不需要额外部署OIDC的其他Identity Provider系统,和企业的用户管理能很好的结合在一起。而且非常适用于多个集群的权限设置。如果企业部署了多个独立的K8S集群,而每个用户需要配置在这些集群里的权限,这个解决方案能够很容易办到,因为一个kubeconfig的配置文件中可以配置多个context,包含多个Service Account Token。用户只要下载一次这个文件,就能访问多个集群,非常方便。

但是这个解决方案有个很大的缺点,就是安全问题。其他的解决方案中客户端在向API Server发请求的时候,所带的Token都是JWT Token,这种Token是有时效的,从30分钟到10个小时不等,可以由管理员设置。当这个Token失效,需要用户重新登录来获得新的Token。而Service Account Token会一直有效。当用户获得了这个kubeconfig配置文件,可以一直访问K8S集群,直到这个Service Account被删除为止。因此,只有当你的Kubernetes集群中对安全性要求不是很高的时候,才会采用这个解决方案。

3.5利用OIDC Proxy来进行用户管理的扩展和集成

VMware的TKGS并不孤单,Google的GKE,AWS的EKS等受管的Kubernetes集群也一样,缺少灵活性,它的Master节点和Worker节点的大部分配置参数是事先定义好的,不能随意配置OIDC来自定义用户的认证系统。对于这些K8S的产品,现在较为推荐的解决方案是使用 OIDC Proxy的方式。既可以使用OIDC扩展,也可以不用修改Master节点API Server的启动参数,这也是本文最推荐的解决方案。这个解决方案不仅可以用于TKGS,还可以用于其他各种受管的Kubernetes集群的认证。因此在下文中,我先介绍这个方案的基本原理和流程,然后给出在TKGS上的详细部署指南。

OIDC Proxy解决方案需要安装三个组件:kubectl插件kubelogin (https://github.com/int128/kubelogin) ,名为“Kube-OIDC-Proxy”的软件项目(https://github.com/jetstack/kube-oidc-proxy),以及上文提到的Dex(https://dexidp.io/docs/kubernetes/)。Kube-OIDC-Proxy是最主要的组件,它位于客户端和Kubernetes的API Server之间。kubectl客户端将所有发给Kubernetes API Server的请求都发给Kube-OIDC-Proxy,而Kube-OIDC-Proxy在截获了客户端的请求后,在Proxy这一层面进行用户身份验证。从名字上就可以看出,Kube-OIDC-Proxy进行用户验证就是通过OIDC扩展的方式来进行。进行验证通过之后,再将客户端的请求转发给真正的Kubernetes API Server。可以看到,这个方案将OIDC扩展点从API Server转移到Proxy上,因此根本不需要在受管的Kubernetes API Server上修改启动参数,添加OIDC的扩展配置信息。

另外,在Kube-OIDC-Proxy成功校验用户身份后,如何使用当前用户的身份来讲请求转发给Kubernetes API Server的呢?这个问题很重要,因为是Kubernetes API Server最后来决定哪个用户有哪些权限,可以操作集群内部哪些资源,所以Kube-OIDC-Proxy发请求给API Server的时候,一定要带上用户的信息。这是通过Kubernetes Impersonation的机制来实现的,这就像Linux的系统中的Sudo一样,可以别的用户身份来运行某个命令。详细的机制原理,请参考Kubernetes的官方文档(https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation)。

DiagramDescription automatically generated

这个解决方案具体的流程如下:

  • 实现创建好一个ServiceAccount账号给Kube-OIDC-Proxy用来连接TKGS,这个账号需要有impersonation的权限。0️⃣
  • 在执行kubectl目录的时候,kubelogin插件会自动探测当前请求是否存在有效的Token,如果不存在,或者Token过期,就会打开本地的一个浏览器窗口连接Dex的登录页面。①
  • Dex通过配置好的LDAP数据库,来验证用户的登录信息是否有效。并返回登录结果。②③④
  • Kubelogin用登录的结果去Dex换取JWT Token(OAuth2认证的一部分),并将这个JWT Token保存到kubeconfig文件中。⑤
  • Kubectl 向Kube-OIDC-Proxy发出带有token的请求。⑥
  • Kube-OIDC-Proxy根据配置信息从Dex的服务器上获得证书CA,并对JWT Token进行验证。⑦⑧
  • 验证成功后,Kube-OIDC-Proxy向TKGS的API Server发出带有Impersonation的请求,TKGS的API Server根据Impersonation的用户信息,校验改用户是否有权操作相应的资源,并将结果返回给Kube-OIDC-Proxy。⑨ (Α)
  • Kube-OIDC-Proxy将结果返回给kubectl客户端。(B)

这个方案具有通用性和安全性的优点,是目前颇为流行的一种受管集群用户认证集成的解决方案。

4. OIDC Proxy方案的完整部署指南

这个方案的概念验证过程如下,需要安装和配置4个组件:

4.0 准备好TKGS的环境

请参考我之前的文章:vSphere with Kubernetes实战之:用户访问控制 (https://blogs.vmware.com/china/2020/04/27/vsphere-with-kubernetes-iam/

4.1 安装配置OpenLDAP

  • 首先为OpenLDAP服务创建基本的配置信息,例如管理员用户名和密码,还可以添加一些别的用户:
$ kubectl create secret generic openldap --from-literal=adminpassword=123456 --from-literal=users=user1 --from-literal=passwords=123456
  • 通过kubectl命令部署openldap。可以参考bitnami官方文档来部署openldap镜像(https://docs.bitnami.com/tutorials/create-openldap-server-kubernetes/),也可以从我的github上直接部署:
$ kubectl apply -f https://raw.githubusercontent.com/yuwang881/tkgs-auth/main/openldap-deployment.yaml
  • 检查LDAP安装是否成功,记住为OpenLDAP分配的外部IP地址。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
openldap-588fb47457-phlr8 1/1 Running 0 10d

$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
openldap LoadBalancer 10.109.15.52 10.117.233.4 1389:32130/TCP 10d
  • 为OpenLDA创建用户样例数据。在本例中名为usradd.ldif的文件。
$ cat usradd.ldif

dn: uid=yuwa,ou=users,dc=example,dc=org
cn: yuwa
sn: yuwa
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
gidNumber: 200015
uidNumber: 200015
loginShell: /bin/bash
homeDirectory: /home/yuwa
mail: [email protected]
uid: yuwa
  • 将用户数据导入到LDAP里。在MacOS里,ldapadd的命令是自带的。如果是别的操作系统,可能要自行安装ldap客户端程序。OpenLDAP的IP地址是上面获得的服务地址。OpenLdap的管理员用户名和密码是我们在第一步配置的信息。“dc=example. dc=org”是缺省的root。
$ ldapadd -h 10.117.233.4:1389 -D cn=admin,dc=example,dc=org -w 123456 -f usradd.ldif
  • 核实用户数据是否成功导入。应该能从输出的内容发现刚才导入的用户信息。
$ ldapsearch -x -h 10.117.233.4:1389 -b 'dc=example,dc=org'

4.2 安装配置Dex

  • 首先为dex创建单独的命名空间
$ kubectl create ns dex
  • OIDC的协议一般都需要https协议,因此要为dex创建密钥和证书。openssl-dex.conf是用openssl签名所需要的配置文件,我将dex服务设置为”dex.vmware.com”。你可以根据自己的需要修改。签名后在当前目录下生成两个文件,一个事密钥文件openid-key.pem,另一个是证书文件openid-ca.pem。
$ cat openssl-dex.conf 

[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = dex.vmware.com


$ openssl req -new -x509 -sha256 -days 3650 -newkey rsa:4096 -extensions v3_req -out openid-ca.pem -keyout openid-key.pem -config openssl-dex.conf -subj "/CN=kube-ca" -nodes
  • 在dex的命名空间里创建一个名为”dex.vmware.com.tls”的secret,这个secret在安装Dex的时候需要用到。
$ kubectl create secret tls dex.vmware.com.tls --key openid-key.pem --cert openid-ca.pem -n dex
  • 部署dex镜像和服务。可以从我的github中下载这个yaml文件,并做相应的修改。(https://raw.githubusercontent.com/yuwang881/tkgs-auth/main/dex-deployment.yaml)
$ kubectl apply -f dex-deployment.yaml
  • 查看负载均衡器为Dex服务分配的外部地址。
$ kubectl get services -n dex

NAME TYPE                CLUSTER-IP     EXTERNAL-IP PORT(S)             AGE
dex      LoadBalancer 10.105.43.168 10.117.233.7     443:31672/TCP 4d6h
  • 我们刚才为Dex服务创建的证书是基于DNS(dex.vmware.com),因此对Dex服务的访问都应该基于此主机名,而不是IP地址。由于在我测试环境中dex.vmware.com并不是个合法的名字,我只能在本机修改“/etc/hosts”文件来添加DNS记录。如果你的主机名是可以路由的DNS记录,则可以跳过此步骤。
$ cat /etc/hosts
10.117.233.5 dex.vmware.com

4.3 安装配置kube-oidc-proxy

  • 首先为dex创建单独的命名空间
$ kubectl create ns kube-oidc-proxy
  • 为kube-oidc-proxy创建密钥和证书。openssl-proxy.conf是用openssl签名所需要的配置文件,我将此proxy服务设置为”oidcproxy.vmware.com”。你可以根据自己的需要修改。签名后在当前目录下生成两个文件,一个事密钥文件proxy-key.pem,另一个是证书文件proxy-ca.pem。
$ cat openssl-proxy.conf

[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = oidcproxy.vmware.com

$ openssl req -new -x509 -sha256 -days 3650 -newkey rsa:4096 -extensions v3_req -out proxy-ca.pem -keyout proxy-key.pem -config openssl-proxy.conf -subj "/CN=kube-ca" -nodes
  • 在kube-oidc-proxy的组件里根据配置需要通过(https协议)连接刚才所配置的dex服务。由于我的”dex.vmware.com” 并不是个合法可路由的名字。因此为了在TKGS内部能够识别这个DNS记录,可以修改coredns的配置文件,加上下面的rewrite命令。
$ kubectl edit configmap coredns -n kube-system



prometheus :9153

rewrite name dex.vmware.com dex.dex.svc.cluster.local

  • 创建kube-oidc-proxy服务所需要的tls secret。
$ kubectl create secret tls kube-oidc-proxy --key proxy-key.pem --cert proxy-ca.pem -n kube-oidc-proxy
  • 创建kube-oidc-proxy服务所需要的其他配置。包括dex服务地址,证书信息,clientid(在dex配置文件中指定的)等等
$ kubectl create secret generic kube-oidc-proxy-config --from-file=oidc.ca-pem=./openid-ca.pem -n kube-oidc-proxy

$ kubectl create secret generic kube-oidc-proxy-config1 \
--from-literal=oidc.username-claim=email \
--from-literal=oidc.issuer-url='https://dex.vmware.com' \
--from-literal=oidc.client-id=example-app \
-n kube-oidc-proxy
  • 部署kube-oidc-proxy的镜像和服务。可以从我的github中直接部署这个yaml文件,也可以下载根据自己的需求做相应的修改。(https://raw.githubusercontent.com/yuwang881/TKGS-auth/main/kube-oidc-proxy.yaml)
$ kubectl apply -f https://raw.githubusercontent.com/yuwang881/tkgs-auth/main/kube-oidc-proxy.yaml
  • 查看负载均衡器为kube-oidc-proxy服务分配的外部地址。
$ kubectl get services -n kube-oidc-proxy

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
kube-oidc-proxy LoadBalancer 10.109.53.21 10.117.233.6 443:30569/TCP
  • 我们刚才为kube-oidc-proxy服务创建的证书是基于DNS(oidcproxy.vmware.com),因此对Dex服务的访问都应该基于此主机名,而不是IP地址。由于在我测试环境中oidcproxy.vmware.com并不是个合法的名字,我只能在本机修改“/etc/hosts”文件来添加DNS记录。如果你的主机名是可以路由的DNS记录,则可以跳过此步骤。
$ cat /etc/hosts

10.117.233.5 dex.vmware.com
10.117.233.6 oidcproxy.vmware.com

4.4 安装配置kubelogin插件

  • 安装kubelogin插件。官网地址(https://github.com/int128/kubelogin)。如果是MacOS,可以通过以下命令来安装。
$ brew install int128/kubelogin/kubelogin
  • 创建一个测试用的Role和RoleBinding,和LDAP里的用户联系起来,请参考(https://raw.githubusercontent.com/yuwang881/tkgs-auth/main/rolebinding.yaml)。
$ kubectl apply -f https://raw.githubusercontent.com/yuwang881/TKGS-auth/main/rolebinding.yaml
  • 创建一个kubectl客户端使用的配置文件,可以参考(https://raw.githubusercontent.com/yuwang881/tkgs-auth/main/kubelogin.yaml)。如下图所示。其中certificate-authority-data需要换成kube-oidc-proxy的证书。可以用(cat proxy-ca.pem | base64)命令获得。另外还需要oidc用户的配置,将oidc-issuer-url指向dex服务的地址,client-id和client-secret需要和dex配置得一样。

    TextDescription automatically generated
  • 将KUBECONFIG的配置文件指向你个新创建的yaml文件。然后执行任意标准的kubernetes命令。
$ export KUBECONFIG=./kubelogin.yaml

$ kubectl get pods
  • Kubelogin插件会自动打开本地浏览器,进行LDAP登录。一旦成功登录,kubectl的命令会自动返回结果。如下图所示。我们是用的缺省的dex登录页面,你也可以根据企业的需求,自定义登录页面。

    Graphical user interfaceDescription automatically generated

5. 总结

TKGS是个受管的Kubernetes集群,当前版本下无法通过OIDC的扩展方式来自定义用户认证。本文介绍了5种不同的解决方案,其中最推荐的是使用kube-oidc-proxy进行前置认证代理,并且结合LDAP的测试环境,给出了详细的配置过程,感兴趣的朋友们可以按照文中的步骤来测试此方案。