一、ServiceAccount
. 1. ServiceAccount 介绍
首先Kubernetes中账户区分为:User Accounts(用户账户) 和 Service Accounts(服务账户) 两种,它们的设计区别如下:
UserAccount是给kubernetes集群外部用户使用的,例如运维或者集群管理人员,使用kubectl命令时用的就是UserAccount账户;UserAccount是全局性。在集群所有namespaces中,名称具有唯一性,默认情况下用户为admin;
ServiceAccount是给运行在Pod的程序使用的身份认证,Pod容器的进程需要访问API Server时用的就是ServiceAccount账户;ServiceAccount仅局限它所在的namespace,每个namespace都会自动创建一个default service account;创建Pod时,如果没有指定Service Account,Pod则会使用default Service Account。
. 2. 默认Service Account
在上篇文章 k8s九 | 详解配置对象ConfigMap与Secret最后kubernetes.io/service-account-token一节中我们已经提到创建命名空间时会创建一个默认的Service Account,而ServiceAccout 创建时也会创建对应的 Secret,下面我们实际操作下。
创建命名空间
1$ kubectl create ns anmin
2namespace/anmin created
查看命名空间的ServiceAccount
1$ kubectl get sa -n anmin
2NAME SECRETS AGE
3default 1 27s
查看ServiceAccount的Secret
1$ kubectl describe sa default -n anmin
2Name: default
3Namespace: anmin
4Labels: 5Annotations: 6Image pull secrets: 7Mountable secrets: default-token-bskds 8Tokens: default-token-bskds 9Events: 10$ kubectl get secret -n anmin11NAME TYPE DATA AGE12default-token-bskds kubernetes.io/service-account-token 3 75s
可以看到在创建名为“anmin”的命名空间后,自动创建了名为“default”的ServiceAccount,并为“default”服务账户创建了对应kubernetes.io/service-account-token类型的secret。
创建一个Pod
1apiVersion: v1
2kind: Pod
3metadata:
4 name: testpod
5 namespace: anmin
6spec:
7 containers:
8 - name: testpod
9 image: busybox
10 args: [/bin/sh, -c,
11 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
查看Pod的Service Account信息
1$ kubectl create -f anmin.yaml
2pod/testpod created
3$ kubectl describe pod testpod -n anmin
4..........
5 Mounts:
6 /var/run/secrets/kubernetes.io/serviceaccount from default-token-bskds (ro)
7..........
8Volumes:
9 default-token-bskds:
10 Type: Secret (a volume populated by a Secret)
11 SecretName: default-token-bskds
12 Optional: false
13.........
在不指定ServiceAccount的情况下,当前 namespace 下面的 Pod 会默认使用 “default” 这个 ServiceAccount,对应的 Secret 会自动挂载到 Pod 的 /var/run/secrets/kubernetes.io/serviceaccount/ 目录中,我们可以在 Pod 里面获取到用于身份认证的信息。
1$ kubectl exec -it testpod -n anmin -- /bin/sh
2/ # ls /var/run/secrets/kubernetes.io/serviceaccount/
3ca.crt namespace token
. 3. 使用自定义的ServiceAccount
创建一个Service Account
1$ kubectl create sa anmin -n anmin
2serviceaccount/anmin created
3$ kubectl get sa -n anmin
4NAME SECRETS AGE
5anmin 1 20s
6default 1 31m
7$ kubectl get secret -n anmin
8NAME TYPE DATA AGE
9anmin-token-nkb8b kubernetes.io/service-account-token 3 28s
10default-token-bskds kubernetes.io/service-account-token 3 31m
Pod使用刚创建的ServiceAccount
1apiVersion: v1
2kind: Pod
3metadata:
4 name: testpod
5 namespace: anmin
6spec:
7 containers:
8 - name: testpod
9 image: busybox
10 args: [/bin/sh, -c,
11 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
12 serviceAccountName: anmin
13 ```
14 更新Pod
15 ```shell
16 $ kubectl apply -f anmin.yaml
17pod/testpod created
18$ kubectl describe pod testpod -n anmin
19.........
20 Mounts:
21 /var/run/secrets/kubernetes.io/serviceaccount from anmin-token-nkb8b (ro)
22Conditions:
23 Type Status
24 Initialized True
25 Ready True
26 ContainersReady True
27 PodScheduled True
28Volumes:
29 anmin-token-nkb8b:
30 Type: Secret (a volume populated by a Secret)
31 SecretName: anmin-token-nkb8b
32 Optional: false
33 ............
可以看到更新后的Pod已经使用了新创建的ServiceAccount服务账户。
. 4. ServiceAccount中添加Image pull secrets
我们也可以在Service Account中设置imagePullSecrets,然后就会自动为使用该 SA 的 Pod 注入 imagePullSecrets 信息。
创建kubernetes.io/dockerconfigjson类型的私有仓库镜像Secret
1$ kubectl create secret docker-registry harbor --docker-server=http://192.168.166.229 --docker-username=admin --docker-password=1234567 --docker-email=test@163.com -n anmin
22secret/harbor created
将镜像仓库的Secret添加到ServiceAccount
1$ kubectl edit sa anmin -n anmin
2# Please edit the object below. Lines beginning with a '#' will be ignored,
3# and an empty file will abort the edit. If an error occurs while saving this file will be
4# reopened with the relevant failures.
5#
6apiVersion: v1
7kind: ServiceAccount
8metadata:
9 creationTimestamp: "2020-06-16T16:09:54Z"
10 name: anmin
11 namespace: anmin
12 resourceVersion: "37509823"
13 selfLink: /api/v1/namespaces/anmin/serviceaccounts/anmin
14 uid: c6bec7bb-808d-459f-86c8-6c78b48cb3ab
15secrets:
16- name: anmin-token-nkb8b
17imagePullSecrets:
18- name: harbor
查看ServiceAccount中Image pull secrets字段信息
1$ kubectl describe sa anmin -n anmin
2Name: anmin
3Namespace: anmin
4Labels: 5Annotations: 6Image pull secrets: harbor7Mountable secrets: anmin-token-nkb8b8Tokens: anmin-token-nkb8b9Events:
使用ServiceAccount拉取私有镜像部署Pod
1apiVersion: v1
2kind: Pod
3metadata:
4 name: anmin2
5 namespace: anmin
6spec:
7 containers:
8 - name: anmin2
9 image: 192.168.166.229/1an/node-exporter:latest
10 serviceAccountName: anmin
更新Pod并查看状态
1$ kubectl apply -f harborsecret.yaml
2pod/anmin2 created
3$ kubectl get pod -n anmin
4NAME READY STATUS RESTARTS AGE
5anmin2 1/1 Running 0 20s
6$ kubectl describe pod anmin2 -n anmin
7......
8Volumes:
9 anmin-token-nkb8b:
10 Type: Secret (a volume populated by a Secret)
11 SecretName: anmin-token-nkb8b
12 Optional: false
13QoS Class: BestEffort
14Node-Selectors: 15Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s16 node.kubernetes.io/unreachable:NoExecute for 300s17Events:18 Type Reason Age From Message19 ---- ------ ---- ---- -------20 Normal Pulling 8h kubelet, k8s-node01 Pulling image "192.168.166.229/1an/node-exporter:latest"21 Normal Pulled 8h kubelet, k8s-node01 Successfully pulled image "192.168.166.229/1an/node-exporter:latest"
可以看到Pod已经成功从镜像仓库拉取镜像并正常运行。
二、RBAC
. 1. RBAC介绍
在Kubernetes 中所有资源对象都是通过 API 对象进行操作, 它们保存在 Etcd 里。而对Etcd的操作我们需要通过访问 kube-apiserver来实现,上面的Service Account其实就是APIServer的认证过程,而授权的机制则是通过RBAC:基于角色的访问控制实现的。
Role + RoleBinding + ServiceAccount 的权限分配方式是要重点掌握的内容。
RBAC的三个基本概念:
Role:角色,其实是一组规则,定义了一组对 Kubernetes API 对象的操作权限;
Subject:被作用者,既可以是“人”,也可以是“机器”,也就是在 Kubernetes 里定义的“用户”;
RoleBinding:定义了“被作用者”和“角色”的绑定关系。
. 2. Role与RoleBinding
现在我们通过实际操作来理解RBAC的工作机制
创建一个Service Account
1$ kubectl create sa zhanmin-sa -n kube-system
2serviceaccount/zhanmin created
定义一个Role对象 zhanmin-sa-role.yaml
1apiVersion: rbac.authorization.k8s.io/v1
2kind: Role
3metadata:
4 name: zhanmin-sa-role
5 namespace: kube-system
6rules:
7- apiGroups: [""]
8 resources: ["pods"]
9 verbs: ["get", "watch", "list"]
10- apiGroups: ["apps"]
11 resources: ["deployments"]
12 verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
在上面的文件我们定义了被作用的命名空间为:kube-system,其中的rules 字段,就是它所定义的权限规则。其中规则定义的角色对Pod没有创建、删除、更新的权限。
其中的“被作用者”我们则是通过RoleBinding
对象来指定。
定义Rolebinding对象 zhanmin-sa-rolebinding.yaml
1kind: RoleBinding
2apiVersion: rbac.authorization.k8s.io/v1
3metadata:
4 name: zhanmin-sa-rolebinding
5 namespace: kube-system
6subjects:
7- kind: ServiceAccount
8 name: zhanmin-sa
9 namespace: kube-system
10roleRef:
11 kind: Role
12 name: zhanmin-sa-role
13 apiGroup: rbac.authorization.k8s.io
subjects 字段,即“被作用者”。它的类型是 User,即 Kubernetes 里的用户,也就是上文中的Service Account,这里我们定义被作用者用户为“zhanmin-sa”。
roleRef则是定义:RoleBinding 对象可以直接通过名字,来引用我们前面定义的 Role 对象,也就是“zhanmin-sa-role”,从而定义了“被作用者(Subject)”和“角色(Role)”之间的绑定关系。
所以Pod使用名为“zhanmin-sa”的ServiceAccount访问API Server时只能够做对Pod做get", "watch", "list"操作。这是因为“zhanmin-sa” 这个 ServiceAccount 的权限,已经被我们绑定了 Role 做了限制。
注意:Role 和 RoleBinding 对象都是 Namespaced 对象(Namespaced Object),它们对权限的限制规则仅在它们自己的 Namespace 内有效,roleRef 也只能引用当前 Namespace 里的 Role 对象。
下面创建这些对象
1$ kubectl create -f zhanmin-sa-role.yaml
2role.rbac.authorization.k8s.io/zhanmin-sa-role created
3$ kubectl create -f zhanmin-sa-rolebinding.yaml
4rolebinding.rbac.authorization.k8s.io/zhanmin-sa-rolebinding created
现在可以去之前部署的kubernetes-dashboard上验证权限
获取当前Service Account的Secret信息
1$ kubectl get secret -n kube-system
2zhanmin-sa-token-x6gxs kubernetes.io/service-account-token 3 136m
3$ kubectl get secret zhanmin-sa-token-x6gxs -o jsonpath={.data.token} -n kube-system |base64 -d
4eyJhbGciOiJSUzI1NiIsImtpZCI6InJCZFhYLTVRc2E4STlGVVN0VzEwWlc2M1VGMVF0ZDZFaFdJQlc3V2RLMzAifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VeXN
现在可以去之前部署的kubernetes-dashboard上验证权限
命名空间修改为kube-system,因为上面我们已经说了Service Account只对当前的namespace有效。
可以看到,权限是符合我们上面的定义,只可以查看Pod和Deployments对象,查看其他资源比如SVC显示是没有数据的。后面我们可以根据自己的需求去查询API对象修改相应的权限规则。
. 3. ClusterRole 和 ClusterRoleBinding
上面的Role和RoleBinding只可以在他们自己的命名空间中有效,如果我们需要一个具有全部命名空间或者对节点有权限的角色时,就需要使用ClusterRole 和 ClusterRoleBinding 对象来做授权了。
ClusterRole 和 ClusterRoleBinding 这两个 API 对象的用法跟 Role 和 RoleBinding 几乎完全一样。不一样的是,它们的定义里,没有了 Namespace 字段,权限可以作用于整个集群。
创建ClusterRole集群角色 clusterrole.yaml
1kind: ClusterRole
2apiVersion: rbac.authorization.k8s.io/v1
3metadata:
4 name: clusterrole-anmin
5rules:
6- apiGroups: [""]
7 resources: ["pods"]
8 verbs: ["get", "watch", "list"]
含义为:名为“clusterrole-anmin”的集群角色可以对集群所有命名空间的Pod进行“GET、Watch、List” 操作。
在Role 或者 ClusterRole 里面,如果要赋予用户 example-user 所有权限,那你就可以给它指定一个 verbs 字段的全集,如下所示:
1verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
创建 ClusterRoleBinding集群角色绑定 ClusterRoleBinding.yaml
1kind: ClusterRoleBinding
2apiVersion: rbac.authorization.k8s.io/v1
3metadata:
4 name: example-clusterrolebinding
5subjects:
6- kind: User
7 name: user-anmin
8 apiGroup: rbac.authorization.k8s.io
9roleRef:
10 kind: ClusterRole
11 name: clusterrole-anmin
12 apiGroup: rbac.authorization.k8s.io
含义为:subjects字段定义被作用者用户为“user-anmin”,roleRef字段定义:绑定名为“clusterrole-anmin”集群角色。
在 Kubernetes 中已经内置了很多个为系统保留的 ClusterRole,它们的名字都以 system: 开头。你可以通过 kubectl get clusterroles
查看到它们。
查看集群角色
1$ kubectl get clusterroles
2NAME AGE
3admin 242d
4calico-kube-controllers 211d
5calico-node 211d
6cluster-admin 242d
7cluster-regular 217d
8edit 242d
9......
查看角色的权限
1$ kubectl describe clusterrole edit
2Name: edit
3Labels: kubernetes.io/bootstrapping=rbac-defaults
4 rbac.authorization.k8s.io/aggregate-to-admin=true
5Annotations: rbac.authorization.kubernetes.io/autoupdate: true
6PolicyRule:
7 Resources Non-Resource URLs Resource Names Verbs
8 --------- ----------------- -------------- -----
9 configmaps [] [] [create delete deletecollection patch update get list watch]
10 endpoints [] [] [create delete deletecollection patch update get list watch]
11 persistentvolumeclaims [] [] [create delete deletecollection patch update get list watch]
12 pods [] [] [create delete deletecollection patch update get list watch]
13 replicationcontrollers/scale [] [] [create delete deletecollection patch update get list watch]
14......
. 4. Group用户组
Kubernetes 还拥有“用户组”(Group)的概念,也就是一组“用户”的意思。如果你为 Kubernetes 配置了外部认证服务的话,这个“用户组”的概念就会由外部认证服务提供。
ServiceAccount,在 Kubernetes 里对应的“用户”的名字是:
1system:serviceaccount:<Namespace名字>:<ServiceAccount名字>
对应的内置“用户组”的名字,就是:
1system:serviceaccounts:<Namespace名字>
比如,现在我们可以在 RoleBinding 里定义如下的 subjects:
1subjects:
2- kind: Group
3 name: system:serviceaccounts
4 apiGroup: rbac.authorization.k8s.io
这就意味着这个 Role 的权限规则,作用于 mynamespace 里的所有 ServiceAccount。这就用到了“用户组”的概念。而下面这个例子:
1subjects:
2- kind: Group
3 name: system:serviceaccounts
4 apiGroup: rbac.authorization.k8s.io
就意味着这个 Role 的权限规则,作用于整个系统里的所有 ServiceAccount。
总结:通过上面的实践,我们了解了在kubernetes中用户分为User Accounts和 Service Accounts,在我们平常的使用中会经常使用ServiceAccount。而对于权限的控制,我们需要先创建角色(Role),其实就是一组权限规则列表。然后我们分配这些权限的方式,就是通过创建 RoleBinding 对象,将被作用者(subject)Service Account和权限列表Role进行绑定,也就是Role + RoleBinding + ServiceAccount来实现。另外ClusterRole 和 ClusterRoleBinding,则是 Kubernetes 集群级别的 Role 和 RoleBinding,它们的作用范围不受 Namespace 限制。
参考资料:
https://time.geekbang.org/column/article/42154
https://www.qikqiak.com/k8s-book/docs/30.RBAC.html
关注公众号回复【k8s】获取视频教程及更多资料: