k8s十 | 一文读懂基于角色的权限控制RBAC

​一、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的三个基本概念:

  1. Role:角色,其实是一组规则,定义了一组对 Kubernetes API 对象的操作权限;
  2. Subject:被作用者,既可以是“人”,也可以是“机器”,也就是在 Kubernetes 里定义的“用户”;
  3. 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】获取视频教程及更多资料:


运维技术社
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342