RBAC授权模式详解

  RBAC(Role-Based Access Control,基于角色的访问控制)在Kubernetes的1.5版本中引入,在1.6版本时升级为Beta版本,在1.8版本时升级为GA。作为Kubeadm安装方式的默认选项,足见其重要程度。相对于其他访问控制方式,新的RBAC具有如下优势。

  •   对集群中的资源和非资源权限均有完整的覆盖。
  •   整个RBAC完全由几个API对象完成,同其他API对象一样,可以用kubectl或API进行操作。
  •   可以在运行时进行调整,无须重新启动API Server。

    要使用RBAC授权模式,需要在API Server的启动参数中加入-authorization-mode=RBAC.

    下面对RBAC的原理和永华进行说明。

1.RBAC的API资源对象说明      

      RBAC引入了4个新的顶级资源对象: Role、ClusterRole、RoleBinding和ClusterRoleBinding。同其他API资源对象一样,用户可以使用kubectl或者API调用等方式操作这些资源对象。

  1)角色(Role)

      一个角色就是一个组权限的集合,这里的权限都是许可形式的,不存在拒绝的规则。在一个命名空间中,可以用角色来定义一个角色,如果是集群级别的,就需要使用ClusterRole了。

       角色只能对命名空间内的资源进行授权,在下面例子中定义的角色具备读取Pod的权限:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" 空字符串,表示核心API群
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

       rules中的参数说明如下:

       apiGroups:  支持的API组列表,例如“apiVersion:batch/v1” "apiVersion:extensions:v1beta1" "apiVersion:apps/v1beta1"等。

       resources: 支持的资源对象列表,例如pods、deployments、jobs等。

       verbs: 对资源对象的操作方法列表,例如get、watch、list、delete、replace、patch等。

2) 集群角色(ClusterRole)

    集群角色除了具有和角色一致的命名空间内资源的管理能力,因其集群级别的范围,还可以用于以下特殊元素的授权。

  • 集群范围的资源,例如Node。
  • 非资源的路径,例如“/healthz”。
  • 包含全部命名空间的资源,例如pods(用于kubectl get pods --all-namespaces这样的操作授权)。

   下面的集群角色可以让用户有权访问任意一个或所有命名空间的secrets(视其绑定方式而定):

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
   # ClusterRole  不受限于命名空间,所以无须设置Namespace的名称
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get","watch","list"]

    3)角色绑定(RoleBinding)和集群角色绑定(ClusterRoleBinding)

        角色绑定或集群角色绑定用来把一个角色绑定到一个目标上,绑定目标可以是User(用户),Group(组)或者Service Account。 使用RoleBinding为某个命名空间授权,使用ClusterRoleBinding为集群范围内授权。

       RoleBinding可以引用Role进行授权,下面的例子中的Rolebinding将在default命令空间中把pod-reader角色授予用户jane,这易操作可以让jane读取default命令空间中的Pod:

     

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: jane
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

     集群角色绑定中的角色只能是集群角色,用于进行集群级别或者对所有命名空间都生效的授权。下面的例子允许manager组的用户读取任意Namespace中的secret:

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: read-secrets-global
subjects:
- kind: Group
  name: manager
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

 

上图展示了上述对Pod的get/watch/list操作进行授权的Role和RoleBinding逻辑关系。

 

2.对资源的引用方式

     多数资源可以用其名称的字符串来表达,也就是Endpoint中的URL相对路径,例如pods。然而,某些Kubernetes API包含下级资源,例如Pod的日志(logs)。Pod日志的Endpoint是GET/ api/v1/namespaces/{namespace}/pods/{name}/log。
      在这个例子中,Pod是一个命名空间内的资源,log就是一个下级资源。要在一个RBAC角色中体现,就需要用斜线“/”来分隔资源和下级资源。若想授权让某个主体同时能够读取Pod和Pod log,则可以配置resources为一个数组:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list"]

       资源还可以通过名称(ResourceName)进行引用。在指定ResourceName后,使用get、delete、update和patch动词的请求,就会被限制在这个资源实例范围内。例如,下面的声明让一个主体只能对一个ConFigmap进行get和update操作:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: configmap-updater
rules:
- apiGroups: [""]
  resources: ["configmap"]
  resourceNames: ["my-configmap"]
  verbs: ["update", "get"]

    可想而知,resourceName这种用法对list、watch、create或deletecollection操作是无效的,这是因为必须要通过URL进行鉴权,而资源名称在list、watch、create或deletecollection请求中只是请求Body数据的一部分。
下面对常见的角色和角色绑定给出示例,提供参考用法。

3.常用的角色示例

 注意,下面的例子只展示了rules部分的内容。

(1) 允许读取核心API组中的Pod资源:       

rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get","list","watch"]

 (2)  允许读写extensions和apps两个API组中的deployment资源:

rules:
- apiGroups: ["extensions", "apps"]
  resources: ["deployments"]
  verbs: ["get","list","watch","create","update","patch","delete"]

(3)  允许读取pods及读写jobs:

rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get","list","watch"]
- apiGroups: ["batch", "extensions"]
  resources: ["jobs"]
  verbs: ["get","list","watch","create","update","patch","delete"]

(4) 允许读取一个名为my-config的ConfigMap(必须绑定到一个RoleBinding来限制到一个Namespace下的ConfigMap):

rules:
- apiGroups: [""]
  resources: ["configmaps"]
  resourceNames: ["my-config"]
  verbs: ["get"]

(5) 读取核心组的Node资源(Node属于集群级的资源,所以必须存在于ClusterRole中,并使用ClusterRoleBinding进行绑定):

rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get","list","watch"]

(6) 允许对非资源端点“/healthz”及其所有子路径进行GET和POST操作(必须使用ClusterRole和ClusterRoleBinding):

rules:
- nonResourceURLs: ["/healthz","/healthz/*"]
  verbs: ["get","post"]

4.常见的角色绑定示例

    注意,在下面例子中只包含subjects部分的内容。

(1)用户名alice@example.com:

subjects:
- kind: User
  name: "alice@example.com"
  apiGroup: rbac.authorization.k8s.io

(2) 组名frontend-admins:

subjects:
- kind: Group
  name: "frontend-admins"
  apiGroup: rbac.authorization.k8s.io

(3) kube-system命令空间中的默认Service Account:

subjects:
- kind: ServiceAccount
  name: default
  namespace: kube-system

(4) qa命名空间中的所有Service Account:

subjects:
- kind: Group
  name: system.serviceaccounts:qa
  apiGroup: rbac.authorization.k8s.io

(5) 所有Service Account:

subjects:
- kind: Group
  name: system.serviceaccounts
  apiGroup: rbac.authorization.k8s.io

(6) 所有认证用户(kuberetes1.5以上版本):

subjects:
- kind: Group
  name: system:authenticated
  apiGroup: rbac.authorization.k8s.io

(7) 所有未认证用户(kubernetes1.5以上版本):

subjects:
- kind: Group
  name: system:unauthenticated
  apiGroup: rbac.authorization.k8s.io

(8) 全部用户(kubernetes1.5以上版本):

subjects:
- kind: Group
  name: system:authenticated
  apiGroup: rbac.authorization.k8s.io
- kind: Group
  name: system:unauthenticated
  apiGroup: rbac.authorization.k8s.io

5. 默认的角色和角色绑定
 

      API Server会创建一套默认的ClusterRole和ClusterRoleBinding对象,其中很多是以“system:”为前缀的,以表明这些资源属于基础架构,对这些对象的改动可能造成集群故障。举例来说,system:node这个ClusterRole为kubelet定义了权限,如果这个集群角色被改动了,kubelet就会停止工作。

    所有默认的ClusterRole和RoleBinding都会用标签kubernetes.io/bootstrapping=rbac-defaults进行标记。

   下面对一些常见的默认ClusterRole和ClusterRoleBinding对象进行说明。

    对系统角色的说明如下表所示。

默认的ClusterRole默认的ClusterRoleBinding描述
system:basic-usersystem:authenticated让用户能够读取自身的信息(在k8s1.14版本之前,还绑定了system:unauthenticated组)
system:discoverysystem:authenticated队API发现Endpoint的只读访问,用于API级别的发现和协商(在k8s1.14版本之前还绑定了system:unauthenticated组)
system:public-info-viewr

system:authenticated与

system:unauthenticated 组

允许读取集群的非敏感信息(从k8s1.14开始引入)

 

       对用户角色的说明如下表所示。有些默认角色不是以“system:” 为前缀的,这部分角色是针对用户的。其中包含超级用户角色(cluster-admin),有的用于集群一级的角色(cluster-status),还有针对Namespace的角色(admin、edit、view)。

 

默认的ClusterRole默认的ClusterRoleBinding描述
cluster-adminsystem:master组让超级用户可以对任何资源执行任何操作,如果在ClusterRoleBinding中使用,则影响的是整个集群所有namespace中的任何资源;如果使用的是RoleBinding,则能控制这一绑定的Namespace中的资源,还包含Namespace本身
adminNone允许admin访问,可以限制在一个Namespace中使用RoleBinding。如果在RoleBinding中使用,则允许对Namespace中的大多数资源进行读写访问,其中包含创建角色和角色绑定的能力。这一角色不允许操作Namespace本身,也不能写入资源限额
editNone允许对命令空间中的大多数资源进行读写操作,不允许查看或修改角色,以及角色绑定
viewNone允许对多数对象进行只读操作,但是对角色、角色绑定及secret是不可访问的

     

对核心Master组件角色的说明如下表:

默认的ClusterRole默认的ClusterRoleBinding描述
system:kube-shedulersystem:kube-scheduler用户能够访问kube-scheduler组件所需的资源
system:volume-shedulersystem: kube-scheduler用户允许kube-sheduler组件访问Volume资源
system:kube-controller-managersystem:kube-controller-manager用户能够访问kube-controller-manager组件所需的资源。
system:nodeNone允许访问kubelet组件所需的资源,包括所有secret的读取,以及对所有Pod状态的写访问。从Kubernetes1.8版本开始,就没有自动绑定过程了。
system:node-proxiersystem:kube-prixy用户允许访问kube-proxy所需的资源

对其他组件角色的说明如下表所示:

默认的ClusterRole默认的ClusterRoleBinding描述
system:auth-delegatorNone允许对授权和认证进行托管,通常用于附加的API服务器
system:heapsterNoneHeapster组件的角色
system:kube-aggregatorNonekube-aggregator角色
system:kube-dns

在kube-system namespace中

kube-dns的Service Account

kube-dns的角色
system:kubelet-api-adminNone允许对kubeket API 的完全访问
system:node-bootstrapperNone允许访问kubelet TLS启动所需的资源
system:node-problem-detectorNone允许访问node-problem-detector组件所需的资源
system:persistent-volume-provisionerNone

允许访问多数动态卷供给所有资源

                                需要赋予的角色

system:controller:attachdetach-controller
system:controller:certificate-controller
system:controller:clusterrole-aggregation-controller
system:controller:cronjob-controller
system:controller:daemon-set-controller
system:controller:deployment-controller
system:controller:disruption-controller
system:controller:endpoint-controller
system:controller:expand-controller
system:controller:generic-garbage-collector
system:controller:horizontal-pod-autoscaler
system:controller:job-controller
system:controller:namespace-controller
system:controller:node-controller
system:controller:persistent-volume-bider
system:controller:pod-garbage-collector
system:controller:pv-protection-controller
system:controller:pvc-protection-controller
system:controller:replication-controller
system:controller:replicaset-controller
system:controller:resourcequota-controller
system:controller:root-ca-cert-publisher
system:controller:route-controller
system:controller:service-account-controller
system:controller:service-controller
system:controller:statefulset-controller
system:controller:ttl-controller

 

      Kubernetes Controller Manager负责的是核心控制流。如果用--use-service-accountcredentials调用,则每个控制过程都会使用不同的Service Account启动,因此就有了对应各个控制过程的角色,前缀是system:controller。如果Controller Manager没有用--use-service-account-credentials启动参数,则将使用自己的凭据运行各个控制流程,这就需要为该凭据授予所有相关角色。

6.授权注意实现:预防提升权限和授权初始化


      RBAC API拒绝用户通过编辑角色或者角色绑定进行提升权限。这一限制是在API层面做出的,因此即使RBAC没有启用也仍然有效。
用户要对角色进行创建或更新操作,需要满足下列至少一个条件:
(1)拥有一个角色的所有权限,且与该角色的生效范围一致(如果是集群角色,则是集群范围;如果是普通角色,则可能是同一个命名空间或者整个集群);
(2)为用户显式授予针对该角色或集群角色的提权(escalate)操作的权限(要求Kubernetes 1.12及以上版本)。
例如,用户user-1没有列出集群中所有secret的权限,就不能创建具有这一权限的集群角色。要让一个用户能够创建或更新角色,需要:
(1)为其授予一个允许创建或更新Role或ClusterRole资源对象的角色;
(2)为其授予绑定某一角色的权限,有隐式或显式两种方法。
◎ 隐式:为用户授予权限,要覆盖该用户所能控制的所有权限范围。用户如果尝试创建超出其自身权限的角色或者集群角色,则该API调用会被禁止。
◎ 显式:为用户显式授予针对该Role或ClusterRole的提权(Escalate)操作的权限(要求Kubernetes 1.12及以上版本)。
       

      如果一个用户的权限包含一个角色的所有权限,就可以为其创建和更新角色绑定(要求同样的作用范围);或者如果被授予了针对某个角色的绑定授权,则也有权完成此操作。例如,如果用户user-1没有列出集群内所有secret的权限,就无法为一个具有这样权限的角色创建集群角色绑定。要使用户能够创建、更新这一角色绑定,则需要这样做,如下所述。
(1)为其授予一个允许创建和更新RoleBinding或ClusterRoleBinding的角色。
(2)为其授予绑定某一角色的权限,有隐式或显式两种方法。
◎ 隐式:让其具有该角色的所有权限。
◎ 显式:为用户授予针对该角色(或集群角色)的绑定操作的权限。
例如,下面的集群角色和角色绑定能让user-1为其他用户在user-1-namespace命名空间中授予admin、edit及view角色:

apiVersion:rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: role-grantor
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
  resources: ["rolebindings"]
  verbs: ["create"]
- apiGroups: ["rbac.authorization.k8s.io"]
  resources: ["clusterroles"]
  verbs: ["bind"]
  resourceName: ["admin","edit","view"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: role-grantor-binding
  namespace: user-1-namespace
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: role-grantor
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: user-1

        在进行第1个角色和角色绑定时,必须让初始用户具备其尚未被授予的权限。要进行初始的角色和角色绑定设置,有以下两种办法。
(1)使用属于system:masters组的身份,这一群组默认具有cluster-admin这一超级角色的绑定。

(2)如果API Server以--insecure-port参数运行,则客户端通过这个非安全端口进行接口调用,这一端口没有认证鉴权的限制。

7.对Service Account的授权管理

 

      默认的RBAC策略为控制平台组件、节点和控制器授予有限范围的权限,但是除kube-system外的Service Account是没有任何权限的(除了所有认证用户都具有的discovery权限)。
这就要求用户为Service Account赋予所需的权限。细粒度的角色分配能够提高安全性,但也会提高管理成本。粗放的授权方式可能会给Service Account多余的权限,但更易于管理。
下面的实践以安全性递减的方式排序。
(1)为一个应用专属的Service Account赋权(最佳实践)。
这个应用需要在Pod的Spec中指定一个serviceAccountName,用API、Application Manifest、kubectl create serviceaccount命令等创建Service Account,例如为my-namespace中的“my-sa”Service Account授予只读权限:

kubectl create rolebinding my-namespace \
--clusterrole=view \
--serviceaccount=my-namespace:my-sa \
--namespace=my-namespace

 

(2)为一个命名空间中名为default的Service Account授权。
如果一个应用没有指定serviceAccountName,则会使用名为default的Service Account。注意,赋给Service Account“default”的权限会让所有没有指定serviceAccountName的Pod都具有这些权限。
例如,在my-namespace命名空间中为Service Account“default”授予只读权限:

kubectl create clusterrolebinding serviceaccounts-cluster-admin \
--clusterrole=cluster-admin \
--group=system:serviceaccounts

 

     另外,许多系统级Add-Ons都需要在kube-system命名空间中运行。要让这些Add-Ons能够使用超级用户权限,则可以把cluster-admin权限赋予kube-system命名空间中名为default的Service Account。注意,这一操作意味着kube-system命名空间包含了通向API超级用户的捷径:

kubectl  create clusterrolebinding add-on-cluster-admin \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:default

(3)为命名空间中的所有Service Account都授予一个角色。
如果希望在一个命名空间中,任何Service Account的应用都具有一个角色,则可以为这一命名空间的Service Account群组进行授权。
例如,为my-namespace命名空间中的所有Service Account赋予只读权限:

kubectl create rolebinding serviceaccouts-view \
--clusterrole=view \
--group=system:serviceaccounts:my-namespace \
--namespace=my-namespace

 

(4)为集群范围内的所有Service Account都授予一个低权限角色(不推荐)。
如果不想为每个命名空间管理授权,则可以把一个集群级别的角色赋给所有Service Account。
例如,为所有命名空间中的所有Service Account授予只读权限:

kubectl create clusterrolebinding serviceaccounts-view \
--clusterrole=view \
--group=system:serviceaccounts

(5)为所有Service Account授予超级用户权限(强烈不建议这样设置)。
如果完全不在意权限,则可以把超级用户权限分配给每个Service Account。
注意,这让所有具有读取Secret权限的用户都可以创建Pod来访问超级用户的专属权限:

kubectl create clusterrolebinding serviceaccounts-cluster-admin \
--clusterrole=view \
--group=system:serviceaccounts

8. 使用kubectl命令工具创建资源对象

    

       除了使用YAML配置文件来创建这些资源对象,也可以直接使用kubectl命令行工具对它们进行创建。下面通过几个例子进行说明。
(1)在命名空间acme中为用户bob授权admin ClusterRole:

kubectl create rolebinding bob-admin-binding --clusterrole=admin --user=bob --namespace=acme


(2)在命名空间acme中为名为myapp的Service Account授予view ClusterRole:

kubectl create robebinding myapp-view-binding --clusterrole=view --serviceaccount=acme:myapp --namespace:acme

(3)在全集群范围内为用户root授予cluster-admin ClusterRole:

kubectl create clusterrolebinding root-cluster-admin-binding --clusterrole=cluster-admin --user=root


(4)在全集群范围内为用户kubelet授予system:node ClusterRole:

kubectl cerate clusterrolebinding kubelete=node-binding --clusterrole=system:node --user=kubelet


(5)在全集群范围内为名为myapp的Service Account授予view ClusterRole:

kubectl create clusterrolebinding myapp-view-binding --clusterrole=view --serviceaccount=acme:myapp

可以在kubectl --help的帮助中查看更详细的说明。

9.RBAC的Auto-reconciliation(自动恢复)功能

     自动恢复从Kubernetes 1.6版本开始引入。每次启动时,API Server都会更新默认的集群角色的缺失权限,也会刷新在默认的角色绑定中缺失的主体,这样就防止了一些破坏性的修改,也保证了在集群升级的情况下相关内容能够及时更新。
如果不希望使用这一功能,则可以将一个默认的集群角色或者角色绑定的Annotation注解“rbac.authorization.kubernetes.io/autoupdate”值设置为false。

10.从旧版本的授权策略升级到RBAC

     在Kubernetes 1.6之前,很多Deployment都试用了比较宽松的ABAC策略,包含为所有Service Account都开放完全API访问权限。
     默认的RBAC策略为控制台组件、节点和控制器授予了范围受限的权限,但是不会为kube-system以外的Service Account授予任何权限。
       这样一来,可能会对现有的一些工作负载造成影响,这时有两种办法来解决这一问题。
(1)并行认证。RBAC和ABAC同时运行,并包含传统的ABAC策略:

--authorization-mode=RBAC,ABAC --authorization-policy-file=mypolicy.json1

      首先会由RBAC尝试对请求进行鉴权,如果得到的结果是拒绝,就轮到ABAC生效。这样,所有应用只要满足RBAC或ABAC之一即可工作。
      使用5或者更详细的日志级别(--v=5或--vmodule=rbac*=5),则可以在API Server日志中看到RBAC的拒绝行为(前缀:RBAC DENY)。可以利用这一信息来确定需要授予何种权限给用户、组或Service Account。等到集群管理员按照RBAC的方式对相关组件进行了授权,并且在日志中不再出现RBAC的拒绝信息,就可以移除ABAC认证方式了。
(2)粗放管理。可以使用RBAC的角色绑定,复制一个粗放的策略。
警告:下面的策略让所有Service Account都具备了集群管理员权限,所有容器运行的应用都会自动接收Service Account的认证,能够对任何API做任何事情,包括查看secret和修改授权。注意,这不是一个值得推荐的策略。

kubectl create clusterrolebinding permissive-binding \
--clusterrole=cluster-admin \
--user=admin \
--user-kubelet \
--group=system:serviceaccounts

小结:

      本节内容较多,但是很重要,希望大家可以好好看,一定要掌握哦。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐