可以大概了解到一个请求的链路是依次通过Authentication(认证,简称Authn)、Authorization(授权,简称Authz)、AdmissionControl(准入控制),从而获取到后端持久化的数据。
从图中可以看到Authn、Authz、AdmissionControl是由多个模块组成的,每个步骤都有多种方式构成的。
在进入认证模块之前会将HTTP的Request进行构建context,而context中就包含了用户的RequestInfo,userInfo、Verb、APIGroup、Version、Namespace、Resource、Path等。
带着这些信息,下面我们来一次看下准入过程中的每个步骤吧。
Kubernetes认证
认证的过程的证明user身份的过程。
Kubernetes中有两类用户,一类是ServiceAccount,一类是集群真实的用户。
ServiceAccount账户是由Kubernetes提供API(资源)进行创建和管理的,ServiceAccount可以认为是特殊的Secret资源,可用户集群内资源访问APIServer的认证所用。通过可以通过mount的方式挂载到Pod内进行使用。
真实的用户通常是从外部发起请求访问APIServer,由管理员进行管理认证凭证,而Kubernetes本身不管理任何的用户和凭证信息的,即所有的用户都是逻辑上的用户,无法通过API调用Kubernetes API进行创建真实用户。
Kubernetes认证的方式众多,常见的有TLS客户端证书双向认证、BearerToken认证、BasicAuthorization或认证代理(WebHook)
所有的认证方式都是以插件的形式串联在认证链路中,只要有一种认证方式通过,即可通过认证模块,且后续的认证方式不会被执行。
在此处参考一点点Kubernetes APIServer Authentication模块的代码,可以发现,任何的认证方式都是一下Interface的实现方式都是接收http Request请求,然后会返回一个user.Info的结构体,一个bool,以及一个error
// Request attempts to extract authentication information from a request and returns
// information about the current user and true if successful, false if not successful,
// or an error if the request could not be checked.
type Request interface {
AuthenticateRequest(req *http.Request) (user.Info, bool, error)
}
user.Info中包含了用户的信息,包括UserName、UUID、Group、Extra。
bool返回了用户是否通过认证,false的话即返回无法通过认证,即返回401错误。
error则返回了当Request无法被检查的错误,如果遇到错误则会继续进行下一种注册的方式进行认证。
如果认证通过,则会把user.Info写入到到请求的context中,后续请求过程可以随时获取用户信息,比如授权时进行鉴权。
下面我会以Kubernetes代码中的认证方式顺序,挑选几项认证方式,并结合TKE开启的认证方式来向你介绍TKE创建的Kubernetes集群默认的认证策略。
Basic Authentication
APIServer启动参数--basic-auth-file=SOMEFILE指定basic认证的csv文件,在APIServer启动之后修改此文件都不会生效,需要重启APIServer来更新basic authentication的token。csv文件格式为:token,user,uid,"group1,group2,group3"。
请求时,需要指定HTTP Header中Authentication为Basic,并跟上Base64Encode(user:passward)值。
x509客户端证书
APIServer启动参数--client-ca-file=SOMEFILE指定CA证书,而在TKE的K8s集群创建过程中,会对集群进行自签名CA密钥和证书用于管理,如果用户下发的客户端证书是由此CA证书的密钥签发的,那么就可以通过客户端证书认证,并使用客户端证书中的CommonName、Group字段分别作为Kubernetes的UserInfo中Username和Group信息。
目前TKE对接子账户都是通过自签名的CA凭证进行签发子账户Uin对应CN的客户端证书。
Bearer Token
Bearer Token的认证方式包含很多,比如启动参数指定的、ServiceAccount(也是一种特殊的BeaerToken)、BootstrapToken、OIDCIssure、WebhookToken
1. 默认指定Token csv文件
APIServer启动参数--token-auth-file=SOMEFILE指定Bearer Token认证的csv文件。和Basic Authentication方式相似,只不过请求APIServer时,指定的HTTP认证方式为Bearer方式。此Bearer后直接跟passward即可。csv文件格式为:password,user,uid,"group1,group2,group3"。
请求时,需要指定HTTP Header中Authentication为Bearer,并跟上Base64Encode(user:passward)值。
2. ServiceAccount
ServiceAccount也是一种特殊beaer token,ServiceAccount在Kubernetes中是一种资源,创建一个ServiceAccount资源之后默认会创建一个Secret资源,而Secret资源中就包含了一个JWT格式的Token字段,以Bearer Token的方式请求到Kube-APIServer,Kube-APIServer解析token中的部分user信息,以及validate以下ServiceAccount是否存在即可进行认证检查。这种方式即之前提到的“两种用户”中常见的集群内认证方式,ServiceAccount,主要用于集群内资源访问APIServer,但不限于集群内。
3. BootstrapToken
此项开关在Kubernetes v1.18版本中才为stable版本,此类Token是专门用来引导集群安装使用的,需要配合controller-manager的TokenCleaner。
目前TKE默认开启此配置。
4. OpenID Connect Tokens
OIDCToken的认证方式是结合OAuth2向身份提供方获取ID Token来访问APIServer。
如需要开启此项功能,需要在APIServer的启动参数中指定oidc的配置参数,例如--oidc-issuer-url指定oidc身份提供方的地址,--oidc-client-id指定身份提供方侧的账户ID,--oidc-username-claim身份提供方的用户名。
具体可参考Kubernetes官方文档,目前公有云TKE没有使用此参数对接腾讯云账户,因为涉及用户需要主动登录授权后才可返回Id Token,和当前官网交互冲突,可以在后续CLI工具中实现。
5. Webhook Token Server
Webhook Token是一种hook的方式来校验是否认证通过。
APIServer启动参数--authentication-token-webhook-config-file及--authentication-token-webhook-cache-ttl来分别指定Webhook地址以及token的cache ttl。
若APiServer开启此方式进行认证校验,则在接受到用户的Request之后,会包装Bearer Token成一个TokenReview发送给WebHookServer,Server端接收到之后会进行校验,并返回TokenReview接口,在status字段中进行反馈是否通过校验通过和user.Info信息。
总结
以上即为Kubernetes APIServer认证的几种方式,TKE在每种认证方式都有支持。供用户灵活使用。
目前TKE正在推使用x509客户端证书方式来进行认证管理,以方便进行对接子账户的创建、授权管理、更新。
Kubernetes授权
Kubernetes的授权模式支持一下几种,和认证一样,参考开始说的RequestInfo context,可知用户Reqeust的context除了认证需要的userInfo,还有一些其他的字段例如Verb、APIGroup、APIVersion、Resource、Namespaces、Path……
授权就是判断user是否拥有操作资源的相应权限。
Kubernetes支持AlwaysAllow、AlwaysDeny、Node、ABAC、RBAC、Webhook授权Mode,和认证一样,只要有一种鉴权模块通过,即可返回资源。
在这里重点介绍下面两种方式
RBAC
RBAC(Role-Based Access Control),Kubernetes提供ClusterRole、Role资源,分别对应集群维度、Namespace维度角色权限管控,用户可以自定义相应的ClusterRole、Role资源,绑定到已经认证的User之上。
如下tke:pod-reader ClusterRole,定义了该角色可以访问core apigroup下面对pods资源的get/watch/list操作
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: tke:pod-reader
rules:
- apiGroups: [""] # "" 指定核心 API 组
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定使得用户 "alex" 能够读取 "default" 命名空间中的 Pods
kind: ClusterRoleBinding
metadata:
name: alex-ClusterRole
subjects:
- kind: User
name: alex
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: tke:pod-reader # 这里的名称必须与你想要绑定的 Role 或 ClusterRole 名称一致
apiGroup: rbac.authorization.k8s.io
通过以上的yaml配置,通过认证模块到达授权模块的requestInfo中userInfo信息是alex的请求,在授权模块中走到RBAC授权模块时,则会进行查询集群的ClusterRole/ClusterRoleBinding信息。进行判断是否拥有context相应操作的权限。
TKE的对接子账户的权限授权策略就是使用的Kubernetes原生的RBAC进行对子账户资源访问控制,这样符合原生,符合有K8s使用习惯的用户。
WebHook
Webhook模式是一种基于HTTP回调的方式,通过配置好授权webhook server地址。当APIServer接收到request的时候,会进行包装SubjectAccessReview请求Webhook Server,Webhook Server会进行判断是否可以访问,然后返回allow信息。
以下是kubernetes社区一个例子,以供参考。
{
"apiVersion": "authorization.k8s.io/v1beta1",
"kind": "SubjectAccessReview",
"spec": {
"resourceAttributes": {
"namespace": "kittensandponies",
"verb": "get",
"group": "unicorn.example.org",
"resource": "pods"
},
"user": "alex",
"group": [
"group1",
"group2"
]
}
}
{
"apiVersion": "authorization.k8s.io/v1beta1",
"kind": "SubjectAccessReview",
"status": {
"allowed": true
}
}
目前TKE没有考虑使用Webhook的模式,但是Webhook模式提供了强大的灵活性,比如对接CAM,实现K8s权限对接到平台侧,但是也有一定的风险和挑战,比如依赖CAM的稳定性;请求延迟、缓存/TTL的配置;CAM action配置与K8s权限对应关系。此项授权模式仍然在考虑中,有需求的用户可以反馈。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!