带你玩转kubernetes-k8s(第39篇:深入分析集群安全机制二[RBAC授权模式])
RBAC授权模式详解RBAC(Role-Based Access Control,基于角色的访问控制)在Kubernetes的1.5版本中引入,在1.6版本时升级为Beta版本,在1.8版本时升级为GA。作为Kubeadm安装方式的默认选项,足见其重要程度。相对于其他访问控制方式,新的RBAC具有如下优势。对集群中的资源和非资源权限均有完整的覆盖。整个RBAC完全由几个AP...
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-user | system:authenticated | 让用户能够读取自身的信息(在k8s1.14版本之前,还绑定了system:unauthenticated组) |
system:discovery | system: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-admin | system:master组 | 让超级用户可以对任何资源执行任何操作,如果在ClusterRoleBinding中使用,则影响的是整个集群所有namespace中的任何资源;如果使用的是RoleBinding,则能控制这一绑定的Namespace中的资源,还包含Namespace本身 |
admin | None | 允许admin访问,可以限制在一个Namespace中使用RoleBinding。如果在RoleBinding中使用,则允许对Namespace中的大多数资源进行读写访问,其中包含创建角色和角色绑定的能力。这一角色不允许操作Namespace本身,也不能写入资源限额 |
edit | None | 允许对命令空间中的大多数资源进行读写操作,不允许查看或修改角色,以及角色绑定 |
view | None | 允许对多数对象进行只读操作,但是对角色、角色绑定及secret是不可访问的 |
对核心Master组件角色的说明如下表:
默认的ClusterRole | 默认的ClusterRoleBinding | 描述 |
---|---|---|
system:kube-sheduler | system:kube-scheduler用户 | 能够访问kube-scheduler组件所需的资源 |
system:volume-sheduler | system: kube-scheduler用户 | 允许kube-sheduler组件访问Volume资源 |
system:kube-controller-manager | system:kube-controller-manager用户 | 能够访问kube-controller-manager组件所需的资源。 |
system:node | None | 允许访问kubelet组件所需的资源,包括所有secret的读取,以及对所有Pod状态的写访问。从Kubernetes1.8版本开始,就没有自动绑定过程了。 |
system:node-proxier | system:kube-prixy用户 | 允许访问kube-proxy所需的资源 |
对其他组件角色的说明如下表所示:
默认的ClusterRole | 默认的ClusterRoleBinding | 描述 |
---|---|---|
system:auth-delegator | None | 允许对授权和认证进行托管,通常用于附加的API服务器 |
system:heapster | None | Heapster组件的角色 |
system:kube-aggregator | None | kube-aggregator角色 |
system:kube-dns | 在kube-system namespace中 kube-dns的Service Account | kube-dns的角色 |
system:kubelet-api-admin | None | 允许对kubeket API 的完全访问 |
system:node-bootstrapper | None | 允许访问kubelet TLS启动所需的资源 |
system:node-problem-detector | None | 允许访问node-problem-detector组件所需的资源 |
system:persistent-volume-provisioner | None | 允许访问多数动态卷供给所有资源 |
需要赋予的角色 |
---|
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
小结:
本节内容较多,但是很重要,希望大家可以好好看,一定要掌握哦。
更多推荐
所有评论(0)