k8s之RBAC权限控制

RBAC(Role-Based Access Control)是一种特定的权限管理模型,它把可以施加在“资源对象”上的“动作”称为“许可权限”,这些许可权限能够按需组合在一起构建出“角色”及其职能,并通过为“用户账户或组账户”分配一到多个角色完成权限委派。这些能够发出动作的用户在RBAC中也称为“主体”。如下展现了用户、角色、权限之间的关系,如图:

基于角色(Role)的访问控制(RBAC)是一种基于组织中用户的角色来调节控制对 计算机或网络资源的访问的方法。

RBAC 鉴权机制使用 rbac.authorization.k8s.io API 组 来驱动鉴权决定,允许你通过 Kubernetes API 动态配置策略。

要启用 RBAC,在启动 API 服务器 时将 --authorization-mode 参数设置为一个逗号分隔的列表并确保其中包含 RBAC,二进制部署以及kubeadm部署中已开启RBAC权限机制

RBAC API 声明了四种 Kubernetes 对象:RoleClusterRoleRoleBinding 和 ClusterRoleBinding。你可以像使用其他 Kubernetes 对象一样, 通过类似 kubectl 这类工具 描述对象, 或修补对象。

一、Role:

Role 总是用来在某个命名空间内设置访问权限;在你创建 Role 时,你必须指定该 Role 所属的名字空间,可以理解为role就是针对namespace的权限管控

例如:查询名称空间kube-system中的role角色,如图:

以第一个为例,查看它的yaml文件内容如下:

1、上图中Role表示资源名称类型

2、apiGroups表示api资源组,通过命令kubectl get apiservice可以看到所有的资源组,如图:

3、resources表示k8s资源名称,执行命令kubectl api-resources 可以查看所有的资源名称,如图:

  • 第一列是资源名称,就是可以写在这里的
  • 第二列是简写,kubectl get 后面的可以简写
  • 第三列是APIGROUP组
  • 第四列是是否属于NAMESPACED资源,就是你可以在ns下面看到的资源
  • 第五列是kind的时候写的名称

4、verbs表示权限,get是查看权限、update是更新权限、patch、watch、proxy、redirect、delete、deletecollection

语法规则如下:

#可使用命令kubectl create role -h  查看具体的语法规则
Usage:
  kubectl create role NAME --verb=verb --resource=resource.group/subresource [--resource-name=resourcename]
[--dry-run=server|client|none] [options]

创建角色:

1、执行命令在默认名称空间default中创建角色gongguan,并且此角色对命名空间default中的pod具有查看和进入pod的权限

kubectl create role gongguan --verb=get,watch,list,create --resource=pods,pods/exec

注意:如果要指定命名空间,需要使用-n + namespace,不同的namespace中的role被认为是不同的角色

查看角色gongguan的权限以及资源,如图:

2、通过yaml文件形式创建role,此role位于默认命名空间,对services具有读访问权限,文件内容如下:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" 标明 core API 组
  resources: ["services"]
  verbs: ["get", "watch", "list"]

verbs常用权限组合:

读取权限:["get", "list", "watch"]
读/写权限:["get", "list", "watch", "create", "update", "patch", "delete"]

二、ClusterRole:

ClusterRole 可以和 Role 相同完成授权。 因为 ClusterRole 属于集群范围,所以它也可以为以下资源授予访问权限:

  • 集群范围资源(比如 节点(Node)
  • 非资源端点(比如 /healthz
  • 跨名字空间访问的名字空间作用域的资源(如 Pods)

ClusterRole 就是用来在集群内设置访问权限。ClusterRole不用固定在一个namespaces

这两种资源的名字不同(Role 和 ClusterRole)是因为 Kubernetes 对象要么是namespaces作用域的,要么是集群作用域的, 不可两者兼具。

语法规则如下:

#可使用命令kubectl create clusterrole -h  查看具体的语法规则

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

1、下面是一个 ClusterRole 的示例,可用来为任一特定名字空间中的 Secret 授予读访问权限, 或者跨名字空间的访问权限(取决于该角色是如何绑定的):

#创建clusterrole,名称为secret-reader,对资源secrets具有读取的权限

kubectl create clusterrole secret-reader --verb=get,watch,list --resource=secrets

2、创建集群角色get-pod,并可以访问任意命名空间中的pod信息,执行命令如下:

kubectl create clusterrole get-pod --verb=get,watch,list --resource=pods

3、下面是通过yaml文件创建clusterrole,表示对secrets授予读访问权限,如下:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # "namespace" 被忽略,因为 ClusterRoles 不受名字空间限制
  name: secret-reader
rules:
- apiGroups: [""]
  # 在 HTTP 层面,用来访问 Secret 资源的名称为 "secrets"
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

注:clusterrole生效访问是命名空间级别还是集群级别取决于rolebinding还是clusterrolebinding

三、RoleBinding

角色绑定(Role Binding)是将角色中定义的权限赋予一个或者一组用户。 它包含若干主体(用户、组或服务账户)的列表和对这些主体所获得的角色的引用。 RoleBinding 在指定的名字空间中执行授权

一个 RoleBinding 可以引用同一个名字空间中的任何 Role。 或者,一个 RoleBinding 可以引用某 ClusterRole 并将该 ClusterRole 绑定到 RoleBinding 所在的名字空间。 如果你希望将某 ClusterRole 绑定到集群中所有名字空间,你要使用 ClusterRoleBinding

语法如下:

#可执行命令kubectl create rolebinding -h  查看语法规则

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

rolebinding引用role

下面的例子rolebinding中将角色role名称gongguan授予在默认命名空间default中的用户gong,这样gong就可以访问default命名空间中的Pod信息,如下:

#将role绑定到用户gong,此用户只能作用于当前rolebinging所在的命令空间
kubectl create rolebinding gongguan-rolebinding --role=gongguan --user=gong
#将role绑定到default空间下的serviceaccunt-nginx上
kubectl create rolebinding gongguan-rolebinding --role=gongguan --serviceaccount=default:serviceaccount-nginx -n default
  • gongguan-rolebinding:创建的rolebinding名称,可自定义
  • –role=gongguan:指定角色名称,在第一步中已经创建并赋予权限
  • –user=gong:指定默认命名空间中的用户

上述可以简单理解为:将默认namespace中的用户gong绑定到默认namespace中的角色gongguan上,这样此用户就具备了角色gongguan所具有的权限了

查看gongguan-rolebinding的内容如下:

关于如何k8s用户管理可参考文章:k8s用户和用户组

验证:现在切换到default命名空间的gong用户下,执行查看pod命令,如图:

从上图中可以看出,用户gong只具备对default名称空间的pod访问权限,kube-system中的Pod无权限查看

rolebinding引用clusterrole

下面例子表示将clusterrole名称为secret-reader授予rolebinding所在的默认命名空间中的用户gong

kubectl create rolebinding guan-rolebinding --clusterrole=secret-reader --user=gong
  • guan-rolebinding:创建角色绑定名称
  • –clusterrole=secret-reader:集群角色为secret-reader(在上面的步骤中创建)
  • –user=gong:指定用户为gong

上面的命令可以简单理解为:将用户gong与集群角色secret-reader进行绑定,那么用户gong将具备此集群角色secret-reader的权限,前提是在当前的guan-rolebinding所在命名空间中,因为rolebinding的作用域在命名空间中

guan-rolebinding的yaml文件内容如下:

验证:现在切换到用户gong下操作集群:

kubectl config use-context gong@kubernetes
kubectl get secrets

因为clusterrole名称secret-reader具有secrets的访问权限,因此用户gong也可以访问

通过用户gong访问其他资源将会提示没有权限列出资源,如图:

注:rolebinding可以引用role和clusterrole

四、ClusterRoleBinding 示例:

要跨整个集群完成访问权限的授予,你可以使用一个 ClusterRoleBinding,语法如下:

#可使用命令kubectl create clusterolebinding -h  查看语法:

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

1、下面的 ClusterRoleBinding 允许 “GUAN” 组内的所有用户访问任何名字空间中的 pod,执行命令如下:

kubectl create clusterrolebinding fullpod --clusterrole=get-pod --group=GUAN

注意:组名是区分大小写的,大写和小写表示两个不同的组

查看集群角色绑定fullpod的yaml文件内容如下:

验证: 现在切换到用户gong下操作集群(用户gong在组GUAN中):

从上图可以看出,切换到用户gong后,无论是默认的命名空间还是kube-system等命名空间中的pod都可以查看

注意:创建了绑定之后,你不能再修改绑定对象所引用的 Role 或 ClusterRole。 试图改变绑定对象的 roleRef 将导致合法性检查错误。 如果你想要改变现有绑定对象中 roleRef 字段的内容,必须删除重新创建绑定对象。这种限制主要有两个原因:

  • 针对不同角色的绑定是完全不一样的绑定。要求通过删除/重建绑定来更改 roleRef, 这样可以确保要赋予绑定的所有主体会被授予新的角色(而不是在允许或者不小心修改 了 roleRef 的情况下导致所有现有主体未经验证即被授予新角色对应的权限)
  • 将 roleRef 设置为不可以改变,这使得可以为用户授予对现有绑定对象的 update 权限, 这样可以让他们管理主体列表,同时不能更改被授予这些主体的角色

注:clusterrolebinding只能引用clusterrole,不能引用role

总结:

  • role:创建角色并设置相应权限,作用域为namespace
  • clusterrole:创建集群角色并设置相应权限,作用域为集群
  • rolebinding:将role和rolebinding所在的命名空间中的用户进行绑定,也可绑定clusterrole,此时clusterrole只能作用在当前的rolebinding所在namespace
  • clusterrolebinding:将clusterrole和用户或者用户组进行绑定,不限制namespace

附加:

五、资源引用:

在 Kubernetes API 中,大多数资源都是使用对象名称的字符串表示来呈现与访问的。 例如,上文中设置clusterrole对于 Pod的权限使用 “pods”。 RBAC 使用对应 API 端点的 URL 中呈现的名字来引用资源。 有一些 Kubernetes API 涉及 子资源(subresource),例如 Pod 的日志、或进入pod内部命令exec,其中,pods 对应名字空间作用域的 Pod 资源,而 log或者exec 是 pods 的子资源。 在 RBAC 角色表达子资源时,使用斜线(/)来分隔资源和子资源。 要允许某主体读取 pods 同时访问这些 Pod 的 子资源,可以这么写:

#表示创建一个角色gongguan,并且在命名空间default中具有查看pod并进入pod内部的权限
kubectl create role gongguan --verb=get,watch,list,create --resource=pods,pods/exec

也可以通过yaml文件形式来编写,如图:

上图中可以pods表示资源名称,pods/exec表示子资源,执行rolebinding后,用户即可查看pod同时进入pod内部

六、主体引用:

RoleBinding 或者 ClusterRoleBinding 可绑定角色到某 *主体(Subject)*上。 主体可以是组,用户或者 服务账户

Kubernetes 用字符串来表示用户名。 用户名可以是普通的用户名,像 “gong”;或者是邮件风格的名称,如 “gong@example.com”, 或者是以字符串形式表达的数字 ID。 

注意:前缀 system: 是 Kubernetes 系统保留的,所以你要确保 所配置的用户名或者组名不能出现上述 system: 前缀。 除了对前缀的限制之外,RBAC 鉴权系统不对用户名格式作任何要求。

服务账户 的用户名前缀为 system:serviceaccount:,属于前缀为 system:serviceaccounts: 的用户组

  • system:serviceaccount: (单数)是用于服务账户用户名的前缀;
  • system:serviceaccounts: (复数)是用于服务账户组名的前缀

API 服务器创建一组默认的 ClusterRole 和 ClusterRoleBinding 对象。 这其中许多是以 system: 为前缀的,用以标识对应资源是直接由集群控制面管理的。 所有的默认 ClusterRole 和 ClusterRoleBinding 都有 kubernetes.io/bootstrapping=rbac-defaults 标签。

注意:在修改名称包含 system: 前缀的 ClusterRole 和 ClusterRoleBinding 时要格外小心。 对这些资源的更改可能导致集群无法继续工作。

自动协商机制:

在每次启动时,API 服务器都会更新默认 ClusterRole 以添加缺失的各种权限,并更新 默认的 ClusterRoleBinding 以增加缺失的各类主体。 这种自动协商机制允许集群去修复一些不小心发生的修改,并且有助于保证角色和角色绑定 在新的发行版本中有权限或主体变更时仍然保持最新。

如果要禁止此功能,请将默认 ClusterRole 以及 ClusterRoleBinding 的 rbac.authorization.kubernetes.io/autoupdate 注解设置成 false。 注意,缺少默认权限和角色绑定主体可能会导致集群无法正常工作,默认情况下为true,如下表示随机查看一个clusterrole的内容,如图:

如果基于 RBAC 的鉴权机制被启用,则自动协商功能默认是被启用的,默认就是true

七、常用命令举例:

1、kubectl create role

创建名称为 “gongguan” 的 Role 对象,允许用户对 Pods 执行 getwatch 和 list 操作

kubectl create role gongguan --verb=get,list,watch --resource=pods

创建名称为 “gongguan” 的 Role 对象并指定 resourceNames

kubectl create role gongguan --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod

注意:你不能使用资源名字来限制 create 或者 deletecollection 请求。 对于 create 请求而言,这是因为在鉴权时可能还不知道新对象的名字。 如果你使用 resourceName 来限制 list 或者 watch 请求, 客户端必须在它们的 list 或者 watch 请求里包含一个与指定的 resourceName 匹配的 metadata.name 字段选择器。 例如,kubectl get configmaps --field-selector=metadata.name=my-configmap

创建名为 “foo” 的 Role 对象并指定 apiGroups

kubectl create role foo --verb=get,list,watch --resource=replicasets.apps

创建名为 “foo” 的 Role 对象并指定子资源权限:

kubectl create role foo --verb=get,list,watch --resource=pods,pods/status,pods/exec

创建名为 “my-component-lease-holder” 的 Role 对象,使其具有对特定名称的 资源执行get/update 的权限:

kubectl create role my-component-lease-holder --verb=get,list,watch,update --resource=lease --resource-name=my-component

2、kubectl create clusterrole

创建名称为 “pod-reader” 的 ClusterRole对象,允许用户对 Pods 对象执行get、watchlist 操作:

kubectl create clusterrole pod-reader --verb=get,list,watch --resource=pods

创建名为 “pod-reader” 的 ClusterRole 对象并指定 resourceNames

kubectl create clusterrole pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod

创建名为 “foo” 的 ClusterRole 对象并指定 apiGroups

kubectl create clusterrole foo --verb=get,list,watch --resource=replicasets.apps

创建名为 “foo” 的 ClusterRole 对象并指定子资源:

kubectl create clusterrole foo --verb=get,list,watch --resource=pods,pods/status

创建名为 “foo” 的 ClusterRole 对象并指定 nonResourceURL

kubectl create clusterrole "foo" --verb=get --non-resource-url=/logs/*

创建名为 “monitoring” 的 ClusterRole 对象并指定 aggregationRule

kubectl create clusterrole monitoring --aggregation-rule="rbac.example.com/aggregate-to-monitoring=true"

八、限制多个不同用户访问不同namespace的访问权限

情况:比如有不同的人员需要访问k8s集群,但是不可能给每个人管理员权限,那么只能根据不同的角色或项目设置不同的权限,从而达到权限管控,具体操作方法如下:

说先查看当前default命名空间下的pod信息,如图:

需求:配置新用户guan,只能查看和列出default下的pod信息

1、在default命名空间中定义role,对default下的pod具有查看权限,如图:

2、在default命名空间下创建serviceaccount,执行命令如下:

kubectl create serviceaccount serviceaccount-nginx

3、将角色role与serviceaccount进行绑定,执行命令如下:

kubectl create rolebinding nginx-account --role=pod-reader --serviceaccount=default:serviceaccount-nginx -n default

4、获取serviceaccout-nginx中的token名字,属于secrets资源,如图:

5、查看token和ca.crt的信息,命令如下:

kubectl get secrets serviceaccount-nginx-token-w7ncm -o yaml

其中的token是经过base64处理的,因此需要进行解码,执行命令如下:

echo $token | base64 -d

6、编辑文件$HOME/.kube/config,添加内容如下:

[root@k8s01 ~]# vim config

apiVersion: v1
kind: Config
clusters:
- cluster:                              #多个集群就要写多个cluster
    server: K8S集群地址
    certificate-authority-data: "ca.crt后的内容"
  name: kubernetes-cluster
users:
- name: "guan"                          #多个用户就写多个
  user:
    token: "解码后的token字符串"
contexts:
- context:                               #多个上下文就写多个
    cluster: kubernetes-cluster
    user: "guan"
  name: kubernetes-context
preferences: {}
current-context: kubernetes-context

clusters记录了一个或多个集群信息,包含以下几个字段:

  • server:集群地址
  • certificate-authority-data:连接k8s集群证书
  • name:集群名称代号,可自定义

users记录了访问k8s集群的账号信息,包含一下几个字段:

  • name:用户账号的名称代号,此处可自定义
  • user/token:用户采用token的方式认证

contexts是上下文信息,包含k8s集群和访问集群的用户信息:

  • name:上下文的名称代号
  • cluster:k8s集群名称代号,需要与上方的cluster中的name保持一致
  • user:访问k8s集群的用户名称代号,需要与users中的name保持一致

current-context:指定当前kubectl使用的上下文信息,需要与上面的contexts中的name保持一致

7、最后通过命令查看pod和service,如图:

从上图看出,pod可以查看但是service不可以,因为我们没有授权

标签