Z.S.K.'s Records

Kubernetes学习(业务程序使用serviceaccount获取kubernetes集群资源)

有时我们的业务程序也有获取kubernetes集群资源的需求, serviceaccount(简写sa)就是专门给pod用的一种鉴权机制, 在搭建Prometheus或者是fluentd时都会有创建serviceaccount的命令, 如何创建一个serviceaccount, 使其只能操作kube-system下的pods.

什么是service account? 顾名思义,相对于user account(比如:kubectl访问APIServer时用的就是user account),service account就是Pod中的Process用于访问Kubernetes API的account,它为Pod中的Process提供了一种身份标识。相比于user account的全局性权限,service account更适合一些轻量级的task,更聚焦于授权给某些特定Pod中的Process所使用.

在kube-system下创建一个sa

1
kubectl create sa pod-reader -n kube-system

该sa会绑定一个secret, 下面需要从该secret中获取token信息

假如该secret 名为pod-reader-token-95cwp

创建role

1
2
3
4
5
6
7
8
9
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: kube-system
name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]

创建rolebinding

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader
namespace: kube-system
subjects:
- kind: ServiceAccount
name: pod-reader # Name is case sensitive
namespace: kube-system
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io

创建集群信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# kubectl命令行下操作
#指定名字空间
namespace=kube-system
#指定secret
name=pod-reader-token-95cwp
#获取ca信息
ca=$(kubectl get secret/$name -n $namespace -o jsonpath='{.data.ca\.crt}')
#获取token
token=$(kubectl get secret/$name -n $namespace -o jsonpath='{.data.token}' | base64 -d)
#namespace=$(kubectl get secret/$name -o jsonpath='{.data.namespace}' | base64 --decode)

#添加集群信息,集群名为cfc
#kubectl config set-cluster cfc --server=https://kubernetes-cluster.local:6443 --certificate-authority-data=${ca} 这种方式新版本不支持, 只能指定ca文件的路径

kubectl config set-cluster cfc --server=https://kubernetes-cluster.local:6443 --certificate-authority=/etc/kubernetes/pki/ca.crt

#添加上下文为cfc,对应集群为cfc,以下4步并没有先后顺序
kubectl config set-context cfc --cluster=cfc --user=sa_user

#添加认证信息,名为sa_user
kubectl config set-credentials sa_user --token=${token}

#设置当前的上下文为cfc, 后续所有的操作都是以这个集群的内容进行操作
kubectl config use-context cfc

#后续可以使用以下命令切换集群
kubectl config use-context kubernetes-admin

#使用以下命令查看当前的集群
kubectl config current-context

我们看到service account并不复杂,只是关联了一个secret资源作为token,该token也叫service-account-token,该token才是真正在API Server验证(authentication)环节起作用的

在pod yaml中使用serviceaccount

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: k8s-example1
spec:
replicas: 1
template:
metadata:
labels:
run: k8s-example1
spec:
serviceAccount: pod-reader #指定上面创建的sa
containers:
- name: k8s-example1
image: k8s/example1:latest
imagePullPolicy: IfNotPresent
...

在大多数情况下,我们上线应用并没有手工地指定这个serviceAccount,那又是为何呢?

默认的serviceaccount

在默认情况下, kubernetes会为每一个namespace创建个一个默认的sa, 而且会默认地给所有在该namespace下的pod都自动挂载到/var/run/secrets/kubernetes.io/serviceaccount

随便查看一个运行的pod的yaml文件

在pod内查看

这三个文件与上面提到的service account的token中的数据是一一对应的

那么这个pod内的应用就能通过这3个文件与api-server通信了, 根据这个sa具有的权限获取资源.

原理

service account为Pod中的Process提供了一种身份标识,在Kubernetes的身份校验(authenticating)环节,以某个service account提供身份的Pod的用户名为:

1
system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT)

以kube-system namespace下的“default” service account为例,使用它的Pod的username全称为:

1
system:serviceaccount:kube-system:default

有了username,那么credentials呢?就是上面提到的service-account-token中的token。API Server的authenticating环节支持多种身份校验方式:client cert、bearer token、static password auth等,这些方式中有一种方式通过authenticating(Kubernetes API Server会逐个方式尝试),那么身份校验就会通过。一旦API Server发现client发起的request使用的是service account token的方式,API Server就会自动采用signed bearer token方式进行身份校验。而request就会使用携带的service account token参与验证。该token是API Server在创建service account时用API server启动参数:–service-account-key-file的值签署(sign)生成的。如果–service-account-key-file未传入任何值,那么将默认使用–tls-private-key-file的值,即API Server的私钥(server.key)。

通过authenticating后,API Server将根据Pod username所在的group:system:serviceaccountssystem:serviceaccounts:(NAMESPACE)的权限对其进行authorityadmission control两个环节的处理, 最终通过验证及鉴权.

参考文章:

转载请注明出处https://izsk.me

Z.S.K. wechat
Scan Me To Read on Phone
I know you won't do this,but what if you did?