Warning: Array to string conversion in /home/wwwroot/myf5/wp-content/plugins/wpjam-basic/public/wpjam-utils.php on line 496
k8s验证与授权思路综述
相信很多人装k8s都想顺手装个dashboard看看,毕竟GUI有时候还是比较重要的,哈哈。 相信很多人会有同感,那就是一个dashboard搞的那么复杂,不是不能访问,就是不能登录,要么就是没权限。下面通过自己的一点研究,将问题分析过程记录如下,供参考。如有错误,请拍砖留言。
从两个方面来分析,即:
1.dashboard的安装与访问
2.dashboard的身份验证与授权
首先,我们需要有一个共识就是,k8s这套东西非常的解耦和插件化,它为了能够提供更好的二次开发能力,将很多东西搞的从一个用户角度理解起来很费劲。 比如说用户,k8s里面本身是不能创建用户名这样的实体对象的(API basic,bear token认证所设置的相关用户名不算k8s里面的实体资源对象),它只有role,role定义一系列资源权限,然后把一个sa或者group或者user 映射到这个role上来完成权限分配的关系。 这里为啥突然有个user了呢,这里的user实际上是外部的,就像远程AAA一样,user账号是在外部系统上的。我们知道API server是K8S负责验证的服务,不管是怎么访问都是要经过它,dashboard也一样。那么要想API给你做验证做授权有哪些方法(重要常见的,以下未包含全部)?
- 使用http basic 认证,这要求配置APIserver支持这种方式,并传递一个包含用户名密码的list文件给API,API就像是个普通开启了http basic认证的web server一样,会挑战浏览器,要求输入用户名和密码。 API获取到输入的用户名密码后和之前预置的list里比对,匹配了,则验证通过,系统就知道是谁登陆了,然后根据该user与role的binding关系就知道了该用户拥有了哪些权限
- Bearer token认证,这种认证方式也要求API server服务配置一个token list文件,这个文件里包含了token,token对应着user名称,原理与basic类似,不同的是这种要求在访问请求的header中要始终包含 Authorization: Bearer <token>这个header而已,授权的方式和basic一样
- 证书方式的验证和授权,因为证书里可以包含CN和OU这些信息,CN可以表明一个user身份,OU可以表明一个组身份,如果访问者上送的证书被校验通过,那么证书里的CN和OU就可以用来作为条件去rolebinding里查找,进而就可以授权。当然对于dashboard的访问,截止目前v1.11版本,是还不支持使用证书来验证身份的。
- Serviceaccount, SA严格意义上不算是用户身份认证,这个是给运行在k8s里的具体应用服务(你可以理解为pods)提供访问API的一种方法,因为有很多运行在k8s里pod内的应用是需要访问API的,所以SA不代表人,代表服务,给一个具体的服务比如dashboard,创建一个SA,然后将SA关联到pod上,并把SA与一个role进行rolebinding。当然实际上服务出示给API的是一个SA的token(k8s为每一个SA都自动产生一个token并保存在secret资源里),这个token是通过mount的方式将对应的token secret mount到pod上来实现的。所以这又回了API的token认证,token-->知道哪个SA, SA和哪个role对应,这样就完成了验证和授权
BEI-ML-JLIN-:~ jlin$ kubectl get clusterrolebinding -o wide -n kube-system NAME AGE ROLE USERS GROUPS SERVICEACCOUNTS canal-calico 15h ClusterRole/calico kube-system/canal canal-flannel 15h ClusterRole/flannel kube-system/canal cluster-admin 16h ClusterRole/cluster-admin system:masters system:aws-cloud-provider 16h ClusterRole/system:aws-cloud-provider kube-system/aws-cloud-provider system:basic-user 16h ClusterRole/system:basic-user system:authenticated, system:unauthenticated system:controller:attachdetach-controller 16h ClusterRole/system:controller:attachdetach-controller ku
上面的rolebinding输出里可以看到一个role关联了 users,groups,以及SAs
说了这么多都是为了背景铺垫,免得下面看起来太费劲。回到上面提到的两个问题:
dashboard的安装与访问
安装比较简单,基本上跑一下官方提供的yaml就可以,这里是官方wiki链接,下面分析下这其中的一些小坑。官方的wiki里大约说了两件事:
- 拿到一个证书和key,放到一个目录下,然后跑个命令产生以下secret
kubectl create secret generic kubernetes-dashboard-certs --from-file=$HOME/certs -n kube-system
这个命令的作用是为了设置dashboard作为web server,配置的服务器侧证书的,把它存到secret里,然后在pod里mount这个secret,然后作为证书配置配置给pod
- 跑一下他们的dashboard yaml文件
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml
yaml文件很长,解读一下相关的关键:
A. 它也创建了一个名字叫kubernetes-dashboard-certs的secret, 所以实际上跑yaml时候系统会报相关secret已存在# ------------------- Dashboard Secret ------------------- # apiVersion: v1 kind: Secret metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-certs namespace: kube-system type: OpaqueB. 创建了一个sa,名字叫kubernetes-dashboard, 这个sa和一个自定义的kubernetes-dashboard-minimal的role进行了绑定
# ------------------- Dashboard Service Account ------------------- # apiVersion: v1 kind: ServiceAccount metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: kubernetes-dashboard-minimal namespace: kube-system roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: kubernetes-dashboard-minimal subjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kube-systemC.将kubernetes-dashboard-certs这个secret mount到了container上, 挂到了/certs这个目录上
volumeMounts: - name: kubernetes-dashboard-certs mountPath: /certsD. 设置了容器运行命令参数 --auto-generate-certificates,这个是干嘛的呢,是自动产生服务器侧证书的,也就是说这个yaml实际上没有用上面mount进去的证书。
spec: containers: - name: kubernetes-dashboard image: k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3 ports: - containerPort: 8443 protocol: TCP args: - --auto-generate-certificates所以,这个时候如果你去访问dashboard,浏览器上显示的证书都是临时签发的证书,并不是/certs里的证书,要想实现是自己指定的证书,需要将自动产生这个参数换掉,换成如下
Args: --tls-cert-file=/certs/kubernetes-dashboard.pem --tls-key-file=/certs/kubernetes-dashboard-key.pem --default-cert-dir=/certs
安装完毕后,就该是如何访问了。官方的yaml默认是clusterip模式发布的服务,这样要想访问到dashbaor的界面,要么通过kubectl proxy,要么通过将服务暴露给外部,要么通过API的端口来代理访问,否则外面咋访问呢???
A. Kubectl proxy方式,kubectl proxy是通过在kubectl上暴露一个服务端口,通常为127.0.0.1:8001的非https访问, 你不能在master或者node上跑这个命令,否则除非你的master或者node有图形化的浏览器,不然还是无法看到图形dashboard。所以要在你自己的本地跑这个命令(所以,我擦,好麻烦,所以你还有在本地设置你kubectl的kubeconfig确保本地kubectl可以有权限操作所有)。然后就可以通过本地浏览器访问http://127.0.0.1:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/#!/login 看到界面了。 但是!这个dashboard还是会提示你进行身份认证。。。。不理解为啥,kubectl proxy本身不就希望代理权限吗?不管它,关于这里的认证授权后面再分析。

B 通过nodeport或者ingress来暴露出来服务,这种方式比较容易理解,等于正常发布一个服务,所以将官方的的yaml改为nodeport方式即可。
C API server本身的服务端口代理访问,即通过API的端口来代理访问dashboard,URI类似这样 https://<master-ip>:<apiserver-port>/ 首先,这种访问API服务的方式需要浏览器提供客户端证书作为认证,比如你可以把kubectl所用的那张证书导入到浏览器里,这样访问服务的时候,会弹出让你选择证书,等于就是双向SSL过程。然后就可以看到dashboard界面了,但是同样,dashboard依旧会再次出现登录界面提示身份验证,也就是说这种方式和kubectl proxy一样,只是代理了界面入口,验证权限方面并未代理。
浏览器未出示证书的情况下,访问返回403
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "services \"https:kubernetes-dashboard:\" is forbidden: User \"system:anonymous\" cannot get services/proxy in the namespace \"kube-system\"",
"reason": "Forbidden",
"details": {
"name": "https:kubernetes-dashboard:",
"kind": "services"
},
"code": 403
}
(这是因为API里启用了RBAC,且默认有个--anonymous-auth=false的参数设定,这意味着匿名用户直接被拒绝验证的。如果将值改为true,虽然可以验证了,但是授权还是通不过,会返回如下401,因为匿名用户没权限)
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}
比如,下图显示浏览器访问6443已经可以获得正常的API权限

但是,当真的访问dashboard时候还是提示认证,下图是没有认证通过,提示的无权限界面的(即在界面上点击skip,这个时候系统直接用在安装yaml文件里自定义的sa kubernetes-dashboard来授权了,这个sa只关联到了自定义的一个minimal的一个资源role,所以会报出很多资源没权限的提示)
也就是说,dashboard不管从哪种方式来访问,其本身的身份验证都是这个服务自己独立的,那么这个服务的验证到底是怎样的?
dashboard身份验证与授权
官方文档对验证做如下表述:
As of release 1.7 Dashboard supports user authentication based on:
Authorization: Bearer <token>header passed in every request to Dashboard. Supported from release 1.6. Has the highest priority. If present, login view will not be shown.- Bearer Token that can be used on Dashboard login view.
- Username/password that can be used on Dashboard login view.
- Kubeconfig file that can be used on Dashboard login view.
简单的来说,就是只支持两种方法,一种是token,一种是user/password。 kubeconfig凡是只是提供了一种便利,并不是一个新的认证方式,如果要用kubeconfig,里面一样,要么使用username/password,要么使用token。跟踪一下看看,通过API proxy方式的方法来访问 https://172.16.150.100:6443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/api/v1/login/modes 看到如下输出
{
"modes": [
"token"
]
}
很显然,指明了token方式
为什么这样访问,没权限?https://172.16.150.100:6443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/api/v1/login/status
{
"tokenPresent": false,
"headerPresent": false,
"httpsMode": true
}
可以看到,login status已经说明,token也没出示,header方式的携带诸如basic认证的方式的token也没带
所以,对于1.7+之上版本的dashboard来说,验证和授权是dashboard完全自己控制的。
根据上述提示,要想登陆进去,要么用用户名密码,要么用token:
- username/password方式
这种方式需要kube-API配合,配置ABAC授权模式,且配置--basic-auth-file,同时dashboard自身的配置里要启用--authentication-mode=basic 配置 - token方式
这种方式就是在login界面输入一下token,token哪里来能,从系统里的SA账户对应的token来,所以这个SA账户要有足够的API权限。下面的步骤是创建SA并通过clusterrolebinding绑定到了clusterrole/cluster-admin上,这样就有了全部的权限BEI-ML-JLIN-:~ jlin$ kubectl create serviceaccount dashboard-gui -n kube-system serviceaccount "dashboard-gui" created BEI-ML-JLIN-:~ jlin$ kubectl get sa -n kube-system NAME SECRETS AGE canal 1 22h coredns 1 22h dashboard-gui 1 11s default 1 23h kubernetes-dashboard 1 10h BEI-ML-JLIN-:~ jlin$ kubectl create clusterrolebinding dashboard-gui-rolebind --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-gui -n kube-system clusterrolebinding.rbac.authorization.k8s.io "dashboard-gui-rolebind" created BEI-ML-JLIN-:~ jlin$ kubectl get clusterrolebinding dashboard-gui-rolebind -o wide -n kube-system NAME AGE ROLE USERS GROUPS SERVICEACCOUNTS dashboard-gui-rolebind 6m ClusterRole/cluster-admin kube-system/dashboard-gui
ok,通过在登录界面输入kubectl describe secret dashboard-gui-token-9l25t -n kube-system ,可以正常访问界面了。
所以,整个dashboard是完全可以通过这样的权限控制(sa,自定义role,role绑定)来实现一个用户在GUI界面上能操作哪些namespace里的哪些资源。
附:
如何利用kubeconfig登录dashboard?
如果只是简单的将诸如kubectl所用的kubeconfig拿来登录,系统会提示:

黄色提示很是误导人,实际原因是因为kubeconfig没有包含token也没有username/pwd, 如果将上面的token放置到kubeconfig文件里,一样就可以登录并有权限了
参考:
https://github.com/kubernetes/dashboard/wiki/Accessing-Dashboard---1.7.X-and-above
https://github.com/kubernetes/dashboard/issues/2474
https://github.com/kubernetes/dashboard/wiki/Access-control



文章评论