认证、授权与准入控制(一)

  在任何将资源或服务提供给有限使用者的系统上,认证和授权都是两个必不可少的功能,认证用于身份鉴别,而授权则实现权限分派。Kubernetes以插件化的方式实现了这两种功能,且分别存在多种可用的插件。另外,它还支持准入控制机制,用于补充授权机制以实现更精细的访问控制功能。

一、访问控制概述

  API Server 作为Kubernetes集群系统的网关,是访问即管理资源对象的唯一入口,余下所有需要访问集群资源的组件,包括kube-controller-manager,kube-scheduler,kubelet和kube-proxy等集群基础组件、CoreDNS等集群的附加组件以及此前使用的kubectl命令等都要经由此网关进行集群访问和管理。这些客户端均要经由API Server访问或改变集群状态并完成数据存储,并由它对每一次的访问请求进行合法性校验,包括用户身份鉴别、操作权限验证以及操作是否符合全局规范的约束等。所有检查均正常完成且对象配置信息合法性校验无误之后才能访问或存储数据于后端存储系统etcd中。

  客户端认证操作由API Server配置的一到多个认证插件完成。收到请求后,API Server依次调用为其配置的认证插件来认证客户端身份,直到其中一个插件可以识别出请求者的身份为止。授权操作由一到多个授权插件进行,它负责确定那些通过认证的用户是否有权限执行其发出的资源操作请求,如创建、读取、删除或修改指定的对象等。随后,通过授权检测的用户所请求的修改相关的操作还要经由一到多个准入控制插件的遍历检测,例如使用默认值补足要创建的目标资源对象中未定义的各字段、检查目标Namespace资源对象是否存在、检查是否违反系统资源限制,等等,而其中任何的检查失败都可能会导致写入操作失败。

  在k8s集群之上部署应用程序的时候,也可以通过宿主机的NodePort暴露的端口访问里面的程序,用户访问kubernetes集群需要经历如下认证过程:认证->授权->准入控制:

  认证(Authenticating)是对客户端的认证,通俗点就是用户名密码验证

  授权(Authorization)是对资源的授权,k8s中的资源无非是容器,最终其实就是容器的计算,网络,存储资源,当一个请求经过认证后,需要访问某一个资源(比如创建一个pod),授权检查会根据授权规则判定该资源(比如某namespace下的pod)是否是该客户可以访问的。

  准入控制器(Admission Controller)位于 API Server 中,在对象被持久化之前,准入控制器拦截对 API Server 的请求,一般用来做身份验证和授权。其中包含两个特殊的控制器:MutatingAdmissionWebhook 和 ValidatingAdmissionWebhook,分别作为配置的变异和验证准入控制 webhook。

  变更(Mutating)准入控制:修改请求的对象

  验证(Validating)准入控制:验证请求的对象

  准入控制器是在 API Server 的启动参数配置的。一个准入控制器可能属于以上两者中的一种,也可能两者都属于。当请求到达 API Server 的时候首先执行变更准入控制,然后再执行验证准入控制。

在部署 Kubernetes 集群的时候都会默认开启一系列准入控制器,如果没有设置这些准入控制器的话可以说Kubernetes 集群就是在裸奔,应该只有集群管理员可以修改集群的准入控制器。

  例如默认开启如下的准入控制器:

--admission-control=ServiceAccount,NamespaceLifecycle,NamespaceExists,LimitRanger,ResourceQuota,MutatingAdmissionWebhook,ValidatingAdmissionWebhook

二、用户账户与用户组

  Kubernetes并不会存储由认证插件从客户端请求中提取出的用户即所属组的信息,它们仅仅用于校验用户是否有权限执行器所请求的操作。客户端访问API服务的途径通常有三种:kubectl、客户端库或者直接使用REST接口进行请求,而可以执行此类请求的主体也被kubernetes分为两类:现实中的“人”和pod对象,它们的用户身份分别对应于常规用户(User Account)和服务账号(Service Account)。

  User Account(用户账号):一般是指由独立于kubernetes之外的其他服务管理的用户账号,例如由管理员分发的密钥、Keystone一类的用户存储(账号库)、甚至是包含有用户名和密码列表的文件等。Kubernetes中不存在表示此类用户账号的对象,因此不能被直接添加进kubernetes系统中。

  Service Account(服务账号):是指由kubernetes API 管理的账号,用于为pod之中的服务进程在访问Kubernetes API时提供身份标识(identify)。Service Account通常要绑定于特定的名称空间,它们由API Server创建,或者通过API 调用手动创建,附带着一组存储为Secret的用于访问API Server的凭据。Service account是为了方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的。它与User account不同,User account是为人设计的,而service account则是为Pod中的进程调用Kubernetes API而设计;User account是跨namespace的,而service account则是仅局限它所在的namespace;每个namespace都会自动创建一个default service account。

  User Account通常用于复杂的业务逻辑管控,它作用于系统全局,故其名称必须全局唯一。相比较来说,Service Account隶属于名称空间,仅用于实现某些特定的操作任务,因此要轻量的多。这两类账号都可以隶属于一个或多个用户组。用户组只是用户账号的逻辑集合,它本身并没有操作权限,但附加于组上的权限可由其内部的所有用户继承,以实现高效的授权管理机制。kubernetes有着以下几个内建的用于特殊目的的组。

  system:unauthenticated:未能通过任何一个授权插件检验的账号,即未通过认证测试的用户所属的组。

  system:authenticated:认证成功后的用户自动加入的一个组,用于快捷引用所有正常通过认证的用户账号

  system:serviceaccounts:当前系统上的所有Service Account对象

  system:serviceaccounts:<namespace>:特定名称空间内所有的Service Account对象。

  API 请求要么与普通用户或服务账户进行绑定,要么被视为匿名请求。这意味着集群内部或外部的每个进程,包括由人类用户使用的kubectl命令,到节点上的kubelet,再到控制平面的成员组件,必须在向API服务器发出请求时进行身份验证,否则即被视为匿名用户。

二、认证、授权与准入控制基础

  API Server处理请求的过程中,认证插件负责鉴定用户身份,授权插件用于操作权限许可鉴别,而准入控制则用于在资源对象的创建、删除、更新或连接操作时实现更精细的许可检查。

1. 认证

  Kubernetes使用身份验证插件对API请求进行身份验证,支持的认证方式包括客户端证书、承载令牌(bearer tokens)、身份验证代理(authenticating proxy)或HTTP basic认证等。API Server接收到访问请求时,它将调用认证插件尝试将以下属性与访问请求相关联。

  Username:用户名,如kubernetes-admin等。

  UID:用户的数字标签符,用于确保用户身份的唯一性

  Groups:用户所属的组,用于权限指派和继承。

  Extra:键值数据类型的字符串,用于提供认证时需要用到的额外信息

  API Server支持同时启用多种认证机制,但至少应该分别为Service Account和User Account各自启用一个认证插件。同时启用多种认证机制时,认证过程会以串行的方式进行,直到一种认证机制成功完成即结束。若认证失败,则服务器会响应401状态码,反之,请求者就会被识别为某个具体的用户(以其用户名进行标识),并且随后的操作都将以此用户身份来进行。

  认证支持多种插件:
(1)令牌(token)认证:

  双方有一个共享密钥,服务器上先创建一个密码下来,客户端登陆的时候拿这个密码登陆即可,这个就是对称密钥认证方式;k8s提供了一个restful风格的接口,它的所有服务都是通过http协议提供的,因此认证信息只能经由http协议的认证首部进行传递,这种认证首部进行传递通常叫做令牌。

(2)ssl认证:

  对于k8s访问来讲,ssl认证能让客户端确认服务器的认证身份,在跟服务器通信的时候,需要服务器发过来一个证书,需要确认这个证书是不是ca签署的,如果是认可的ca签署的,里面的subj信息与访问的目标主机信息保持一致,没有问题,那么就认为服务器的身份得到认证了,k8s中最重要的是服务器还需要认证客户端的信息,kubectl也应该有一个证书,这个证书也是server所认可的ca签署的证书,双方需要互相认证,实现加密通信,这就是ssl认证。

2. 授权

  为了核验用户的操作许可,成功通过身份认证后的操作请求还需要转交给授权插件进行许可权限检查,以确保其拥有执行相应的操作的许可。API Server主要支持使用四类内建的授权插件来定义用户的操作权限。

1)Node(节点认证)基于pod资源的目标调度节点来实现的对kubelet的访问控制

2)ABAC:基于属性的访问控制

3)RBAC:基于角色的访问控制***

4)Webhook:基于http回调机制通过外部REST服务检查确认用户授权的访问控制

  另外,还有AlwaysDeny和AlwayAllow两个特殊的授权插件,其中AlwayDeny(总是拒绝)仅用于测试,而AlwaysAllow(总是允许)则用于不期望进行授权检查时直接授权检查阶段放行的所有操作请求。启动API Server时,“--authorization-mode”选项用于定义要启用的授权机制,多个选项彼此之间以逗号分隔。

3. 准入控制

  准入控制只是用来定义授权检查完成之后的后续的其他安全检查操作的,进一步补充了授权机制,由多个插件组合实行。准入控制器用于在客户端请求经过身份验证和授权检查之后,但在对象持久化存储etcd之前拦截请求,用于实现在资源的创建、更新和删除操作期间强制执行对象的语法验证等功能,读取资源信息的操作请求不会经由准入控制器的检查。Kubernetes的Admission Control实际上是一个准入控制器(Admission Controller)插件列表,发送到APIServer的请求都需要经过这个列表中的每个准入控制器插件的检查,如果某一个控制器插件准入失败,就准入失败。API Server内置了许多准入控制器,常用的包括以下几种:

  AlwaysAdmit:允许所有请求通过

  AlwaysPullImages:在启动容器之前总是去下载镜像,相当于每当容器启动前做一次用于是否有权使用该容器镜像的检查,常用于多租户环境中以确保私有镜像仅能够被拥有权限的用户使用

  AlwaysDeny:拒绝所有请求通过,仅用于测试

  DenyEscalatingExec:拒绝exec和attach命令到有升级特权的Pod的终端用户访问。如果集中包含升级特权的容器,而要限制终端用户在这些容器中执行命令的能力,推荐使用此插件

  ServiceAccount:用于实现Service Account管控机制的自动化,实现创建pod对象时自动为其附加相关的Service Account对象

  SecurityContextDeny:将Pod定义中定义了的SecurityContext选项全部失效。SecurityContext包含在容器中定义了操作系统级别的安全选型如fsGroup,selinux等选项

  ResourceQuota:用于namespace上的配额管理,它会观察进入的请求,确保在namespace上的配额不超标。推荐将这个插件放到准入控制器列表的最后一个。ResourceQuota准入控制器既可以限制某个namespace中创建资源的数量,又可以限制某个namespace中被Pod请求的资源总量。ResourceQuota准入控制器和ResourceQuota资源对象一起可以实现资源配额管理

  LimitRanger:可用资源范围界定,用于监控对设置了LimitRange的对象所发出的所有请求,以确保其资源请求不会超限

  NamespaceLifecycle:当一个请求是在一个不存在的namespace下创建资源对象时,该请求会被拒绝。当删除一个namespace时,将会删除该namespace下的所有资源对象

  DefaultStorageClass:监控所有创建PVC对象的请求,以保证那些没有附加任何专用StorageClass的请求会自动设定一个默认值

  DefaultTolerationSeconds:如果pod对象上不存在污点宽容期限,则为它们设置默认的宽容期,以宽容"notready:NoExecute"和"unreachable:NoExecute"类的污点5分钟时间

  当Kubernetes版本>=1.6.0,官方建议使用这些插件:
–admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds
  当Kubernetes版本>=1.4.0,官方建议使用这些插件:
–admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota
  以上是标准的准入插件,如果是自己定制的话,k8s1.7版 出了两个alpha features, Initializers 和 External Admission Webhooks

三、服务账号管理与应用

  运行过程中,Pod资源里的容器进程在某些场景中需要调用kubernetes API 或者其他类型的服务,而这些服务通常需要认证客户端身份,如调度器、pod控制器或节点控制器,甚至是获取启动容器的镜像访问的私有Registry服务等。服务账号就是用于让pod对象内的容器进程访问其他服务时提供身份认证信息的账户。一个Service Account资源一般由用户名及相关的Secret对象组成。

1. Service Account自动化

  kubectl explain pods.spec 可以看到有一个字段serviceAccountName(服务账户名称),这个就是pod连接apiserver时使用的账号。

[root@k8s-master1 ~]# kubectl explain pod.spec.serviceAccountName
KIND:     Pod
VERSION:  v1

FIELD:    serviceAccountName <string>

DESCRIPTION:
     ServiceAccountName is the name of the ServiceAccount to use to run this
     pod. More info:
     https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/

  ServiceAccount:方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的,是kubernetes中的一种资源。 

  此前创建的每个pod资源都自动关联了一个存储卷,并由其容器挂载至/var/run/secrets/kubernetes.io/serviceaccount目录,例如下面的示例显示的pod-test对象的描述信息:

[root@k8s-master1 pod]# kubectl describe pods pod-test
Name:         pod-test
Namespace:    default
Priority:     0
Node:         k8s-node1/10.0.0.132
Start Time:   Wed, 19 Oct 2022 22:43:03 +0800
Labels:       app=myapp
              env=dev
Annotations:  cni.projectcalico.org/podIP: 10.244.36.112/32
              cni.projectcalico.org/podIPs: 10.244.36.112/32
Status:       Running
IP:           10.244.36.112
IPs:
  IP:  10.244.36.112
Containers:
  pod-test:
    Container ID:   docker://1302621bef9811cec594c8504300f089e048a899c2eea92a92f0e54bd0d64358
    Image:          nginx:latest
    Image ID:       docker-pullable://nginx@sha256:b95a99feebf7797479e0c5eb5ec0bdfa5d9f504bc94da550c2f58e839ea6914f
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Wed, 19 Oct 2022 22:43:05 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-5n29f (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-5n29f:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-5n29f
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  57s   default-scheduler  Successfully assigned default/pod-test to k8s-node1
  Normal  Pulled     56s   kubelet            Container image "nginx:latest" already present on machine
  Normal  Created    56s   kubelet            Created container pod-test
  Normal  Started    55s   kubelet            Started container pod-test

  pod和apiserver的认证信息通过secret进行定义,由于认证信息属于敏感信息,所以需要保存在secret资源当中,并以存储卷的方式挂载到Pod当中。从而让Pod内运行的应用通过对应的secret中的信息来连接apiserver,并完成认证。每个 namespace 中都有一个默认的叫做 default 的 serviceaccount 资源。查看名称空间内的secret,也可以看到对应的default-token。让当前名称空间中所有的pod在连接apiserver时可以使用的预制认证信息,从而保证pod之间的通信。

  挂载点目录中通常存在三个文件:ca.crt,namespace和token,其中,token文件保存了Service Account的认证token,容器中的进程使用它向API Server发起连接请求,进而由认证插件完成用户认证并将其用户名传递给授权插件。

[root@k8s-master1 ~]# kubectl get secret default-token-5n29f
NAME                  TYPE                                  DATA   AGE
default-token-5n29f   kubernetes.io/service-account-token   3      81d
[root@k8s-master1 ~]# kubectl describe secret default-token-5n29f
Name:         default-token-5n29f
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: default
              kubernetes.io/service-account.uid: 6f6cb617-d812-45ca-a4e4-d3cd811604de

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1066 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IkxKVHlZMHFIMWpxRnlOSWRPMmVDQnBPdGFwdWRlbkdrLUpuOG50WUhfbEkifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tNW4yOWYiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjZmNmNiNjE3LWQ4MTItNDVjYS1hNGU0LWQzY2Q4MTE2MDRkZSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.pjFDCr3GF7P0NLFnHWZ4UayYyBS-rj1NOGuES3IJnWBeHS8x1gczy197LPFKDRLJ_HByBtEKGMJwOwZldlyH0l55mMy9iKcO2hM7iHynWd4hSQYlZJBi2l7nKajsg-umx_Anki_Y5v36cDSo6QcASbR3K8wS4iWPgoKGmiNj4-vLBGw-4L_i29qH4zwEdy46ynTj00h3bi5noVTqQVqFJuBNe1bafTVg_FSaAqo2Zc-dqD0-ur9fq3Rwfi5xTiw8NnT51-xaEX-Z3oLhz3Kw_VJntWPxt9zAsJiLGJpPaX8TgvVJ6KPqW8jWXDaj-aytzYddUYW8hENt9JFiKAlbQQ

  每个pod对象都只有一个服务账户,若创建pod资源时未予以明确指定,则名为Service Account的准入控制器会为其自动附加当前名称空间中默认的服务账号,其名称通常为default。下面命令显示了default这个服务账户的详细信息:

[root@k8s-master1 ~]# kubectl get serviceaccount default
NAME      SECRETS   AGE
default   1         81d
[root@k8s-master1 ~]# kubectl describe sa default
Name:                default
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   default-token-5n29f
Tokens:              default-token-5n29f
Events:              <none>

  kubernetes系统通过三个独立的组件间的相互协作来实现服务账户的自动化,三个组件具体为:Service Account准入控制器、令牌控制器(token controller)和Service Account账户控制器。Service Account 控制器负责为名称空间管理相应的资源,并确保每个名称空间中都存在一个名为“default”的Service Account对象。Service Account准入控制器是API Server的一部分,负责在创建或更新Pod时对其按需进行Service Account对象相关信息的修改,这包括如下操作:

1)若pod没有明确定义使用的Service Account对象,则将其甚至为“default”

2)确保pod明确引用的Service Account已存在,否则请求将被拒绝

3)若pod对象中不包含ImagePullSecrets,则把Service Account的ImagePullSecrets添加于其上

4)为带有访问API 的令牌的pod添加一个存储卷

5)为pod对象中的每个容器添加一个volumeMounts,挂载至/var/run/secrets/kubernetes.io/serviceaccount

  令牌控制器是controller-manager的子组件,工作于异步模式。其负责完成的任务具体如下:

1)监控Service Account的创建操作,并为其添加用于访问API 的Secret对象。

2)监控Service Account的删除操作,并删除其相关的所有Service Account令牌密钥

3)监控Secret对象的添加操作,确保其引用的Service Account已存在,并在必要时为Secret对象添加认证令牌

4)监控Secret对象的删除操作,以确保删除每个Service Account中对此Secret的引用

  需要注意的是,为确保完整性等,必须为kube-controller-manager使用“--service-account-private-key-file”选项指定一个私钥文件,以用于对生成的服务账户令牌进行签名,此私钥文件必须是pem格式。类似地,还要为kube-apiserver使用“--service-account-key-file"指定与前面的私钥配对儿的公钥文件,以用于在认证期间对认证令牌进行校验。

2. 创建服务账户

  Service Account是k8s API上的一种资源类型,它隶属于名称空间,用于让pod对象内部的应用程序在于API Server通信时完成身份认证。事实上,每个名称空间都有一个名为default的默认资源对象,如下面的命令及其结果所示,其可用于让pod对象有权限读取同一名称空间中的其他资源对象的元数据信息。需要赋予pod对象更多的操作权限时,则应该由用户按需创建自定义的Service Account资源:

 

[root@k8s-master1 ~]# kubectl get sa --all-namespaces
NAMESPACE              NAME                                 SECRETS   AGE
default                cephfs-provisioner                   1         20d
default                default                              1         81d
default                nfs-client-provisioner               1         27d
default                rbd-provisioner                      1         21d
kube-node-lease        default                              1         81d
kube-public            default                              1         81d
kube-system            attachdetach-controller              1         81d
...

 每个pod对象均可附加其所属名称空间中的一个Service Account资源,且只能附加一个。不过,一个Service Account资源可由其所属名称空间中的多个pod对象共享使用。创建pod资源时,用户可使用“pods.spec.serviceAccountName”属性直接指定要使用的Service Account对象,或者省略此字段而由其自动附加当前名称空间中默认的Service Account(default)。

  可使用资源配置文件创建Service Account资源,也可以直接使用“kubectl create serviceaccount NAME”命令创建,提供认证令牌的secret资源对象会由命令自动创建完成。下面的配置清单是一个Service Account资源示例,它仅指定了创建名为sa-demo的服务账户,其余的信息交由系统自动生成:

[root@k8s-master1 ~]# mkdir sa
[root@k8s-master1 ~]# cd sa/
[root@k8s-master1 sa]# vim sa-demo.yaml
[root@k8s-master1 sa]# cat sa-demo.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-demo
  namespace: default
[root@k8s-master1 sa]# kubectl apply -f sa-demo.yaml
serviceaccount/sa-demo created
[root@k8s-master1 sa]# kubectl get sa sa-demo
NAME      SECRETS   AGE
sa-demo   1         10s
[root@k8s-master1 sa]# kubectl describe sa sa-demo
Name:                sa-demo
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   sa-demo-token-57nn4
Tokens:              sa-demo-token-57nn4
Events:              <none>

  自动创建了secret:sa-demo-token-57nn4和token:sa-demo-token-57nn4

[root@k8s-master1 sa]# kubectl get secret sa-demo-token-57nn4
NAME                  TYPE                                  DATA   AGE
sa-demo-token-57nn4   kubernetes.io/service-account-token   3      47s
[root@k8s-master1 sa]# kubectl describe secret sa-demo-token-57nn4
Name:         sa-demo-token-57nn4
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: sa-demo
              kubernetes.io/service-account.uid: 34d63dd3-a9f2-4e15-9db1-994d345d19aa

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1066 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IkxKVHlZMHFIMWpxRnlOSWRPMmVDQnBPdGFwdWRlbkdrLUpuOG50WUhfbEkifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InNhLWRlbW8tdG9rZW4tNTdubjQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoic2EtZGVtbyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjM0ZDYzZGQzLWE5ZjItNGUxNS05ZGIxLTk5NGQzNDVkMTlhYSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OnNhLWRlbW8ifQ.W3X8VMUIAiuwMJAFJprZ5zwVq9rWY6LoBa8817-ZUgQzWkmdxsrPCClcRW2VAWrrrIGiXYaeijCTHtPw5pVlGZfsA9CXW9ZSKS7vai-M2ga5b98ULkJXS4czbQgYV6Ozgj5Ge6xaj3dXtmiYPAiLhO3Wd_gQ65eYMeGACbm_dJji90fZSpxDDQJuT8Fo5cpQsY7N86Fu4xZ2uLiSVzgJBw1A06IkJGruwOYm9g1kqMiVOYzvM71gSmBwAq8RvLzasIE7Jf9ZkNlvTK49Rdo65ppK5AHn30b4gjxW8b6KpM0CoeBWrTAXsBaSZbjjT1mIRjm_xpoINOBNmCoefLJlmA

  可以看到自动生成的sa-demo-token-57nn4的token详细信息,这个token就是sa连接apiserver的认证信息,这个token也是登陆k8s dashboard的token,这些是一个认证信息,能够登陆k8s,能认证到k8s,但是不能做别的事情,不代表权限,想要做其他事情,需要授权。

  创建pod对象时,可为pod对象指定使用自定义的服务账户,从而实现自主控制pod对象资源的访问权限。Pod向API Server发出请求时,其携带的认证令牌在通过认证后将由授权插件来判定相关的Service Account是否有权限访问其所请求的资源。Kubernetes支持多种授权插件,由管理员负责选定及配置,RBAC是目前较为主流的选择。

3. 调用imagePullSecrets资源对象

  Service Account资源还可以基于pod.spec.imagePullSecrets字段附带一个由下载镜像专用的Secret资源组成的列表,用于在进行容器创建时,从某私有镜像仓库下载镜像文件之前进行服务认证。下面的示例定义了一个有着从本地私有镜像仓库harbor中下载镜像文件时用于认证的secret对象信息的Service Account:

[root@k8s-master1 sa]# cat sa-imagePullSecret.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: image-download-sa
  namespace: default
imagePullSecrets:
- name: local-harbor-secret

  其中,local-harbor-secret是docker-registry类型的secret对象,由用户提前手动创建,它可以通过键值数据提供docker仓库服务器地址、接入服务器的用户名、密码及用户的电子邮件等信息。认证通过后,引用此Service Account的pod资源即可从指定的镜像仓库中下载由image字段指定的镜像文件。

四、客户端配置文件kubeconfig

  包括kubectl、Kubelet和kube-controller-manager等在内的API Server的各类客户端都可以使用kubeconfig配置文件提供接入多个集群的相关配置信息,包括各API Server的URL及认证信息等,而且能够设置成不同的上下文环境,并在各环境之间快速切换。

  使用kubeadm初始集群后生成的/etc/kubernetes/admin.conf文件即为kubeconfig格式的配置文件,其由kubeadm init命令自动生成,可由kubectl加载(默认路径为$HOME/.kube/config)后用于接入服务器。“kubectl config view”命令能够显示当前正在使用的配置文件,下面的命令结果打印了文件中配置的集群列表、用户列表、上下文列表以及当前使用的上下文(current-context)等:

[root@k8s-master1 ~]# kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://10.0.0.131:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    namespace: default
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

  事实上,任何类型的API Server客户端都可以使用kubeconfig进行配置,例如kubernetes Node之上的kubelet和kube-proxy也需要将其用到的认证信息保存于专用的kubeconfig文件中,并通过--kubeconfig选项进行加载。kubeconfig文件的定义中包含了以下几项主要的配置:

clusters:集群列表,包含访问API Server的URL和所属集群的名称等

users:用户列表,包含访问API Server时的用户名和认证信息

contexts:kubelet的可用上下文列表,由用户列表中的某特定用户名称和集群列表中的某特定集群名称组合而成

current-context:kubelet当前使用的上下文名称,即上下文列表中的某个特定项

  用户也可以按需自定义相关的配置信息于kubeconfig配置文件中,以实现使用不同的用户账户接入集群等功能。kubeconfig是一个文本文件,虽然支持使用文本处理工具直接进行编辑,但这里建议用户使用“kubectl config”命令进行设定,它能够自动进行语法检测等额外功能。kubectl config命令的常用操作包括以下几项:

[root@k8s-master1 ~]# kubectl config --help
Modify kubeconfig files using subcommands like "kubectl config set current-context my-context"

 The loading order follows these rules:

  1.  If the --kubeconfig flag is set, then only that file is loaded. The flag may only be set once and no merging takes
place.
  2.  If $KUBECONFIG environment variable is set, then it is used as a list of paths (normal path delimiting rules for
your system). These paths are merged. When a value is modified, it is modified in the file that defines the stanza. When
a value is created, it is created in the first file that exists. If no files in the chain exist, then it creates the
last file in the list.
  3.  Otherwise, ${HOME}/.kube/config is used and no merging takes place.

Available Commands:
  current-context Displays the current-context
  delete-cluster  Delete the specified cluster from the kubeconfig
  delete-context  Delete the specified context from the kubeconfig
  delete-user     Delete the specified user from the kubeconfig
  get-clusters    Display clusters defined in the kubeconfig
  get-contexts    Describe one or many contexts
  get-users       Display users defined in the kubeconfig
  rename-context  Renames a context from the kubeconfig file.
  set             Sets an individual value in a kubeconfig file
  set-cluster     Sets a cluster entry in kubeconfig  #设置kubeconfig的cluster配置段
  set-context     Sets a context entry in kubeconfig  #设置kubeconfig的context配置段
  set-credentials Sets a user entry in kubeconfig #设置kubeconfig的users配置段
  unset           Unsets an individual value in a kubeconfig file
  use-context     Sets the current-context in a kubeconfig file  #设置kubeconfig的current-context配置段
  view            Display merged kubeconfig settings or a specified kubeconfig file  #打印kubeconfig文件内容

Usage:
  kubectl config SUBCOMMAND [options]

Use "kubectl <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).

  使用kubeadm部署kubernetes集群默认提供了拥有集群管理权限的kubeconfig配置文件/etc/kubernetes/admin.conf,它可被复制到任何有着kubectl的主机上以用于管理整个集群。除此之外,管理员还可以创建其他基于SSL/TLS认证的自定义用户账号,以授予非管理员级的集群资源使用权限,其配置过程由两部分组成:一是为用户创建专用私钥及证书文件,二是将其配置于某kubeconfig文件中。下面给出其具体的实现过程,并借此创建将一个测试用户kube-user1用于后文中的授权测试。

第一步:为目标用户账号kube-user1创建私钥及证书文件,保存于/etc/kubernetes/pki/目录中

注:本步骤中的操作需要在master节点上以root用户的身份执行

1)生成私钥文件,注意其权限应该为600以阻止其他用户随意获取,这里在master节点上以root用户进行操作,并将文件放置于/etc/kubernetes/pki/目录中:

[root@k8s-master1 ~]# cd /etc/kubernetes/pki
[root@k8s-master1 pki]# umask 077;openssl genrsa -out kube-user1.key 2048
Generating RSA private key, 2048 bit long modulus
..........................................................................+++
......+++
e is 65537 (0x10001)

2)创建证书签署请求,-subj选项中CN的值将被kubeconfig作为用户名使用,O的值将被识别为用户组

[root@k8s-master1 pki]# openssl req -new -key kube-user1.key -out kube-user1.csr -subj "/CN=kube-user1/O=kubernetes"

3)基于kubeadm安装kubernetes集群时生成的CA签署证书,这里设置其有效时长为3650天:

[root@k8s-master1 pki]# openssl x509 -req -in kube-user1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out kube-user1.crt -days 3650
Signature ok
subject=/CN=kube-user1/O=kubernetes
Getting CA Private Key

4)验证证书信息

[root@k8s-master1 pki]# openssl x509 -in kube-user1.crt -text -noout
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            8c:fd:5e:ac:1d:c0:67:37
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=kubernetes
        Validity
            Not Before: Oct 23 14:44:49 2022 GMT
            Not After : Oct 20 14:44:49 2032 GMT
        Subject: CN=kube-user1, O=kubernetes
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:cf:43:80:75:ed:07:76:01:5d:ac:e3:9f:b8:00:
                    6d:c2:ca:4f:b0:32:af:7b:9e:eb:7a:e6:c4:5c:d8:
                    59:b5:73:00:8f:a6:82:30:9b:29:1c:39:36:62:91:
                    63:3e:f3:32:ca:d5:f8:3d:d9:c0:85:53:5e:e7:20:
                    10:93:77:85:7b:a7:21:49:7a:23:d0:82:86:f4:b9:
                    55:33:a7:ed:f6:ad:90:7c:42:96:20:de:a7:d8:67:
                    87:1d:48:f4:81:71:ab:7f:77:9f:20:39:17:8f:b0:
                    4a:f5:cd:23:8c:fd:8c:e0:f2:ed:01:61:ba:af:7f:
                    f2:7b:57:82:37:e2:73:64:31:6b:0c:92:58:24:ae:
                    83:ef:db:fa:99:9c:b7:88:ac:d2:7e:2c:ba:e0:3f:
                    f6:b9:c0:93:46:d8:f6:28:d1:4b:03:ce:73:90:5b:
                    cd:73:36:86:6c:cf:ad:18:2b:10:fe:5a:1c:45:ba:
                    8d:1b:74:da:d0:29:6d:69:c6:e9:24:d0:73:4f:90:
                    1f:cc:da:6a:f0:4f:82:af:8d:d7:2c:fe:88:6e:52:
                    ea:40:e6:6e:1f:00:ff:6c:4a:a5:0d:65:90:ac:f7:
                    fe:8e:3a:94:37:1f:35:37:df:77:ad:13:69:3e:62:
                    27:ed:83:40:a2:8d:fd:94:a7:34:a8:e1:35:36:da:
                    b1:25
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         a4:c1:f6:29:07:d4:cc:a1:77:55:af:d0:88:47:c2:eb:5b:25:
         c0:49:46:85:e0:43:01:40:a4:e7:2a:a5:61:db:f6:1c:e3:41:
         1e:8f:3c:cc:d3:a3:7e:b3:d3:69:c3:96:ae:5f:53:92:18:47:
         d0:da:15:4a:f5:be:27:4c:d0:aa:91:5a:3d:12:d7:72:50:72:
         6f:ba:d9:1b:a0:83:a2:e8:4c:bc:c3:74:b3:16:7e:8e:32:07:
         0e:02:14:1d:51:4c:87:55:01:04:03:f2:31:1f:19:90:11:f3:
         bc:88:28:c3:4f:c8:29:74:64:4b:a2:14:51:ec:9f:77:b3:3c:
         5f:5b:97:76:dd:2d:9b:a8:e0:60:79:76:28:49:bd:4a:29:2c:
         68:ab:69:78:cf:d5:71:a3:ba:5a:f0:d5:0a:86:94:5d:8f:63:
         54:82:3c:96:46:c2:8d:d6:44:9b:26:df:3a:8e:9b:ad:09:d2:
         85:70:eb:3e:ed:91:d8:d5:8e:73:4d:0a:42:41:3c:ac:3a:c3:
         e2:78:6a:6a:a8:ae:1e:b9:55:a2:73:86:01:b4:8e:97:32:bc:
         28:b3:bc:81:c5:f9:79:5a:c4:96:7a:d6:24:49:4b:54:a5:c2:
         9e:93:81:ca:7b:d6:8f:67:13:04:f6:46:bf:4d:fb:bd:ac:1e:
         7c:3c:5e:62

第二步:以默认管理员kubernetes-admin@kubernetes为新建的kube-user1设定kubeconfig配置文件。配置结果将默认保存于当前系统用户的.kube/config文件中,当然也可以为kubectl 使用--kubeconfig选项指定自定义的专用文件路径。

1)配置集群信息,包括集群名称、API Server URL和CA证书,若集群信息已然存在,则可省略此步,另外,提供的新配置不能与现有的配置中的集群名称相同,否则覆盖它们:

  若要配置使用如下命令:

kubectl config set-cluster kubernetes --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server="https://ip地址:6443"

2)配置客户端证书及密钥,用户名信息会通过命令从证书Subject的CN值中自动提取,例如前面创建csr时使用的“CN=kube-user1”,而组名则来自于“O=kubernetes”的定义:

[root@k8s-master1 pki]# kubectl config set-credentials kube-user1 --embed-certs=true --client-certificate=/etc/kubernetes/pki/kube-user1.crt --client-key=/etc/kubernetes/pki/kube-user1.key
User "kube-user1" set.

3)配置context,用来组合cluster和credentials,即访问集群的上下文。如果为管理多个集群而设置了多个环境,则可以使用use-context来切换:

[root@k8s-master1 pki]# kubectl config set-context kube-user1@kubernetes --cluster=kubernetes --user=kube-user1
Context "kube-user1@kubernetes" created.

4)最后指定要使用的上下文,切换为以kube-user1访问集群:

[root@k8s-master1 pki]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".

5)测试访问集群资源,不过在启用RBAC的集群上执行命令时,kube-user1并未获得集群资源的访问权限,因此会出现错误提示:

[root@k8s-master1 pki]# kubectl get pods
Error from server (Forbidden): pods is forbidden: User "kube-user1" cannot list resource "pods" in API group "" in the namespace "default"

  此时,若需切换至管理员账号,则可使用“kubectl config use-context kubernetes-admin@kubernetes”命令来完成

[root@k8s-master1 pki]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
[root@k8s-master1 pki]# kubectl get pods
NAME                                     READY   STATUS    RESTARTS   AGE
cephfs-provisioner-78c5545448-mtnbz      1/1     Running   21         23d
nfs-client-provisioner-5d65b75f7-2tv4q   1/1     Running   54         28d
pod-test                                 1/1     Running   2          4d
rbd-provisioner-65bf77fd59-9jnm8         1/1     Running   23         23d

  另外,临时使用某context时,不必设置current-context,只需要为kubectl 命令使用--context 选项指定目标context的名称即可,如“kubectl --context=kube-user1@kubernetes get pods”。 

五、基于角色的访问控制:RBAC

  RBAC(Role-Based Access Control,基于角色的访问控制)是一种新型、灵活且使用广泛的访问控制机制,它将权限授予“角色”之上,这一点有别于传统访问控制机制中将权限直接赋予使用者的方式。

  在RBAC中,用户(user)就是一个可以独立访问计算机系统中的数据或者用数据表示的其他资源的主体(Subject)。角色是指一个组织或任务中的工作或者位置,它代表了一种权利、资格和责任。许可(Permission)就是允许对一个或多个客体(Object)执行的操作。一个用户可经授权而拥有多个角色,一个角色可由多个用户构成;每个角色可拥有多种许可,每个许可也可授权给多个不同的角色。每个操作可施加于多个客体(受控对象),每个客体也可以接受多个操作。

  RBAC的基于“角色”这一核心组件实现了权限指派,具体实现中,它为账号赋予一到多个角色从而让其具有角色之上的权限,其中的账号可以是用户账号、用户组、服务账号及其相关的组等,而同时关联至多个角色的账号所拥有的权限是多个角色之上的权限集合。即让一个用户(Users)扮演一个角色(Role),角色拥有权限,从而让用户拥有这样的权限,随后在授权机制当中,只需要将权限授予某个角色,此时用户将获取对应角色的权限,从而实现角色的访问控制。RBAC中的用户、角色及权限的关系如图所示:

1. RBAC授权插件

  RBAC是一种操作授权机制,用于界定“谁”能够或不能够“操作”哪个或哪类“对象”。动作的发出者即“主体”,通常以“账号”为载体,它既可以是常规用户,也可以是服务账号。“操作”用于表明要执行的具体操作,包括创建、删除、修改和查看等,对应于kubectl来说,它通常由create、apply、delete、update、patch、edit和get等子命令来给出。而“客体”则是指操作施加于的目标实体,对kubernetes API来说主要是各类的资源对象以及非资源型URL。

  RBAC授权机制的优势:

1)对集群的资源和非资源型URL的权限实现了完整覆盖

2)整个RBAC完全由少数几个API对象实现,而且同其他API对象一样可以用kubectl或API调用进行操作

3)支持权限的运行时调整,无需重新启动API Server

  API Server是RESTful风格的API,各类客户端基于HTTP的请求报文(首部)发送身份认证信息并由认证插件完成身份验证,而后通过HTTP的请求方法指定对目标对象的操作请求并由授权插件进行授权检查,而操作的对象则是借助URL路径指定的REST资源。

  运行于API Server之上的授权插件RBAC负责确定某账号是否有权限对目标资源发出指定的操作,它们都属于“许可”类型的授权,不存在任何“拒绝”权限。

  在kubernetes的授权机制当中,采用RBAC的方式进行授权,其工作逻辑是,把对对象的操作权限定义到一个角色当中,再将用户绑定到该角色,从而使用户得到对应角色的权限。RBAC授权插件支持Role和ClusterRole两类角色,其中Role作用于名称空间级别,用于定义名称空间内的资源权限集合,而ClusterRole则用于组织集群级别的资源权限集合,它们都是标准的API资源类型。一般来说,ClusterRole的许可授权作用于整个集群,因此常用于控制Role无法生效的资源类型,这包括集群级别的资源(如Node)、非资源类型的端点(如/healthz)和作用于所有名称空间的资源(例如,跨名称空间获取任何资源的权限)。

  对这两类角色进行赋权时,需要用到RoleBinding和ClusterRoleBinding这两种资源类型。RoleBinding用于将Role上的许可权限绑定到一个或多个用户至上,它隶属于且仅能作用于一个名称空间。如果通过rolebinding绑定role,只能对rolebingding所在的名称空间的资源有权限,上图user1这个用户绑定到role1上,只对role1这个名称空间的资源有权限,对其他名称空间资源没有权限。RoleBinding绑定时,可以引用同一名称中的Role,也可以引用集群级别的ClusterRole。

  ClusterRoleBinding则把ClusterRole中定义的许可权限绑定在一个或一组用户之上,它仅可以引用集群级别的ClusterRole。如果将User2通过ClusterRoleBinding到ClusterRole,从而使User2拥有集群的操作权限。

  Role、RoleBinding、ClusterRole和ClusterRoleBinding的关系如下图:

  通过上图可以看到,可以通过rolebinding绑定role,rolebinding绑定clusterrole,clusterrolebinding绑定clusterrole

  角色的绑定可以有以下三种:

1)用户通过rolebinding绑定role

2)用户通过clusterrolebinding绑定clusterrole

3)rolebinding绑定clusterrole

  rolebinding绑定clusterrole的好处:

  假如有6个名称空间,每个名称空间的用户都需要对自己的名称空间有管理员权限,那么需要定义6个role和rolebinding,然后依次绑定,如果名称空间更多,需要定义更多的role,这个是很麻烦的,所以引入clusterrole,定义一个clusterrole,对clusterrole授予所有权限,然后用户通过rolebinding绑定到clusterrole,就会拥有自己名称空间的管理员权限了。

注:RoleBinding仅仅对当前名称空间有对应的权限

  一个名称空间中可以包含多个Role和RoleBinding对象,类似地,集群级别也可以同时存在多个ClusterRole和ClusterRoleBinding对象。而一个账户也可经由RoleBinding或ClusterRoleBinding关联至多个角色,从而具有多重许可授权。

2. Role和RoleBinding

  Role仅是一组许可权限的集合,它描述了对哪些资源可执行何种操作,资源配置清单中使用rules字段嵌套授权规则。

[root@k8s-master1 ~]# kubectl explain role.rules
KIND:     Role
VERSION:  rbac.authorization.k8s.io/v1

RESOURCE: rules <[]Object>

DESCRIPTION:
     Rules holds all the PolicyRules for this Role

     PolicyRule holds information that describes a policy rule, but does not
     contain information about who the rule applies to or which namespace the
     rule applies to.

FIELDS:
   apiGroups    <[]string> # 包含了资源的API组名称,支持列表格式指定的多个组,空串("")表示核心组
     APIGroups is the name of the APIGroup that contains the resources. If
     multiple API groups are specified, any action requested against one of the
     enumerated resources in any API group will be allowed.

   nonResourceURLs      <[]string> #用于定义用户应该有权限访问的网址列表,它并非名称空间级别的资源,因此只能应用于ClusterRole和ClusterRoleBinding,在Role中提供此字段的目的仅为于ClusterRole在格式上兼容
     NonResourceURLs is a set of partial urls that a user should have access to.
     *s are allowed, but only as the full, final step in the path Since
     non-resource URLs are not namespaced, this field is only applicable for
     ClusterRoles referenced from a ClusterRoleBinding. Rules can either apply
     to API resources (such as "pods" or "secrets") or non-resource URL paths
     (such as "/api"), but not both.

   resourceNames        <[]string> #规则应用的目标资源名称列表,可选,缺省时意味着指定资源类型下的所有资源
     ResourceNames is an optional white list of names that the rule applies to.
     An empty set means that everything is allowed.

   resources    <[]string> #规则应用的目标资源类型组成的列表,例如pods、deployments、daemonsets、roles等,ResourceAll表示所有资源
     Resources is a list of resources this rule applies to. ResourceAll
     represents all resources.

   verbs        <[]string> -required- #可应用至此规则匹配到的所有资源类型的操作列表,可用选项有get、list、create、update、patch、watch、proxy、redirect、delete和deletecollection;此为必选字段
     Verbs is a list of Verbs that apply to ALL the ResourceKinds and
     AttributeRestrictions contained in this rule. VerbAll represents all kinds.

  下面是一个定义在rbac名称空间中的Role对象的配置清单示例,它设定了读取、列出及监视pod资源的许可权限:

[root@k8s-master1 ~]# mkdir rbac
You have new mail in /var/spool/mail/root
[root@k8s-master1 ~]# cd rbac/
[root@k8s-master1 rbac]# kubectl create ns rbac
namespace/rbac created
[root@k8s-master1 rbac]# kubectl get ns rbac
NAME   STATUS   AGE
rbac   Active   6s
[root@k8s-master1 rbac]# vim pods-reader.yaml
[root@k8s-master1 rbac]# cat pods-reader.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: rbac
  name: pods-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get","watch","list"]
[root@k8s-master1 rbac]# kubectl apply -f pods-reader.yaml
role.rbac.authorization.k8s.io/pods-reader created
[root@k8s-master1 rbac]# kubectl get role pods-reader -n rbac
NAME          CREATED AT
pods-reader   2022-10-25T12:20:35Z

  绝大数资源均可通过其资源类型的名称引用,如"pods"或“services”等,这些名字与它们在API endpoint中的形式相同。不过,有些资源类型还支持子资源(subresource),例如Pod对象的/log,Node对象的/status等,它们的URL格式通常形如如下表示:

GET /api/v1/namespaces/{namespace}/pods/{name}/log

  在RBAC角色定义中,如果要引用这种类型的子资源,则需要使用“resource/subresource”的格式,如:pods/log。另外,还可以通过直接给定资源名称(resourceName)来引用特定的资源,此时支持使用的操作通常仅为get、delete、update和patch,也可使用这四个操作的子集实现更小范围的可用操作限制。

  除了编写配置清单创建Role资源之外,还可以直接使用“kubectl create role”命令进行快速创建,语法格式如下:

[root@k8s-master1 rbac]# kubectl create role --help
Create a role with single rule.

Examples:
  # Create a Role named "pod-reader" that allows user to perform "get", "watch" and "list" on pods
  kubectl create role pod-reader --verb=get --verb=list --verb=watch --resource=pods

  # Create a Role named "pod-reader" with ResourceName specified
  kubectl create role pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod

  # Create a Role named "foo" with API Group specified
  kubectl create role foo --verb=get,list,watch --resource=rs.extensions

  # Create a Role named "foo" with SubResource specified
  kubectl create role foo --verb=get,list,watch --resource=pods,pods/status

Options:
      --allow-missing-template-keys=true: If true, ignore any errors in templates when a field or map key is missing in
the template. Only applies to golang and jsonpath output formats.
      --dry-run='none': Must be "none", "server", or "client". If client strategy, only print the object that would be
sent, without sending it. If server strategy, submit server-side request without persisting the resource.
      --field-manager='kubectl-create': Name of the manager used to track field ownership.
  -o, --output='': Output format. One of:
json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file.
      --resource=[]: Resource that the rule applies to
      --resource-name=[]: Resource in the white list that the rule applies to, repeat this flag for multiple items
      --save-config=false: If true, the configuration of current object will be saved in its annotation. Otherwise, the
annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future.
      --template='': Template string or path to template file to use when -o=go-template, -o=go-template-file. The
template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
      --validate=true: If true, use a schema to validate the input before sending it
      --verb=[]: Verb that applies to the resources contained in the rule

Usage:
  kubectl create role NAME --verb=verb --resource=resource.group/subresource [--resource-name=resourcename]
[--dry-run=server|client|none] [options]

Use "kubectl options" for a list of global command-line options (applies to all commands).

  例如,下面的命令在rbac名称空间中创建了一个名为services-admin的角色:

[root@k8s-master1 rbac]# kubectl create role services-admin --verb="*" --resource="services,services/*" -n rbac
role.rbac.authorization.k8s.io/services-admin created
You have new mail in /var/spool/mail/root
[root@k8s-master1 rbac]# kubectl get role services-admin -n rbac -o wide
NAME             CREATED AT
services-admin   2022-10-25T12:36:01Z
[root@k8s-master1 rbac]# kubectl describe role services-admin -n rbac
Name:         services-admin
Labels:       <none>
Annotations:  <none>
PolicyRule:
  Resources   Non-Resource URLs  Resource Names  Verbs
  ---------   -----------------  --------------  -----
  services/*  []                 []              [*]
  services    []                 []              [*]

  创建完成之后,rbac名称空间中就有了pods-reader和services-admin两个角色,但角色本身并不能作为动作的执行主体,它们需要“绑定”(RoleBinding)到主体(如user、group或service account)之上才能发生作用。

[root@k8s-master1 rbac]# kubectl get role -n rbac
NAME             CREATED AT
pods-reader      2022-10-25T12:20:35Z
services-admin   2022-10-25T12:36:01Z

  RoleBinding用于将Role中定义的权限赋予一个或一组用户,它由一组主体,以及一个要引用来赋予这组主体的Role或ClusterRole组成。需要注意的是,RoleBinding仅能够引用同一名称空间中的Role对象完成授权。例如,下面配置清单中的RoleBinding于rbac名称空间中将pods-reader角色赋予用户kube-user1,从而使得kube-user1拥有了此角色之上的所有许可授权:

[root@k8s-master1 rbac]# vim pod-read-bind.yaml
[root@k8s-master1 rbac]# cat pod-read-bind.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-read-bind
  namespace: rbac
subjects:
- kind: User
  name: kube-user1
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pods-reader
  apiGroup: rbac.authorization.k8s.io
[root@k8s-master1 rbac]# kubectl apply -f pod-read-bind.yaml
rolebinding.rbac.authorization.k8s.io/pod-read-bind created
[root@k8s-master1 rbac]# kubectl get rolebinding -n rbac
NAME            ROLE               AGE
pod-read-bind   Role/pods-reader   14s
[root@k8s-master1 rbac]# kubectl describe rolebinding pod-read-bind -n rbac
Name:         pod-read-bind
Labels:       <none>
Annotations:  <none>
Role:
  Kind:  Role
  Name:  pods-reader
Subjects:
  Kind  Name        Namespace
  ----  ----        ---------
  User  kube-user1

  将此RoleBinding资源应用到集群中,kube-user1用户便有了读取rbac名称空间中pods资源的权限。将kubectl的配置上下文切换至kube-user1用户,分别对pods和services资源发起访问请求测试,由下面命令结果可以看出,它能够请求读取pods资源,但对其他任何资源的任何操作请求都将被拒绝:

[root@k8s-master1 rbac]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".
[root@k8s-master1 rbac]# kubectl get pods -n rbac
No resources found in rbac namespace.
[root@k8s-master1 rbac]# kubectl get services -n rbac
Error from server (Forbidden): services is forbidden: User "kube-user1" cannot list resource "services" in API group "" in the namespace "rbac"

  RoleBinding资源也能够直接在命令行中创建,语法格式如下:

[root@k8s-master1 ~]# kubectl create rolebinding --help
Create a RoleBinding for a particular Role or ClusterRole.

Examples:
  # Create a RoleBinding for user1, user2, and group1 using the admin ClusterRole
  kubectl create rolebinding admin --clusterrole=admin --user=user1 --user=user2 --group=group1

Options:
      --allow-missing-template-keys=true: If true, ignore any errors in templates when a field or map key is missing in
the template. Only applies to golang and jsonpath output formats.
      --clusterrole='': ClusterRole this RoleBinding should reference
      --dry-run='none': Must be "none", "server", or "client". If client strategy, only print the object that would be
sent, without sending it. If server strategy, submit server-side request without persisting the resource.
      --field-manager='kubectl-create': Name of the manager used to track field ownership.
      --group=[]: Groups to bind to the role
  -o, --output='': Output format. One of:
json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-as-json|jsonpath-file.
      --role='': Role this RoleBinding should reference
      --save-config=false: If true, the configuration of current object will be saved in its annotation. Otherwise, the
annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future.
      --serviceaccount=[]: Service accounts to bind to the role, in the format <namespace>:<name>
      --template='': Template string or path to template file to use when -o=go-template, -o=go-template-file. The
template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
      --validate=true: If true, use a schema to validate the input before sending it

Usage:
  kubectl create rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname]
[--serviceaccount=namespace:serviceaccountname] [--dry-run=server|client|none] [options]

Use "kubectl options" for a list of global command-line options (applies to all commands).

  例如,将kubectl的上下文切换为kubernetes-admin@kubernetes用户,将前面创建的services-admin角色绑定于kube-user1之上,可以使用如下命令进行:

[root@k8s-master1 rbac]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
[root@k8s-master1 rbac]# kubectl create rolebinding services-admin-bind --role=services-admin --user=kube-user1 -n rbac
rolebinding.rbac.authorization.k8s.io/services-admin-bind created
[root@k8s-master1 rbac]# kubectl get rolebinding -n rbac
NAME                  ROLE                  AGE
pod-read-bind         Role/pods-reader      11m
services-admin-bind   Role/services-admin   19s
[root@k8s-master1 rbac]# kubectl get rolebinding services-admin-bind  -n rbac
NAME                  ROLE                  AGE
services-admin-bind   Role/services-admin   32s
[root@k8s-master1 rbac]# kubectl describe rolebinding services-admin-bind -n rbac
Name:         services-admin-bind
Labels:       <none>
Annotations:  <none>
Role:
  Kind:  Role
  Name:  services-admin
Subjects:
  Kind  Name        Namespace
  ----  ----        ---------
  User  kube-user1

  再次切换到kube-user1用户,进行services资源的访问测试,由以下命令结果可知,它能够访问services资源,而不再是拒绝权限:

[root@k8s-master1 rbac]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".
[root@k8s-master1 rbac]# kubectl get services -n rbac
No resources found in rbac namespace.

  事实上,通过services-admin-bind这个RoleBinding绑定至services-admin角色后,kube-user1用户拥有管理rbac名称空间中的Services资源的所有权限。另外需要注意的是,虽然RoleBinding不能跨名称空间引用Role资源,但是主体中的用户账号、用户组和服务账号却不受名称空间的限制,因此,管理员可为一个主体通过不同的RoleBinding资源绑定多个名称空间中的角色。

  RoleBinding的配置清单中主要包含两个嵌套的字段roleRef和subjects,其中subjects的值是一个对象列表,用于给出要绑定的主体,而roleRef的值是单个对象,用于指定要绑定的Role或ClusterRole资源。

  subjects字段可嵌套字段具体说明如下:

[root@k8s-master1 ~]# kubectl explain rolebinding.subjects
KIND:     RoleBinding
VERSION:  rbac.authorization.k8s.io/v1

RESOURCE: subjects <[]Object>

DESCRIPTION:
     Subjects holds references to the objects the role applies to.

     Subject contains a reference to the object or user identities a role
     binding applies to. This can either hold a direct API object reference, or
     a value for non-objects such as user and group names.

FIELDS:
   apiGroup     <string> #要引用的主体所属的API群组,对于Service Account类的主体来说默认为"",而User和Group类主体的默认值为"rbac.authorization.k8s.io"
     APIGroup holds the API group of the referenced subject. Defaults to "" for
     ServiceAccount subjects. Defaults to "rbac.authorization.k8s.io" for User
     and Group subjects.

   kind <string> -required-  #要引用的资源对象(主体)所属的类别,可用值为"User","Group"和"ServiceAccount"
     Kind of object being referenced. Values defined by this API group are
     "User", "Group", and "ServiceAccount". If the Authorizer does not
     recognized the kind value, the Authorizer should report an error.

   name <string> -required-  #引用的主体名称,必选字段
     Name of the object being referenced.

   namespace    <string> #引用的主体所属的名称空间,对于非名称空间类型的主体,如"User"和"Group",其值必须为空,否则授权插件将返回错误信息
     Namespace of the referenced object. If the object kind is non-namespace,
     such as "User" or "Group", and this value is not empty the Authorizer
     should report an error.

  roleRef字段可嵌套字段具体说明如下:

[root@k8s-master1 ~]# kubectl explain rolebinding.roleRef
KIND:     RoleBinding
VERSION:  rbac.authorization.k8s.io/v1

RESOURCE: roleRef <Object>

DESCRIPTION:
     RoleRef can reference a Role in the current namespace or a ClusterRole in
     the global namespace. If the RoleRef cannot be resolved, the Authorizer
     must return an error.

     RoleRef contains information that points to the role being used

FIELDS:
   apiGroup     <string> -required-   #引用的资源(Role或ClusterRole)所属的API群组,必选字段
     APIGroup is the group for the resource being referenced

   kind <string> -required-  #引用的资源所属的类别,可用值为Role或ClusterRole,必选字段
     Kind is the type of resource being referenced

   name <string> -required- #引用的资源名称
     Name is the name of resource being referenced

  Role和RoleBinding是名称空间级别的资源,它们仅能用于完成单个名称空间内的访问控制,此时若要赋予某主体多个名称空间中的访问权限,就不得不逐个名称空间地进行。另外,还有一些资源其本身并不属于名称空间(如PersistentVolume、NameSpace和Node等),甚至还有一些非资源类型的URL路径(如/healthz等),对此类资源的管理显然无法在名称空间级别完成,此时就需要用到另外两个集群级别的资源类型ClusterRole和ClusterRoleBinding。

3. ClusterRole和ClusterRoleBinding

  集群级别的角色资源ClusterRole资源除了能够管理与Role资源一样的许可权限之外,还可以用于集群级组件的授权,配置方式及其在rules字段中可内嵌的字段也与Role资源类似。下面的配置清单示例中定义了ClusterRole资源nodes-reader,它拥有访问集群的节点信息的权限:

[root@k8s-master1 rbac]# vim nodes-reader.yaml
[root@k8s-master1 rbac]# cat nodes-reader.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nodes-reader
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "watch", "list"]
[root@k8s-master1 rbac]# kubectl apply -f nodes-reader.yaml
clusterrole.rbac.authorization.k8s.io/nodes-reader created
[root@k8s-master1 rbac]# kubectl get clusterrole nodes-reader
NAME           CREATED AT
nodes-reader   2022-10-27T14:04:49Z
[root@k8s-master1 rbac]# kubectl get clusterrole nodes-reader -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"rbac.authorization.k8s.io/v1","kind":"ClusterRole","metadata":{"annotations":{},"name":"nodes-reader"},"rules":[{"apiGroups":[""],"resources":["nodes"],"verbs":["get","watch","list"]}]}
  creationTimestamp: "2022-10-27T14:04:49Z"
  managedFields:
  - apiVersion: rbac.authorization.k8s.io/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .: {}
          f:kubectl.kubernetes.io/last-applied-configuration: {}
      f:rules: {}
    manager: kubectl-client-side-apply
    operation: Update
    time: "2022-10-27T14:04:49Z"
  name: nodes-reader
  resourceVersion: "948300"
  selfLink: /apis/rbac.authorization.k8s.io/v1/clusterroles/nodes-reader
  uid: e3cb6fa7-e0ec-4368-9bb3-63248e6b4f8b
rules:
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
  - watch
  - list

  ClusterRole是集群级别的资源,它不属于名称空间,故在此处其配置不应该使用metadata.namespace字段,这也可以通过获取nodes-reader的状态信息来进行验证。kube-user1用户此前绑定的pods-reader和services-admin角色属于名称空间,它们无法给予此用户访问集群级别nodes资源的权限。

  RoleBinding也能够将主体绑定至ClusterRole资源之上,但仅能赋予用户访问RoleBinding资源本身所在的名称空间之内的可由ClusterRole赋予的权限,例如,在ClusterRole具有访问所有名称空间的ConfigMap资源权限时,通过rbac名称空间的RoleBinding将其绑定至kube-user1用户,则kube-user1用户就具有了访问rbac名称空间中的ConfigMap资源的权限,但不能访问其他名称空间中的ConfigMap资源。不过,若借助ClusterRoleBinding进行绑定,则kube-user1就具有了所有名称空间中的ConfigMap资源的访问权限。

  因此,一种常见的做法是集群管理员在集群范围内预先定义好一组访问名称空间级别资源权限的ClusterRole资源,而后在多个名称空间中多次通过RoleBinding引用它们,从而让用户分别具有不同名称空间上的资源的相应访问权限,完成名称空间级别权限的快速授予。例如定义一个集群角色可让用户访问任意secrets:

[root@k8s-master1 rbac]# vim secrets-reader.yaml
[root@k8s-master1 rbac]# cat secrets-reader.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]
[root@k8s-master1 rbac]# kubectl apply -f secrets-reader.yaml
clusterrole.rbac.authorization.k8s.io/secret-reader created
[root@k8s-master1 rbac]# kubectl get clusterrole secret-reader
NAME            CREATED AT
secret-reader   2022-10-27T14:32:51Z

  RoleBinding 也可以引用 ClusterRole,以将对应 ClusterRole 中定义的访问权限授予 RoleBinding 所在名字空间的资源。例如下面的 RoleBinding 引用的是一个secret-reader这个ClusterRole,"kube-user1"(这里的主体, 区分大小写)只能访问 "rbac" 名字空间中的 Secrets 对象,因为 RoleBinding 所在的名字空间(由其 metadata 决定)是 "rbac"

[root@k8s-master1 rbac]# vim read-secret-bind.yaml
You have new mail in /var/spool/mail/root
[root@k8s-master1 rbac]# cat read-secret-bind.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-secret-bind
  namespace: rbac
subjects:
- kind: User
  name: kube-user1
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io
[root@k8s-master1 rbac]# kubectl apply -f read-secret-bind.yaml
rolebinding.rbac.authorization.k8s.io/read-secret-bind created
[root@k8s-master1 rbac]# kubectl get rolebinding read-secret-bind -n rbac
NAME               ROLE                        AGE
read-secret-bind   ClusterRole/secret-reader   32s

  切换到kube-user1用户,进行secret资源的访问测试,由下面命令可知,它能够访问rbac名称空间下的secret资源,其他名称空间下的secret资源则没有权限:

[root@k8s-master1 rbac]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".
[root@k8s-master1 rbac]# kubectl get secrets -n rbac
NAME                  TYPE                                  DATA   AGE
default-token-b5kbb   kubernetes.io/service-account-token   3      2d2h
[root@k8s-master1 rbac]# kubectl get secrets
Error from server (Forbidden): secrets is forbidden: User "kube-user1" cannot list resource "secrets" in API group "" in the namespace "default"

  当然,如果通过ClusterRoleBinding引用这类的ClusterRole,则相应的用户即拥有了在所有相关名称空间上的权限。

[root@k8s-master1 rbac]# vim read-secret-global.yaml
[root@k8s-master1 rbac]# cat read-secret-global.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-secret-global
subjects:
- kind: User
  name: kube-user1
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io
[root@k8s-master1 rbac]# kubectl apply -f read-secret-global.yaml
clusterrolebinding.rbac.authorization.k8s.io/read-secret-global created
[root@k8s-master1 rbac]# kubectl get clusterrolebinding read-secret-global
NAME                 ROLE                        AGE
read-secret-global   ClusterRole/secret-reader   14s

  切换到kube-user1用户,进行secret资源的访问测试,由下面命令可知,它能够访问所有名称空间下的secret资源:

[root@k8s-master1 rbac]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".
[root@k8s-master1 rbac]# kubectl get secrets -n rbac
NAME                  TYPE                                  DATA   AGE
default-token-b5kbb   kubernetes.io/service-account-token   3      2d2h
[root@k8s-master1 rbac]# kubectl get secrets
NAME                                                                       TYPE                                  DATA   AGE
ceph-kubernetes-dynamic-user-9d96ec32-40d2-11ed-b301-0a0d43da79be-secret   Opaque                                1      26d
ceph-secret-1                                                              ceph.com/rbd                          1      27d
cephfs-provisioner-token-ltvpd                                             kubernetes.io/service-account-token   3      27d
cephfs-secret-1                                                            ceph.com/cephfs                       1      27d
default-token-5n29f                                                        kubernetes.io/service-account-token   3      87d
local-registry                                                             kubernetes.io/dockerconfigjson        1      12d
mysql-auth                                                                 Opaque                                2      14d
nfs-client-provisioner-token-qhpns                                         kubernetes.io/service-account-token   3      33d
nginx-ssl                                                                  kubernetes.io/tls                     2      12d
rbd-provisioner-token-qbtmt                                                kubernetes.io/service-account-token   3      27d
sa-demo-token-57nn4                                                        kubernetes.io/service-account-token   3      6d
ssh-key-secret                                                             Opaque                                2      13d
tomcat-ingress-secret                                                      kubernetes.io/tls                     2      39d

  集群级别的资源nodes、persistentvolumes等资源,以及非资源型的URL不属于名称空间级别,故此通过RoleBinding绑定至用户时无法完成访问授权。事实上,所有的非名称空间级别的资源都无法通过RoleBinding绑定至用户并赋予用户相关的权限,这些是属于ClusterRoleBinding的功能。集群角色绑定的角色只能是集群角色,用于进行集群级别或对所有命名空间都生效的授权。例如允许kube-user1用户能获取到集群中节点信息:

[root@k8s-master1 rbac]# vim read-nodes-bind.yaml
[root@k8s-master1 rbac]# cat read-nodes-bind.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-nodes-bind
subjects:
- kind: User
  name: kube-user1
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: nodes-reader
  apiGroup: rbac.authorization.k8s.io
[root@k8s-master1 rbac]# kubectl apply -f read-nodes-bind.yaml
clusterrolebinding.rbac.authorization.k8s.io/read-nodes-bind created
[root@k8s-master1 rbac]# kubectl get clusterrolebinding read-nodes-bind
NAME              ROLE                       AGE
read-nodes-bind   ClusterRole/nodes-reader   20s
[root@k8s-master1 rbac]# kubectl get clusterrolebinding read-nodes-bind -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"rbac.authorization.k8s.io/v1","kind":"ClusterRoleBinding","metadata":{"annotations":{},"name":"read-nodes-bind"},"roleRef":{"apiGroup":"rbac.authorization.k8s.io","kind":"ClusterRole","name":"nodes-reader"},"subjects":[{"apiGroup":"rbac.authorization.k8s.io","kind":"User","name":"kube-user1"}]}
  creationTimestamp: "2022-10-27T14:20:46Z"
  managedFields:
  - apiVersion: rbac.authorization.k8s.io/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .: {}
          f:kubectl.kubernetes.io/last-applied-configuration: {}
      f:roleRef:
        f:apiGroup: {}
        f:kind: {}
        f:name: {}
      f:subjects: {}
    manager: kubectl-client-side-apply
    operation: Update
    time: "2022-10-27T14:20:46Z"
  name: read-nodes-bind
  resourceVersion: "951053"
  selfLink: /apis/rbac.authorization.k8s.io/v1/clusterrolebindings/read-nodes-bind
  uid: 98c11f57-8355-4212-86a1-655673d99ff1
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: nodes-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: kube-user1

  切换到kube-user1用户,进行nodes资源的访问,由下面命令结果可知,它能够访问到nodes资源:

[root@k8s-master1 rbac]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".
You have new mail in /var/spool/mail/root
[root@k8s-master1 rbac]# kubectl get nodes
NAME          STATUS   ROLES                  AGE   VERSION
k8s-master1   Ready    control-plane,master   87d   v1.20.6
k8s-node1     Ready    worker                 87d   v1.20.6
k8s-node2     Ready    worker                 87d   v1.20.6

  另外,除了名称空间及集群级别的资源之外,Kubernetes还有着/api,/apis,/healthz、/swaggerapi和/version等非资源型URL,对这些URL的访问也必须事先获得相关的权限。同集群级别的资源一样,它们也只能定义在ClusterRole中,且需要基于ClusterRoleBinding进行授权。不过,对此类资源的读取权限已经由系统默认的名称同为system:discovery的ClusterRole和ClusterRoleBinding两个资源自动设定。下面的命令显示了system:discovery ClusterRole的相关信息:

[root@k8s-master1 ~]# kubectl get clusterrole system:discovery -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2022-08-01T12:44:58Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  managedFields:
  - apiVersion: rbac.authorization.k8s.io/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .: {}
          f:rbac.authorization.kubernetes.io/autoupdate: {}
        f:labels:
          .: {}
          f:kubernetes.io/bootstrapping: {}
      f:rules: {}
    manager: kube-apiserver
    operation: Update
    time: "2022-08-01T12:44:58Z"
  name: system:discovery
  resourceVersion: "86"
  selfLink: /apis/rbac.authorization.k8s.io/v1/clusterroles/system%3Adiscovery
  uid: 52a17e69-6cc3-4f98-aef2-54f019e04d8c
rules:
- nonResourceURLs:
  - /api
  - /api/*
  - /apis
  - /apis/*
  - /healthz
  - /livez
  - /openapi
  - /openapi/*
  - /readyz
  - /version
  - /version/
  verbs:
  - get

  nonResourceURLs字段给出了相关的URL列表(不同版本的kubernetes系统上的显示可能略有区别)允许的访问权限仅有“get”一个。引用了此资源的ClusterRoleBinding的相关信息如下面的命令及其结果所示:

[root@k8s-master1 ~]# kubectl get clusterrolebindings system:discovery -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2022-08-01T12:44:59Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  managedFields:
  - apiVersion: rbac.authorization.k8s.io/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .: {}
          f:rbac.authorization.kubernetes.io/autoupdate: {}
        f:labels:
          .: {}
          f:kubernetes.io/bootstrapping: {}
      f:roleRef:
        f:apiGroup: {}
        f:kind: {}
        f:name: {}
      f:subjects: {}
    manager: kube-apiserver
    operation: Update
    time: "2022-08-01T12:44:59Z"
  name: system:discovery
  resourceVersion: "147"
  selfLink: /apis/rbac.authorization.k8s.io/v1/clusterrolebindings/system%3Adiscovery
  uid: 149d7a11-adec-49ae-9a76-37eb81d945fc
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:discovery
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:authenticated

  由命令的输出结果可知,它绑定了system:authenticated这个组,因此,所有认证了的用户默认均有权限请求读取这些资源,任何发往API Server的此类端点请求都会得到响应。例如,下面的ClusterRole资源示例定义了对非资源型URL路劲/healthz的读写访问权限:

[root@k8s-master1 rbac]# vim healthz-admin.yaml
[root@k8s-master1 rbac]# cat healthz-admin.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: health-admin
rules:
- nonResourceURLs:
  - /healthz
  verbs: ["get", "create"]
[root@k8s-master1 rbac]# kubectl apply -f healthz-admin.yaml
clusterrole.rbac.authorization.k8s.io/health-admin created
[root@k8s-master1 rbac]# kubectl get clusterrole health-admin
NAME           CREATED AT
health-admin   2022-10-28T11:17:47Z
[root@k8s-master1 rbac]# kubectl get clusterrole health-admin -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"rbac.authorization.k8s.io/v1","kind":"ClusterRole","metadata":{"annotations":{},"name":"health-admin"},"rules":[{"nonResourceURLs":["/healthz"],"verbs":["get","create"]}]}
  creationTimestamp: "2022-10-28T11:17:47Z"
  managedFields:
  - apiVersion: rbac.authorization.k8s.io/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .: {}
          f:kubectl.kubernetes.io/last-applied-configuration: {}
      f:rules: {}
    manager: kubectl-client-side-apply
    operation: Update
    time: "2022-10-28T11:17:47Z"
  name: health-admin
  resourceVersion: "960302"
  selfLink: /apis/rbac.authorization.k8s.io/v1/clusterroles/health-admin
  uid: 184ad3d4-5422-4f5d-ac72-e4a1cdf53c03
rules:
- nonResourceURLs:
  - /healthz
  verbs:
  - get
  - create

  另外,非资源型URL的授权规则与资源权限的授权规则可定义在同一个ClusterRole中,它们同属于rules字段中的对象。

4. 聚合型ClusterRole

  kubernetes自1.9版本开始支持在rules字段中嵌套aggregationRule字段来整合其他的ClusterRole对象的规则,这种类型的ClusterRole的权限受控于控制器,它们由所有被标签选择器匹配到的用于聚合的ClusterRole的授权规则合并生成。下面是一个示例,它定义了一个标签选择器用于挑选匹配的ClusterRole:

[root@k8s-master1 rbac]# vim monitoring.yaml
[root@k8s-master1 rbac]# cat monitoring.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: monitoring
aggregationRule:
  clusterRoleSelectors:
  - matchLabels:
      rbac.example.com/aggredate-to-monitoring: "true"
rules: []

  任何能够被示例中的资源的标签选择器匹配到的ClusterRole的相关规则都将一同合并为它的授权规则,后续新增的ClusterRole资源亦是如此。因此,聚合型ClusterRole的规则会随着标签选择器的匹配结果而动态变化。下面即是一个能匹配到此聚合型ClusterRole的另一个ClusterRole的示例:

[root@k8s-master1 rbac]# vim monitoring-endpoints.yaml
You have new mail in /var/spool/mail/root
[root@k8s-master1 rbac]# cat monitoring-endpoints.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: monitoring-endpoints
  labels:
    rbac.example.com/aggredate-to-monitoring: "true"
rules:
- apiGroups: [""]
  resources: ["services", "endpoints", "pods"]
  verbs: ["get", "list", "watch"]

  创建上述两个资源,而后查看聚合型ClusterRole资源monitoring的相关权限信息,由下面的命令结果可以看出,它所拥有的权限包含了ClusterRole资源monitoring-endpoints的所有授权:

[root@k8s-master1 rbac]# kubectl create -f monitoring.yaml 
clusterrole.rbac.authorization.k8s.io/monitoring created
[root@k8s-master1 rbac]# kubectl create -f monitoring-endpoints.yaml
clusterrole.rbac.authorization.k8s.io/monitoring-endpoints created
[root@k8s-master1 rbac]# kubectl get clusterrole monitoring -o yaml
aggregationRule:
  clusterRoleSelectors:
  - matchLabels:
      rbac.example.com/aggredate-to-monitoring: "true"
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: "2022-10-28T11:41:44Z"
  managedFields:
  - apiVersion: rbac.authorization.k8s.io/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:aggregationRule:
        .: {}
        f:clusterRoleSelectors: {}
    manager: kubectl-create
    operation: Update
    time: "2022-10-28T11:41:44Z"
  - apiVersion: rbac.authorization.k8s.io/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:rules: {}
    manager: kube-controller-manager
    operation: Update
    time: "2022-10-28T11:43:54Z"
  name: monitoring
  resourceVersion: "964816"
  selfLink: /apis/rbac.authorization.k8s.io/v1/clusterroles/monitoring
  uid: c278c42e-71ca-49b8-b5bf-8e27cb19d96f
rules:
- apiGroups:
  - ""
  resources:
  - services
  - endpoints
  - pods
  verbs:
  - get
  - list
  - watch

  事实上,kubernetes系统上面向用户的内建ClusterRole admin和edit 也是聚合型ClusterRole,因为这可以使得默认角色中包含自定义资源的相关规则,例如,由CustomResource-Definitions或Aggregated API服务器提供的规则等。

5. 面向用户的内建ClusterRole

  API Server内建了一组默认的ClusterRole和ClusterRoleBinding以预留系统使用,其中大多数都以“system:”为前缀。另外还有一些非以“system:”为前缀的默认的Role资源,它们是为面向用户的需求而设计的,包括超级用户角色(cluster-admin)、用于授权集群级别权限的ClusterRoleBinding(cluster-status)以及授予特定名称空间级别权限的RoleBinding(admin、edit和view)。

  内建的ClusterRole资源cluster-admin拥有管理集群所有资源的权限,它基于同名的ClusterRoleBinding资源绑定到了“system:masters”组上,这意味着所有隶属于此组的用户都将具有集群的超级管理权限。kubeadm安装设定集群时自动创建的配置文件/etc/kubernetes/admin.conf中定义的用户kubernetes-admin使用证书文件/etc/kubernetes/pki/apiserver-kubelet-client.crt向API Server进行验证。而此证书的Subject信息为“/O=system:masters/CN=kubernetes-admin”,进行认证时,CN的值可作为用户名使用,而O的值将作为用户所属组名使用,因此,kubernetes-admin具有集群管理权限。

  于是,为kubernetes集群额外自定义超级管理员的方法至少有两种:一种是创建用户证书,其Subject中O的值为“system:masters”,另一种是创建ClusterRoleBinding将用户绑定至cluster-admin之上。

  另外,在多租户、多项目或多环境等使用场景中,用户通常应该获取名称空间级别绝大多数资源的管理、只读或编辑权限,这类权限的快速授予可通过在指定的名称空间中创建RoleBinding资源引用内建的ClusterRole资源admin、view或edit来进行。例如,在名称空间dev中创建一个RoleBinding资源,它将引用admin,并绑定至kube-user1,使得此用户具有管理dev名称空间中除了名称空间本身及资源配额之外的所有资源的权限:

[root@k8s-master1 rbac]# kubectl create ns dev
namespace/dev created
[root@k8s-master1 rbac]# kubectl create rolebinding dev-admin --clusterrole=admin --user=kube-user1 -n dev
rolebinding.rbac.authorization.k8s.io/dev-admin created
[root@k8s-master1 rbac]# kubectl get rolebinding dev-admin -n dev
NAME        ROLE                AGE
dev-admin   ClusterRole/admin   19s

  而后切换至kube-user1用户在dev中创建一个资源,并查看相关信息进行测试访问,如下面命令所示:

[root@k8s-master1 rbac]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".
[root@k8s-master1 rbac]# kubectl create deployment myapp-deploy --image=ikubernetes/myapp:v1 -n dev
deployment.apps/myapp-deploy created
[root@k8s-master1 rbac]# kubectl get all -n dev -o wide
NAME                               READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
pod/myapp-deploy-b7df67f84-vtn6g   1/1     Running   0          34s   10.244.169.181   k8s-node2   <none>           <none>

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES                 SELECTOR
deployment.apps/myapp-deploy   1/1     1            1           34s   myapp        ikubernetes/myapp:v1   app=myapp-deploy

NAME                                     DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES                 SELECTOR
replicaset.apps/myapp-deploy-b7df67f84   1         1         1       34s   myapp        ikubernetes/myapp:v1   app=myapp-deploy,pod-template-hash=b7df67f84

  如果需要授予的是编辑或只读权限,则仅需要将创建RoleBinding时引用的ClusterRole相应地修改为edit或view即可。下面表格中总结了典型的面向用户的内建ClusterRole及其说明:

  API Server会创建一组默认的ClusterRole和ClusterRoleBinding,大多数都以“system:”为前缀,被系统基础架构所使用,修改这些资源将会导致集群功能不正常。一般所有默认的ClusterRole和ClusterRoleBinding都打了标签“kubernetes.io/bootstrapping: rbac-defaults”。

  每次启动时,API Server都会自动为默认的ClusterRole重新赋予缺失的权限,以及为默认的ClusterRoleBinding绑定缺失的Subject。这种机制给了集群从意外修改中自动恢复的能力,以及升级版本后,自动将ClusterRole和ClusterRoleBinding升级到满足新版本需求的能力。

  Kubernetes内建的其他的ClusterRole和ClusterRoleBinding还有很多,它们绝大多数都是用于系统本身的诸多组件结合RBAC获得最小化但完整的资源访问授权。它们大体可分为专用于核心的组件、附加的组件、资源发现及controller-manager运行核心控制循环(control loop)等几个类型,如system:kube-scheduler、system:kube-controller-manager、system:node、system:node-proxier和system:kube-dns等。

posted @ 2022-10-28 21:07  出水芙蓉·薇薇  阅读(443)  评论(0编辑  收藏  举报