UP | HOME

基于角色的访问控制

Table of Contents

基于角色的访问控制( Role-Based Access Control )使用 rbac.authorization.k8s.io API Group 实现 授权 决策,允许管理员通过 Kubernetes API 动态配置策略

要启用 RBAC,请使用 --authorization-mode=RBAC 启动 API Server

API

接下来将介绍 RBAC API 所定义的四种顶级类型

用户可以像使用其他 Kubernetes API 资源一样 (例如通过 kubectl、API 调用等)与这些资源进行交互

例如,命令 kubectl create -f (resource).yml 可以被用于以下所有的例子

Role 与 ClusterRole

在 RBAC API 中,一个 角色 包含了一套表示 一组权限 的规则:

  • 权限以纯粹的 累加 形式累积(没有” 否定” 的规则)
    • 角色可以由 namespace 内的 Role 对象定义
    • 整个 Kubernetes 集群 范围内有效的角色则通过 ClusterRole 对象实现

一个 Role 对象只能用于授予对某一单一命名空间中资源的访问权限

kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # 空字符串"" 表明使用 core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
以上示例描述了 _default_ 命名空间中的一个 Role 对象的定义,用于授予对 pod 的读访问权限

ClusterRole 对象可以授予与 Role 对象相同的权限,但由于它们属于集群范围对象, 用它们授予对以下几种资源的访问权限:

  • 集群范围资源

    例如节点,即 node
    
  • 非资源类型 endpoint

    例如”/healthz”
    
  • 跨所有命名空间的命名空间范围资源

    例如 pod,需要运行命令 kubectl get pods --all-namespaces 来查询集群中所有的 pod
    
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  # 鉴于 ClusterRole 是集群范围对象,所以这里不需要定义 "namespace" 字段
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]
示例中的 ClusterRole 定义可用于授予用户对某一特定命名空间,或者所有命名空间中的 secret(取决于其 绑定 方式)的读访问权限

RoleBinding 与 ClusterRoleBinding

角色绑定将一个角色中定义的各种权限授予一个或者一组用户:

  • 角色绑定包含了一组相关主体:
    • 用户 User
    • 用户组 Group
    • 服务账户 Service Account
    • 对被授予角色的引用
  • 在命名空间中可以通过 RoleBinding 对象授予权限
  • 集群范围的权限授予则通过 ClusterRoleBinding 对象完成

RoleBinding 可以引用在同一命名空间内定义的 Role 对象

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
示例中定义的 RoleBinding 对象在 ”default” 命名空间中将 ”pod-reader” 角色授予用户”jane”

这一授权将允许用户”jane” 从”default” 命名空间中读取 pod

RoleBinding 对象也可以引用一个 ClusterRole 对象

这一点允许管理员在整个集群范围内首先定义一组通用的角色,然后再在不同的命名空间中复用这些角色
# 以下角色绑定允许用户 "dave" 读取 "development" 命名空间中的 secret。
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: read-secrets
  namespace: development # 这里表明仅授权读取 "development" 命名空间中的资源。
subjects:
- kind: User
  name: dave
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io
尽管示例中的 RoleBinding 引用的是一个 ClusterRole 对象,但是用户”dave”(即角色绑定主体)还是只能读取”development” 命名空间中的 secret(即 RoleBinding 所在的命名空间)

也可以使用ClusterRoleBinding在集群级别和所有命名空间中授予权限

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
示例中所定义的ClusterRoleBinding允许在用户组”manager” 中的任何用户都可以读取集群中任何命名空间中的 secret

对资源的引用

大多数资源由代表其 名字的字符串 表示

例如”pods”,就像它们出现在相关 API endpoint 的 URL 中一样

然而,有一些 Kubernetes API 还 包含了 子资源

比如 pod 的 logs,在 Kubernetes 中 pod logs endpoint 的 URL 格式为:

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

在这种情况下,”pods” 是 命名空间资源 ,而 ”log” 是 pods 的子资源。为了在 RBAC 角色中表示出这一点,需要使用 斜线 来划分资源 与子资源。如果需要角色绑定主体读取 pods 以及 pod log,需要定义以下角色:

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

通过 resourceNames 列表,角色可以针对不同种类的请求根据资源名引用资源实例。当指定了resourceNames列表时,不同 动作 种类的请求的权限将被 限定 到资源列表中所包含的资源实例上

如使用”get”、”delete”、”update” 以及”patch” 等动词的请求
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: configmap-updater
rules:
- apiGroups: [""]
  resources: ["configmap"]
  resourceNames: ["my-configmap"]
  verbs: ["update", "get"]
如果需要限定一个角色绑定主体只能”get” 或者”update” 一个 configmap 时,可以定义上面这个角色

注意:如果设置了 resourceNames ,则请求所使用的动词 不能listwatchcreate 或者 deletecollection

由于资源名不会出现在 create、list、watch 和 deletecollection 等 API 请求的 URL 中,所以这些请求动词不会被设置了 resourceNames 的规则所允许,因为规则中的resourceNames 部分不会匹配这些请求

例子

角色定义

允许读取 core API Group 中定义的资源”pods”:

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

允许读写在”extensions” 和”apps” API Group 中定义的”deployments”:

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

允许读取一个名为”my-config” 的ConfigMap实例(需要将其通过RoleBinding绑定从而限制针对某一个命名空间中定义的一个ConfigMap实例的访问):

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

允许读取 core API Group 中的”nodes” 资源(由于Node是集群级别资源,所以此ClusterRole定义需要与一个ClusterRoleBinding绑定才能有效):

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

允许对非资源 endpoint “/healthz” 及其所有子路径的”GET” 和”POST” 请求(此ClusterRole定义需要与一个ClusterRoleBinding绑定才能有效):

rules:
- nonResourceURLs: ["/healthz", "/healthz/*"] # 在非资源 URL 中,'*' 代表后缀通配符
  verbs: ["get", "post"]

角色绑定

角色绑定主体 Subject 可以是用户组 Group_、用户 _User 或者服务账户 Service Accounts

  • 用户:字符串表示

    可以是纯粹的用户名,例如”alice”、电子邮件风格的名字,如 “bob@example.com” 或者是用字符串表示的数字 id
    
    由 Kubernetes 管理员配置 认证模块 以产生所需格式的用户名,对于用户名,RBAC 授权系统不要求任何特定的格式
    
    然而,前缀 system: 是 为 Kubernetes 系统使用而保留的,所以管理员应该确保用户名不会意外地包含这个前缀
    
  • 用户组:信息由授权模块提供

    用户组与用户一样由字符串表示。Kubernetes 对用户组 字符串没有格式要求,但前缀 system: 同样是被系统保留的
    
  • 服务账户

    拥有包含 system:serviceaccount: 前缀的用户名,并属于拥有 system:serviceaccounts: 前缀的用户组 
    

一个名为”alice@example.com” 的用户:

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

一个名为”frontend-admins” 的用户组:

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

kube-system 命名空间中的默认服务账户:

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

名为”qa” 命名空间中的所有服务账户:

subjects:
- kind: Group
  name: system:serviceaccounts:qa
  apiGroup: rbac.authorization.k8s.io
​```在集群中的所有服务账户:

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

所有认证过的用户:

subjects:
- kind: Group
  name: system:authenticated
  apiGroup: rbac.authorization.k8s.io
​```所有未认证的用户(version 1.5+):

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

所有用户:

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

默认角色与默认角色绑定

API Server 会创建一组默认的 ClusterRole 和 ClusterRoleBinding 对象。 这些默认对象中有许多包含 system: 前缀,表明这些资源由 Kubernetes 基础组件拥有

对这些资源的修改可能导致集群无法工作(non-functional cluster)

一个例子是 system:node ClusterRole 对象,这个角色定义了 kubelets 的权限。如果这个角色被修改,可能会导致 kubelets 无法正常工作

所有默认的 ClusterRole 和 ClusterRoleBinding 对象都会被标记为 kubernetes.io/bootstrapping=rbac-defaults

自动更新

每次启动时,API Server 都会更新默认 ClusterRole 所缺乏的各种权限,并更新默认 ClusterRoleBinding 所缺乏的各个角色绑定主体

这种自动更新机制允许集群修复一些意外的修改,由于权限和角色绑定主体在新的 Kubernetes 释出版本中可能变化,这也能够保证角色和角色 绑定始终保持是最新的

如果需要禁用自动更新,请将默认 ClusterRole 以及 ClusterRoleBinding 的 rbac.authorization.kubernetes.io/autoupdate 设置成为 false

注意,缺乏默认权限和角色绑定主体可能会导致非功能性集群问题

发现类角色

Table 1: 发现类角色
默认 ClusterRole 默认 ClusterRoleBinding 描述
system:basic-user system:authenticated and system:unauthenticatedgroups 允许用户只读访问有关自己的基本信息
system:discovery system:authenticated and system:unauthenticatedgroups 允许只读访问 API discovery endpoints, 用于在 API 级别进行发现和协商

面向用户的角色

一些默认角色并不包含 system: 前缀,它们是面向用户的角色。 这些角色包含 超级用户 角色(cluster-admin),即旨在利用 ClusterRoleBinding(cluster-status)在集群范围内授权的角色, 以及那些使用 RoleBinding(admin、edit 和 view)在特定命名空间中授权的角色

Table 2: 面向用户的角色
默认 ClusterRole 默认 ClusterRoleBinding 描述
cluster-admin system:masters group 超级用户权限,允许对任何资源执行任何操作。 在 ClusterRoleBinding 中使用时,可以完全控制集群和所有命名空间中的所有资源。 在 RoleBinding 中使用时,可以完全控制 RoleBinding 所在命名空间中的所有资源,包括命名空间自己
admin None 管理员权限,利用 RoleBinding 在某一命名空间内部授予。 在 RoleBinding 中使用时,允许针对命名空间内大部分资源的读写访问, 包括在命名空间内创建角色与角色绑定的能力。 但不允许对资源配额(resource quota)或者命名空间本身的写访问
edit None 允许对某一个命名空间内大部分对象的读写访问,但不允许查看或者修改角色或者角色绑定
view None 允许对某一个命名空间内大部分对象的只读访问。 不允许查看角色或者角色绑定。 由于可扩散性等原因,不允许查看 secret 资源

核心组件角色

Table 3: 核心组件角色
默认 ClusterRole 默认 ClusterRoleBinding 描述
system:kube-scheduler system:kube-scheduler user 允许访问 kube-scheduler 组件所需要的资源
system:kube-controller-manager system:kube-controller-manager user 允许访问 kube-controller-manager 组件所需要的资源
system:node system:nodes group (deprecated in 1.7) 允许对 kubelet 组件所需要的资源的访问,包括读取所有 secret 和对所有 pod 的写访问
system:node-proxier system:kube-proxy user 允许对 kube-proxy 组件所需要资源的访问

其它组件角色

Table 4: 其他组件角色
默认 ClusterRole 默认 ClusterRoleBinding 描述
system:auth-delegator None 允许委托认证和授权检查。 通常由附加 API Server 用于统一认证和授权
system:heapster None Heapster 组件的角色
system:kube-aggregator None kube-aggregator 组件的角色
system:kube-dns kube-dns service account in the kube-systemnamespace kube-dns 组件的角色
system:node-bootstrapper None 允许对执行 Kubelet TLS 引导(Kubelet TLS bootstrapping) 所需要资源的访问
system:node-problem-detector None node-problem-detector 组件的角色
system:persistent-volume-provisioner None 允许对大部分动态存储卷创建组件(dynamic volume provisioner)所需要资源的访问

控制器角色

Kubernetes controller manager 负责运行核心控制循环:

  • 当使用 –use-service-account-credentials 选项运行 controller manager 时,每个 控制循环 都将使用 单独的服务账户 启动。 而每个控制循环都存在对应的 角色 ,前缀名为 system:controller:
  • 如果不使用 –use-service-account-credentials 选项时,controller manager 将会使用 自己的凭证 运行所有控制循环,而这些凭证必须被 授予 相关的角色

这些控制器角色包括:

  • system:controller:attachdetach-controller
  • system:controller:certificate-controller
  • system:controller:cronjob-controller
  • system:controller:daemon-set-controller
  • system:controller:deployment-controller
  • system:controller:disruption-controller
  • system:controller:endpoint-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-binder
  • system:controller:pod-garbage-collector
  • system:controller:replicaset-controller
  • system:controller:replication-controller
  • system:controller:resourcequota-controller
  • system:controller:route-controller
  • system:controller:service-account-controller
  • system:controller:service-controller
  • system:controller:statefulset-controller
  • system:controller:ttl-controller

初始化与预防权限升级

RBAC API 会 阻止 用户通过 编辑角色 或者 角色绑定升级权限

由于这一点是在 API 级别实现的,所以在 RBAC 授权器(RBAC authorizer)未启用的状态下依然可以正常工作

用户只有在 拥有角色 所包含的 所有权限的条件 下才能创建/更新一个 角色 ,这些操作还必须在 角色所处的相同范围 内进行

对于 ClusterRole 来说是集群范围,对于 Role 来说是在与角色相同的命名空间或者集群范围

例如,如果用户”user-1” 没有权限读取集群范围内的 secret 列表,那么他也不能创建包含这种权限的 ClusterRole

为了能够让用户创建/更新角色,需要:

  1. 授予用户一个角色以允许他们根据需要创建/更新 Role 或者 ClusterRole 对象
  2. 授予用户一个角色包含他们在 Role 或者 ClusterRole 中所能够设置的所有权限
    • 如果用户尝试创建或者修改 Role 或者 ClusterRole 以设置那些他们未被授权的权限时,这些 API 请求将被禁止

用户只有在拥有 所引用的角色 中包含的 所有权限 时才可以创建/更新 角色绑定 ,这些操作也必须在角色绑定所处的相同范围内进行 或者 用户被明确授权可以在所引用的角色上执行绑定操作

例如,如果用户”user-1” 没有权限读取集群范围内的 secret 列表,那么他将不能创建 ClusterRole 来引用那些授予了此项权限的角色

为了能够让用户创建/更新角色绑定,需要:

  1. 授予用户一个角色以允许他们根据需要创建/更新 RoleBinding 或者 ClusterRoleBinding 对象
  2. 授予用户绑定某一特定角色所需要的权限:
    • 隐式地,通过授予用户所有所引用的角色中所包含的权限
    • 显式地,通过授予用户在特定 Role(或者 ClusterRole)对象上执行 bind 操作的权限
apiVersion: rbac.authorization.k8s.io/v1beta1
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"]
  resourceNames: ["admin","edit","view"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
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

当初始化第一个角色和角色绑定时,初始用户需要能够授予他们尚未拥有的权限。 初始化初始角色和角色绑定时需要:

  • 使用包含 system:masters 用户组的 凭证 ,该用户组通过默认绑定绑定到 cluster-admin 超级用户 角色
  • 如果 API Server 在运行时启用了非安全端口 –insecure-port ,也可以通过这个没有施行认证或者授权的端口发送角色或者角色绑定请求

命令行工具

有两个 kubectl 命令可以用于在命名空间内或者整个集群内授予角色

在某一特定命名空间内授予 Role 或者 ClusterRole

kubectl create rolebinding

示例如下:

  • 在名为”acme” 的命名空间中将 admin ClusterRole 授予用户”bob”:

    $ kubectl create rolebinding bob-admin-binding --clusterrole=admin --user=bob --namespace=acme
    
  • 在名为”acme” 的命名空间中将 view ClusterRole 授予服务账户”myapp”:

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

在整个集群中授予 ClusterRole,包括所有命名空间:

$ kubectl create clusterrolebinding

示例如下:

  • 在整个集群范围内将 cluster-admin ClusterRole 授予用户”root”:

    $ kubectl create clusterrolebinding root-cluster-admin-binding --clusterrole=cluster-admin --user=root
    
  • 在整个集群范围内将 system:node ClusterRole 授予用户”kubelet”:

    $ kubectl create clusterrolebinding kubelet-node-binding --clusterrole=system:node --user=kubelet
    
  • 在整个集群范围内将 view ClusterRole 授予命名空间”acme” 内的服务账户”myapp”:

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

服务账户权限

默认的 RBAC 策略将授予控制平面组件 control-plane component 、节点 node 和控制器 controller一组范围受限的权限

但对于 ”kube-system” 命名空间以外的服务账户,则 不授予任何权限 (超出授予所有认证用户的发现权限)

这一点允许根据需要向 特定服务账号 授予 特定权限

细粒度的角色绑定将提供更好的安全性,但需要更多精力管理

更粗粒度的授权可能授予服务账号不需要的 API 访问权限(甚至导致潜在授权扩散),但更易于管理

从最安全到最不安全可以排序以下方法

对某一特定应用程序的服务账户授予角色(最佳实践)

要求应用程序在其 pod spec 中指定 serviceAccountName 字段,并且要创建相应服务账户

例如,在”my-namespace” 命名空间中授予服务账户”my-sa” 只读权限
$ kubectl create rolebinding my-sa-view \
  --clusterrole=view \
  --serviceaccount=my-namespace:my-sa \
  --namespace=my-namespace

在某一命名空间中授予 default 服务账号一个角色

如果一个应用程序没有在其 pod 规范中指定 serviceAccountName,它将默认使用 default 服务账号

注意:授予 default 服务账号的权限将可用于命名空间内任何没有指定 serviceAccountName 的 pod 

下面的例子将在”my-namespace” 命名空间内授予 ”default” 服务账号只读权限
kubectl create rolebinding default-view \
  --clusterrole=view \
  --serviceaccount=my-namespace:default \
  --namespace=my-namespace

目前 许多 加载项(addon) 作为 kube-system 命名空间中的 default 服务帐户运行。 要允许这些加载项使用超级用户访问权限,请将 cluster-admin 权限授予 kube-system 命名空间中的 default 服务帐户

$ kubectl create clusterrolebinding add-on-cluster-admin \
  --clusterrole=cluster-admin \
  --serviceaccount=kube-system:default 
注意:启用上述操作意味着 ”kube-system” 命名空间将包含允许超级用户访问 API 的秘钥

为命名空间中所有的服务账号授予角色

如果希望命名空间内的所有应用程序都拥有同一个角色,无论它们使用什么服务账户,可以为该命名空间的服务账户用户组授予角色

下面的例子将授予 ”my-namespace” 命名空间中的所有服务账户只读权限
$ kubectl create rolebinding serviceaccounts-view \
  --clusterrole=view \
  --group=system:serviceaccounts:my-namespace \
  --namespace=my-namespace

对集群范围内的所有服务账户授予一个受限角色(不鼓励)

如果不想管理每个命名空间的权限,则可以将集群范围角色授予所有服务帐户

下面的例子将所有命名空间中的只读权限授予集群中的所有服务账户
$ kubectl create clusterrolebinding serviceaccounts-view \
  --clusterrole=view \
  --group=system:serviceaccounts

授予超级用户访问权限给集群范围内的所有服务帐户(强烈不鼓励)

如果根本不关心权限分块,可以对所有服务账户授予超级用户访问权限。

$ kubectl create clusterrolebinding serviceaccounts-cluster-admin \
  --clusterrole=cluster-admin \
  --group=system:serviceaccounts
警告:这种做法将允许任何具有读取权限的用户访问 secret 或者通过创建一个容器的方式来访问超级用户的凭据
Next:网络策略 Previous: Service Account Home:安全