一、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,下面我们实际操作下。
创建命名空间
$ kubectl create ns anmin
namespace/anmin created
查看命名空间的ServiceAccount
$ kubectl get sa -n anmin
NAME SECRETS AGE
default 1 27s
查看ServiceAccount的Secret
$ kubectl describe sa default -n anmin
Name: default
Namespace: anmin
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: default-token-bskds
Tokens: default-token-bskds
Events: <none>
$ kubectl get secret -n anmin
NAME TYPE DATA AGE
default-token-bskds kubernetes.io/service-account-token 3 75s
可以看到在创建名为“anmin”的命名空间后,自动创建了名为“default”的ServiceAccount,并为“default”服务账户创建了对应kubernetes.io/service-account-token类型的secret。
创建一个Pod
apiVersion: v1
kind: Pod
metadata:
name: testpod
namespace: anmin
spec:
containers:
- name: testpod
image: busybox
args: [/bin/sh, -c,
'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
查看Pod的Service Account信息
$ kubectl create -f anmin.yaml
pod/testpod created
$ kubectl describe pod testpod -n anmin
..........
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-bskds (ro)
..........
Volumes:
default-token-bskds:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-bskds
Optional: false
.........
在不指定ServiceAccount的情况下,当前 namespace 下面的 Pod 会默认使用 “default” 这个 ServiceAccount,对应的 Secret 会自动挂载到 Pod 的 /var/run/secrets/kubernetes.io/serviceaccount/ 目录中,我们可以在 Pod 里面获取到用于身份认证的信息。
$ kubectl exec -it testpod -n anmin -- /bin/sh
/ # ls /var/run/secrets/kubernetes.io/serviceaccount/
ca.crt namespace token
3. 使用自定义的ServiceAccount
创建一个Service Account
$ kubectl create sa anmin -n anmin
serviceaccount/anmin created
$ kubectl get sa -n anmin
NAME SECRETS AGE
anmin 1 20s
default 1 31m
$ kubectl get secret -n anmin
NAME TYPE DATA AGE
anmin-token-nkb8b kubernetes.io/service-account-token 3 28s
default-token-bskds kubernetes.io/service-account-token 3 31m
Pod使用刚创建的ServiceAccount
apiVersion: v1
kind: Pod
metadata:
name: testpod
namespace: anmin
spec:
containers:
- name: testpod
image: busybox
args: [/bin/sh, -c,
'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
serviceAccountName: anmin
更新Pod
$ kubectl apply -f anmin.yaml
pod/testpod created
$ kubectl describe pod testpod -n anmin
.........
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from anmin-token-nkb8b (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
anmin-token-nkb8b:
Type: Secret (a volume populated by a Secret)
SecretName: anmin-token-nkb8b
Optional: false
............
可以看到更新后的Pod已经使用了新创建的ServiceAccount服务账户。
4. ServiceAccount中添加Image pull secrets
我们也可以在Service Account中设置imagePullSecrets,然后就会自动为使用该 SA 的 Pod 注入 imagePullSecrets 信息。
创建kubernetes.io/dockerconfigjson类型的私有仓库镜像Secret
$ 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
2secret/harbor created
将镜像仓库的Secret添加到ServiceAccount
$ kubectl edit sa anmin -n anmin
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2020-06-16T16:09:54Z"
name: anmin
namespace: anmin
resourceVersion: "37509823"
selfLink: /api/v1/namespaces/anmin/serviceaccounts/anmin
uid: c6bec7bb-808d-459f-86c8-6c78b48cb3ab
secrets:
- name: anmin-token-nkb8b
imagePullSecrets:
- name: harbor
查看ServiceAccount中Image pull secrets字段信息
$ kubectl describe sa anmin -n anmin
Name: anmin
Namespace: anmin
Labels: <none>
Annotations: <none>
Image pull secrets: harbor
Mountable secrets: anmin-token-nkb8b
Tokens: anmin-token-nkb8b
Events: <none>
使用ServiceAccount拉取私有镜像部署Pod
apiVersion: v1
kind: Pod
metadata:
name: anmin2
namespace: anmin
spec:
containers:
- name: anmin2
image: 192.168.166.229/1an/node-exporter:latest
serviceAccountName: anmin
更新Pod并查看状态
$ kubectl apply -f harborsecret.yaml
pod/anmin2 created
$ kubectl get pod -n anmin
NAME READY STATUS RESTARTS AGE
anmin2 1/1 Running 0 20s
$ kubectl describe pod anmin2 -n anmin
......
Volumes:
anmin-token-nkb8b:
Type: Secret (a volume populated by a Secret)
SecretName: anmin-token-nkb8b
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Pulling 8h kubelet, k8s-node01 Pulling image "192.168.166.229/1an/node-exporter:latest"
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
$ kubectl create sa zhanmin-sa -n kube-system
serviceaccount/zhanmin created
定义一个Role对象 zhanmin-sa-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: zhanmin-sa-role
namespace: kube-system
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
在上面的文件我们定义了被作用的命名空间为:kube-system,其中的rules 字段,就是它所定义的权限规则。其中规则定义的角色对Pod没有创建、删除、更新的权限。
其中的“被作用者”我们则是通过RoleBinding
对象来指定。
定义Rolebinding对象 zhanmin-sa-rolebinding.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: zhanmin-sa-rolebinding
namespace: kube-system
subjects:
- kind: ServiceAccount
name: zhanmin-sa
namespace: kube-system
roleRef:
kind: Role
name: zhanmin-sa-role
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 对象。
下面创建这些对象
$ kubectl create -f zhanmin-sa-role.yaml
role.rbac.authorization.k8s.io/zhanmin-sa-role created
$ kubectl create -f zhanmin-sa-rolebinding.yaml
rolebinding.rbac.authorization.k8s.io/zhanmin-sa-rolebinding created
现在可以去之前部署的kubernetes-dashboard上验证权限
获取当前Service Account的Secret信息
$ kubectl get secret -n kube-system
zhanmin-sa-token-x6gxs kubernetes.io/service-account-token 3 136m
$ kubectl get secret zhanmin-sa-token-x6gxs -o jsonpath={.data.token} -n kube-system |base64 -d
eyJhbGciOiJSUzI1NiIsImtpZCI6InJCZFhYLTVRc2E4STlGVVN0VzEwWlc2M1VGMVF0ZDZFaFdJQlc3V2RLMzAifQ.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
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: clusterrole-anmin
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
含义为:名为“clusterrole-anmin”的集群角色可以对集群所有命名空间的Pod进行“GET、Watch、List” 操作。
在Role 或者 ClusterRole 里面,如果要赋予用户 example-user 所有权限,那你就可以给它指定一个 verbs 字段的全集,如下所示:
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
创建 ClusterRoleBinding集群角色绑定 ClusterRoleBinding.yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: example-clusterrolebinding
subjects:
- kind: User
name: user-anmin
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: clusterrole-anmin
apiGroup: rbac.authorization.k8s.io
含义为: subjects字段定义被作用者用户为“user-anmin”,roleRef字段定义:绑定名为“clusterrole-anmin”集群角色。
在 Kubernetes 中已经内置了很多个为系统保留的 ClusterRole,它们的名字都以 system: 开头。你可以通过 kubectl get clusterroles
查看到它们。
查看集群角色
$ kubectl get clusterroles
NAME AGE
admin 242d
calico-kube-controllers 211d
calico-node 211d
cluster-admin 242d
cluster-regular 217d
edit 242d
......
查看角色的权限
$ kubectl describe clusterrole edit
Name: edit
Labels: kubernetes.io/bootstrapping=rbac-defaults
rbac.authorization.k8s.io/aggregate-to-admin=true
Annotations: rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
configmaps [] [] [create delete deletecollection patch update get list watch]
endpoints [] [] [create delete deletecollection patch update get list watch]
persistentvolumeclaims [] [] [create delete deletecollection patch update get list watch]
pods [] [] [create delete deletecollection patch update get list watch]
replicationcontrollers/scale [] [] [create delete deletecollection patch update get list watch]
......
4. Group用户组
Kubernetes 还拥有“用户组”(Group)的概念,也就是一组“用户”的意思。如果你为 Kubernetes 配置了外部认证服务的话,这个“用户组”的概念就会由外部认证服务提供。
ServiceAccount,在 Kubernetes 里对应的“用户”的名字是:
system:serviceaccount:<Namespace名字>:<ServiceAccount名字>
对应的内置“用户组”的名字,就是:
system:serviceaccounts:<Namespace名字>
比如,现在我们可以在 RoleBinding 里定义如下的 subjects:
subjects:
- kind: Group
name: system:serviceaccounts
apiGroup: rbac.authorization.k8s.io
这就意味着这个 Role 的权限规则,作用于 mynamespace 里的所有 ServiceAccount。这就用到了“用户组”的概念。而下面这个例子:
subjects:
- kind: Group
name: system:serviceaccounts
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】获取视频教程及更多资料: