TKEStack 中的认证与鉴权

Author: LeoRyu

认证鉴权对于 K8s 而言可以说是最为复杂、灵活和关键的部分,本文将介绍 TKEStack 中认证鉴权机制是如何运作的。

开始之前

由于认证鉴权涉及的相关知识很多,为了避免读者在下面探究 TKEStack 认证鉴权机制时查处相关名词知识,在开始之前先介绍一些本文涉及到的知识概念。

K8s 中的一些身份认证方式

  • X509 客户证书。通过给 API 服务器传递 --client-ca-file=SOMEFILE 选项,就可以启动客户端证书身份认证。 所引用的文件必须包含一个或者多个证书机构,用来验证向 API 服务器提供的客户端证书。 如果提供了客户端证书并且证书被验证通过,则 subject 中的公共名称(Common Name)就被 作为请求的用户名。

  • 静态令牌文件。当 API 服务器的命令行设置了 --token-auth-file=SOMEFILE 选项时,会从文件中 读取持有者令牌。目前,令牌会长期有效,并且在不重启 API 服务器的情况下 无法更改令牌列表。

  • 服务账号令牌。服务账号(Service Account)是一种自动被启用的用户认证机制,使用经过签名的 持有者令牌来验证请求。服务账号通常由 API 服务器自动创建并通过 ServiceAccount 准入控制器 关联到集群中运行的 Pod 上。 持有者令牌会挂载到 Pod 中可预知的位置,允许集群内进程与 API 服务器通信。 服务账号也可以使用 Pod 规约的 serviceAccountName 字段显式地关联到 Pod 上。

  • OpenID Connect(OIDC)令牌。OpenID Connect 是一种 OAuth2 认证方式, 被某些 OAuth2 提供者支持,例如 Azure 活动目录、Salesforce 和 Google。 协议对 OAuth2 的主要扩充体现在有一个附加字段会和访问令牌一起返回, 这一字段称作 ID Token(ID 令牌)。详情可参考 https://openid.net/connect/

更多认证相关信息可参考 用户认证[1]。

K8s 中的一些鉴权方式

  • Node。一个专用鉴权组件,根据调度到 kubelet 上运行的 Pod 为 kubelet 授予权限。
  • ABAC。基于属性的访问控制(ABAC)定义了一种访问控制范型,通过使用将属性组合 在一起的策略,将访问权限授予用户。策略可以使用任何类型的属性(用户属性、资源属性、 对象,环境属性等)。
  • RBAC。基于角色的访问控制(RBAC)是一种基于企业内个人用户的角色来管理对 计算机或网络资源的访问的方法。在此上下文中,权限是单个用户执行特定任务的能力, 例如查看、创建或修改文件。
  • Webhook。WebHook 是一个 HTTP 回调:发生某些事情时调用的 HTTP POST; 通过 HTTP POST 进行简单的事件通知。实现 WebHook 的 Web 应用程序会在发生某些事情时 将消息发布到 URL。
  • AlwaysAllow。允许所有请求。仅在你不需要 API 请求 的鉴权时才使用。
  • AlwaysDeny。阻止所有请求。仅用于测试。

更多认证相关信息可参考 鉴权概述[2]。

Casbin

Casbin 是一款轻量级的开源访问控制框架,支持 PERM 模式(Policy,Effect,Request,Matchers),相关概念如下:

  • Request:定义了请求的元组对象,至少包含访问实体(sub)、访问的资源(obj)和行为(Action),例如:r={sub, obj,act}。
  • Policy:定义了鉴权规则各字段的名称和顺序,至少包含访问实体(sub)、访问的资源(obj)和行为(Action),例如:p={sub, obj, act}。
  • Matchers:定义了 Request 和 Policy 的匹配规则。
  • Effect:用于对所有 Matchers 匹配后的结果,再进行一次逻辑组合判断(例如:e = some(where (p.eft == allow)) && !some(where (p.eft == deny)),这个例子组合的逻辑含义是:如果有匹配出结果为 alllow 的策略,并且没有匹配出结果为 deny 的策略,则结果为真,如果有任何deny,都为假)。

关于本项目详细信息可以参考 Casbin 概述[3]。

两种认证鉴权场景

TKEStack 扩展 K8s API 的方式是通过 aggregated apiserver[4] 实现的,这种方式与 CRD 的方式不同,每一个扩展组件都可以被视为一个独立的 APIServer,这使得 TKEStack 的认证鉴权相较之下更加灵活,但也更加复杂。为了更加方便和清晰地展示认证鉴权的流程,这里我们分为两种场景分别展开:第一种是用户通过浏览器由 tke-gateway 入口访问各个组件的资源;第二种是用户通过 kubectl 由 kube-apiserver 入口访问各个组件的资源。

由浏览器发起的访问

认证

用户通过浏览器登陆访问的用户信息并不是 K8s 集群可以识别的用户,无法由集群本身进行认证流程,需要外部的 OIDC provider 进行认证。在 TKEStack 中承担此工作的是 tke-auth 组件,tke-auth 中是通过 dex 实现的 OIDC 服务。

在由浏览器发起的访问场景下,认证流程的链路大致分为两步骤:

  1. 用户浏览器中登录 -> tke-gateway -> tke-auth返回认证信息凭证 -> 设置访问凭证到浏览器
  2. 已有访问凭证的前端 -> tke-gateway -> tke-xxxx -> tke-auth校验认证凭证

整个认证过程中数据传输都是通过浏览器或是 TKEStack 系统组件完成的,没有 kube-apiserver 的参与。

鉴权

当前版本 TKEStack 系统组件的鉴权模式默认是以 SubjectAccessReview 继承了 kube-apiserver 的鉴权模式,而 kube-apiserver 中鉴权模式配置了 webhook 指向了 tke-auth 组件。

tke-auth 中的鉴权是基于 casbin 实现的,基于其 PERM 模型 TKEStack 完成了一套 RBAC 模型的实现:

[request_definition]
r = sub, dom, obj, act

[policy_definition]
p = sub, dom, obj, act, eft

[role_definition]
g = _, _, _

[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))

[matchers]
m = g(r.sub, p.sub, r.dom) && keyMatchCustom(r.obj, p.obj) && keyMatchCustom(r.act, p.act)
  • request_definition:定义了模型的 Request
  • policy_definition:定义了模型的 Policy
  • role_definition:定义了模型的用户和角色的映射关系, 三个空缺分别表示用户, 角色, 域,TKEStack 使用的域为业务 ID
  • policy_effect:定义了模型的 Effect
  • matchers:定义了模型的匹配方式,keyMatchCustom 为自定义匹配函数,支持以正则匹配和通配符的方式,匹配 Role 和 Policy 的字段

用户通过浏览器访问场景下 TKEStack 的鉴权流程整个链路如下:

用户浏览器发起请求 -> tke-gateway -> tke-xxx -> kube-apiserver webhook -> tke-auth返回鉴权结果

集群内由 kubectl 发起的请求

认证

集群内通过 kubectl 发起请求场景下的认证流程与 K8s 本身的认证流程基本无异,因此整个链路也非常简单:

kubectl 读取 kubeconfig 中的认证信息 -> kube-apiserver 检验认证信息

由于此场景下的用户信息是可以被 K8s 识别的,且 kubectl 是直接连接 kube-apiserver 的,认证流程在请求到达 TKEStack 系统组件之前就完成了。

鉴权

之前在由浏览器发起访问场景中已经提到 TKEStack 系统组件的鉴权模式是以 SubjectAccessReview 继承了 kube-apiserver 的鉴权模式,这种模式也同样适用于集群内由 kubectl 发起请求的场景,只不过在 kube-apiserver 中生效的鉴权模式不再是指向 tke-auth 的 webhook,而是 K8s 的 RBAC/ABAC 模式。

整个鉴权流程的链路如下:

kubectl 发起请求 -> kube-apiserver -> tke-xxx -> kube-apiserver 返回 RBAC/ABAC 鉴权结果

[1] Kubernetes 用户认证 [https://kubernetes.io/zh/docs/reference/access-authn-authz/authentication/]

[2] Kubernetes 鉴权概述 [https://kubernetes.io/zh/docs/reference/access-authn-authz/authorization/]

[3] Casbin 概述 [https://casbin.org/docs/zh-CN/overview]

[4] Kubernetes API Aggregation Layer [https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/]