一、简介
之前,Kubernetes中的授权策略主要是ABAC(Attribute-Based Access Control)。对于ABAC,Kubernetes在实现上是比较难用的,而且需要Master Node的SSH和根文件系统访问权限,授权策略发生变化后还需要重启API Server。
Kubernetes 1.6中,RBAC(Role-Based Access Control)基于角色的访问控制进入Beta阶段。RBAC访问控制策略可以使用kubectl或Kubernetes API进行配置。使用RBAC可以直接授权给用户,让用户拥有授权管理的权限,这样就不再需要直接触碰Master Node。在Kubernetes中RBAC被映射成API资源和操作。
二、RBAC API的资源对象
在Kubernetes 1.6中通过启动参数--authorization-mode=RBAC.API Overview
为API Server启用RBAC。
使用kubeadm初始化的1.6版本的Kubernetes集群,已经默认为API Server开启了RBAC,可以查看Master Node上API Server的静态Pod定义文件,如果- apiserver底下没有看到
如果没有下面红色的信息,说明没有启用RBAC
- apiserver
- --bind-address=0.0.0.0
- --secure-port=443
- --insecure-bind-address=0.0.0.0
- --insecure-port=8080
- --allow-privileged=true
- --service-cluster-ip-range=10.3.0.0/24
- --advertise-address=172.16.71.200
- --cors-allowed-origins=.*
- --admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota
- --tls-cert-file=/etc/kubernetes/ssl/apiserver.pem
- --tls-private-key-file=/etc/kubernetes/ssl/apiserver-key.pem
- --client-ca-file=/etc/kubernetes/ssl/ca.pem
- --service-account-key-file=/etc/kubernetes/ssl/apiserver-key.pem
- --v=3
- --etcd-servers=http://172.16.71.200:2379,http://172.16.71.201:2379,http://172.16.71.202:2379,http://172.16.71.203:2379
- --authorization-mode=RBAC
RBAC API定义了四个资源对象用于描述RBAC中用户和资源之间的连接权限:
- Role
- ClusterRole
- RoleBinding
- ClusterRoleBinding
1、Role和ClusterRole
在RBAC API中,Role包含表示一组权限的规则。 权限是纯粹的加法(没有“否定”规则)。 一个Role可以在一个namespace中用一个角色来定义,也可以使用ClusterRole在群集范围内定义。
Role只能用于授予对单个namespace中资源的访问权限。 以下是“default”命名空间中可用于授予对pod的读访问权限的示例:
kind: Role apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: namespace: default name: pod-reader rules: - apiGroups: [""] # "" indicates the core API group resources: ["pods"] verbs: ["get", "watch", "list"]
ClusterRole可用于授予与Role相同的权限,但由于它们是集群范围的,因此也可以使用它们来授予对以下内容的访问权限:
- 集群范围的资源(如nodes)
- 非资源端点(如“/ healthz”)
- 在所有namespace中的资源(如pod)(例如:kubectl get pods --all-namespaces)
以下ClusterRole可用于授予对任何特定namespace或所有namespace中的secrets 的读取访问(取决于其绑定方式):
kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: # "namespace" omitted since ClusterRoles are not namespaced name: secret-reader rules: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "watch", "list"]
2、RoleBinding和ClusterRoleBinding
RoleBinding把Role绑定到账户主体Subject(users, groups, or service accounts),让Subject继承Role所在namespace下的权限。ClusterRoleBinding把ClusterRole绑定到Subject,让Subject集成ClusterRole在整个集群中的权限。
以下RoleBinding将“pod-reader”角色授予“默认”命名空间中的用户“hzb”。 这允许“hzb”在“默认”命名空间中读取pod。
# This role binding allows "jane" to read pods in the "default" namespace. kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: read-pods namespace: default subjects: - kind: User name: hzb apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io
RoleBinding还可以引用ClusterRole来授予RoleBinding命名空间中ClusterRole中定义的命名空间资源的权限。 这允许管理员为整个集群定义一组通用角色,然后在多个命名空间中重用它们。也就是说,ClusterRole一旦被RoleBinding到某一个namespace中,它只能访问该namesapce中的资源。
例如,即使以下RoleBinding引用了ClusterRole,“hzb”只能在“development”这个namespace(RoleBinding的命名空间)中读取secrets 。
# This role binding allows "dave" to read secrets in the "development" namespace. kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: read-secrets namespace: development # This only grants permissions within the "development" namespace. subjects: - kind: User name: hzb apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: secret-reader apiGroup: rbac.authorization.k8s.io
ClusterRoleBinding可以用于在集群级别和所有namespace中授予权限。 以下ClusterRoleBinding允许组“manager”中的任何用户在任何namespace中读取secrets 。
kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 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
3、子资源权限
大多数资源由其名称的字符串表示形式表示,例如“pod”,就像它出现在相关API端点的URL中一样。 然而,一些Kubernetes API涉及“子资源”,例如pod的日志。 pod的日志端点的URL是:
GET /api/v1/namespaces/{namespace}/pods/{name}/log
在这种情况下,“pod”是namespace资源,“log”是pod的子资源。 要在RBAC角色中表示此角色,请使用/来划分资源和子资源。 要允许主题读取pod和pod日志,请写:
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"]
4、资源名称引用
Role权限的资源也可以是某一定义好的资源的名称引用,需要在resourceNames中指定名称。 比如限制一个主题只能“获取”和“更新”一个configmap(这个configmap是用户自己定义的一个资源名称),您可以写:
kind: Role apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: namespace: default name: configmap-updater rules: - apiGroups: [""] resources: ["configmap"] resourceNames: ["my-configmap"] verbs: ["update", "get"]
值得注意的是,如果设置了resourceName,那么以上的verbs不能是list,watch,create或deletecollection。
5、Role举例
以下示例中仅显示了规则部分。
允许读取核心API组中的资源“pod”:
rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "watch"]
允许在“extensions”和“apps”API组中读/写“deployments”:
rules: - apiGroups: ["extensions", "apps"] resources: ["deployments"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
允许读“pod”和阅读/写“jobs”:
rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "watch"] - apiGroups: ["batch", "extensions"] resources: ["jobs"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
允许读取名为“my-config”的ConfigMap(必须使用RoleBinding绑定才能限制在单个namespace中的单个ConfigMap):
rules: - apiGroups: [""] resources: ["configmaps"] resourceNames: ["my-config"] verbs: ["get"]
允许读取核心组中的资源“nodes”(因为nodes是集群范围的,必须是ClusterRole用ClusterRoleBinding绑定才有效):
rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get", "list", "watch"]
允许“GET”和“POST”请求到非资源端点“/ healthz”和所有子路径(必须是ClusterRole用ClusterRoleBinding绑定才有效):
rules: - nonResourceURLs: ["/healthz", "/healthz/*"] # '*' in a nonResourceURL is a suffix glob match verbs: ["get", "post"]
6、给Subjects授权
RoleBinding或ClusterRoleBinding将角色绑定到subjects。 subjects可以是 groups, users or service accounts。
Subjects 中 Users 使用字符串表示,它可以是一个普通的名字字符串,如 “alice”;也可以是 email 格式的邮箱地址,如 “[email protected]”;甚至是一组字符串形式的数字 ID。Users 的格式必须满足集群管理员配置的 验证模块 ,RBAC 授权系统中没有对其做任何格式限定; 但是 Users 的前缀 system:
是系统保留的,集群管理员应该确保普通用户不会使用这个前缀格式
Kubernetes中的groups目前由Authenticator模块提供。 groups表示为字符串,该字符串没有格式要求,除了前缀system:被保留。
service accounts具有前缀为system:serviceaccount:用户名,属于前缀为system:serviceaccount:的组
RoleBinding举例:
以下示例中仅显示了RoleBinding的subjects部分。对于名为“[email protected]”的用户:
subjects: - kind: User name: "[email protected]" 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
对于任何的 service accounts:
subjects: - kind: Group name: system:serviceaccounts apiGroup: rbac.authorization.k8s.io
对于所有 authenticated users (version 1.5+):
subjects: - kind: Group name: system:authenticated apiGroup: rbac.authorization.k8s.io
对于所有 unauthenticated users (version 1.5+):
subjects: - kind: Group name: system:unauthenticated apiGroup: rbac.authorization.k8s.io
对于所有users (version 1.5+):
subjects: - kind: Group name: system:authenticated apiGroup: rbac.authorization.k8s.io - kind: Group name: system:unauthenticated apiGroup: rbac.authorization.k8s.io
三、默认的Roles and Role Bindings
API servers 创建一组默认的ClusterRole和ClusterRoleBinding对象。 其中许多是system:前缀,表示资源由基础架构“拥有”。 对这些资源的修改可能导致集群异常。 一个例子是system:node。 此角色定义了kubelet的权限。 如果角色被修改,它可能使kubelets无法工作。
所有的 cluster roles and rolebindings 被label标记为:
kubernetes.io/bootstrapping=rbac-defaults
API Server 在每次启动后都会更新已经丢失的默认 ClusterRole 和 其绑定的相关 Subjects;这将允许集群自动修复因为意外更改导致的 RBAC 授权错误,同时能够使在升级集群后基础设施的 RBAC 授权得以自动更新。
如果想要关闭 API Server 的自动修复功能,只需要将默认创建的 ClusterRole 和其 RoleBind 的 rbac.authorization.kubernetes.io/autoupdate
注解设置为 false 即可,这样做会有很大风险导致集群因为意外修改 RBAC 而无法工作
Auto-reconciliation 在 1.6+ 版本被默认启用(当 RBAC 授权被激活时)
Discovery Roles
默认ClusterRole | 默认ClusterRoleBinding | 描述 |
system:basic-user | system:authenticated and system:unauthenticatedgroups | 允许用户只读访问有关自己的基本信息。 |
system:discovery | system:authenticated and system:unauthenticatedgroups | 允许只读访问API发现端点,以发现和协商API级别。 |
User-facing Roles
一些默认角色不是system:前缀。 这些是面向用户的角色。 它们包括超级用户角色(cluster-admin),旨在使用ClusterRoleBindings(cluster-status)授予集群范围的角色,以及旨在使用RoleBindings(admin,edit,view)在特定命名空间中授予的角色。
默认ClusterRole | 默认ClusterRoleBinding | 描述 |
cluster-admin | system:masters group | 允许超级用户访问对任何资源执行任何操作。如果使用的是ClusterRoleBinding,它可以完全控制集群和所有命名空间中的每个资源, 当在RoleBinding中使用时,它可以完全控制rolebinding的命名空间中的每个资源,包括命名空间本身。 |
admin | none | 允许管理员访问,旨在使用RoleBinding授予对命名空间的访问。 如果在RoleBinding中使用,则允许对命名空间中大多数资源进行读/写访问, 包括在命名空间中创建角色和角色绑定的功能。 它不允许对资源配额或命名空间本身的写访问。 |
edit | none | 允许对命名空间中大多数对象的读/写访问。 它不允许查看或修改Role或RoleBinding。 |
view | none | 允许只读访问查看命名空间中的大多数对象。 它不允许查看或修改Role或RoleBinding。 它不允许查看secrets。 |
Core Component Roles
默认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组件所需的资源,包括对所有secrets的读取访问权限,以及对所有pod的访问权限。 从1.7开始,建议使用[Node Authorizer](/ docs / admin / authorization / node /)和[NodeRestriction admission plugin](/docs/admin/admission-controllers#NodeRestriction)而不是此角色,并允许基于计划在其上运行的pod的API访问kubelets。 从1.7开始,当启用“Node”授权模式时,不会自动绑定到“system:nodes”组 |
system:node-proxier | system:kube-proxy user | 允许访问kube-proxy组件所需的资源 |
Other Component Roles
默认ClusterRole | 默认ClusterRoleBinding | 描述 |
system:auth-delegator | none | 允许委托认证和授权检查。 这通常由附加API服务器用于统一认证和授权。 |
system:heapster | none | Heapster组件的角色 |
system:kube-aggregator | none | kube-aggregator组件的角色。 |
system:kube-dns | kube-dns service account in the kube-system namespace | kube-dns组件的角色 |
system:node-bootstrapper | none | 允许访问执行Kubelet TLS自举所需的资源。 |
system:node-problem-detector | none | node-problem-detector组件的角色 |
system:persistent-volume-provisioner | none | 允许访问大多数动态卷配置所需的资源 |
Controller Roles
Kubernetes控制器管理器运行核心控制环路。 当使用--use-service-account-credentials调用时,每个控制循环都将使用单独的服务帐户启动。 对于每个控制循环,存在相应的角色,前缀为system:controller:。 如果控制器管理器未启动--use-service-account-credentials,它将使用其自己的凭证运行所有控制循环,这些凭证必须被授予所有相关的角色。 这些角色包括:
- 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授权器没有被使用也是如此。
用户即使在对某个 Role 拥有全部权限的情况下也仅能在其作用范围内(ClusterRole -> 集群范围内,Role -> 当前 namespace 或 集群范围)对其进行 create 和 update 操作;
例如 “user-1” 用户不具有在集群范围内列出 secrets 的权限,那么他也无法在集群范围内创建具有该权限的 ClusterRole,也就是说想传递权限必须先获得该权限;
想要允许用户 cretae/update Role 有两种方式:
- 授予一个该用户期望 create/update 的 Role 或者 ClusterRole
- 授予一个包含该用户期望 create/update 的 Role 或者 ClusterRole 的 Role 或者 ClusterRole(有点绕…);如果用户尝试 crate/update 一个其不拥有的 Role 或者 ClusterRole,则 API 会禁止。 如果他们尝试创建或修改一个Role或ClusterRole的权限,他们自己还没有被授权,API请求将被禁止。
如果用户想要创建/更新role binding,那么用户必须已经具有包含在引用角色中的所有权限(与角色绑定相同的范围),或者如果已被赋予权限来执行role binding的verb,如果“user-1”无法在群集范围内列出secrets,则不能向授予该权限的角色创建ClusterRoleBinding。
允许用户创建/更新角色绑定:
- 授予他们一个角色,允许他们根据需要创建/更新RoleBinding或ClusterRoleBinding对象。
- 授予他们绑定特定角色所需的权限:
- 隐含地,通过给他们角色中包含的权限。
- 明确地说,通过授予他们在特定角色(或群集角色)上执行绑定动词的权限。
例如,此集群角色和角色绑定将允许“user-1”授予其他用户在“user-1-namespace”命名空间中的管理,编辑和查看角色:
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
当使用 bootstrapping 时,初始用户尚没有访问 API 的权限,此时想要授予他们一些尚未拥有的权限是不可能的,此时可以有两种解决方案:
- 使用具有system:masters group的credential ,该credential是通过默认绑定绑定到cluster-admin超级用户角色。
- 如果您的API服务器在启用了不安全端口(--insecure-port)的情况下运行,那么还可以通过该端口进行API调用,不会强制执行身份验证或授权
五、RBAC命令行工具
存在两个kubectl命令来在命名空间或整个集群中授予角色
kubectl create rolebinding
kubectl create rolebinding bob-admin-binding --clusterrole=admin --user=bob --namespace=acme
kubectl create rolebinding myapp-view-binding --clusterrole=view --serviceaccount=acme:myapp --namespace=acme
kubectl create clusterrolebinding
kubectl create clusterrolebinding root-cluster-admin-binding --clusterrole=cluster-admin --user=root
kubectl create clusterrolebinding kubelet-node-binding --clusterrole=system:node --user=kubelet
kubectl create clusterrolebinding myapp-view-binding --clusterrole=view --serviceaccount=acme:myapp
六、Service Account Permissions
Service Account概念的引入是基于这样的使用场景:运行在pod里的进程需要调用Kubernetes API以及非Kubernetes API的其它服务。Service Account它并不是给kubernetes集群的用户使用的,而是给pod里面的进程使用的,它为pod提供必要的身份认证。
默认RBAC策略向 control-plane components, nodes, and controllers授予范围限制的权限,但不向“kube-system”命名空间之外的service accounts授予权限(超出发给所有已验证用户的发现权限)。这允许您根据需要向特定服务帐户授予特定角色。 细粒度角色绑定提供更大的安全性,但需要更多的努力来管理。 更广泛的授权可以给service accounts提供不必要的(可能升级的)API访问,但是更容易管理。
从最安全到最不安全的的方式如下:
- 为应用程序特定的服务帐户(最佳实践)授予角色:这要求应用程序在其pod的spec中指定serviceAccountName,并且要创建 service account 。例如,将“my-namespace”中的只读权限授予“my-sa”服务帐户:
kubectl create rolebinding my-sa-view --clusterrole=view --serviceaccount=my-namespace:my-sa --namespace=my-namespace
- 在命名空间中为“默认” service account 授予角色:如果应用程序没有指定serviceAccountName,它将使用“默认”service account。注意:授予“默认”服务帐户的权限可用于命名空间中未指定serviceAccountName的任何pod。
例如,将“my-namespace”中的只读权限授予“默认”service account:
kubectl create rolebinding default-view --clusterrole=view --serviceaccount=my-namespace:default --namespace=my-namespace
许多加载项当前作为“kube-system”命名空间中的“默认”service account运行。 要允许这些加载项使用超级用户访问权限,请将cluster-admin权限授予“kube-system”命名空间中的“默认”服务帐户。注意:启用这意味着“kube-system”命名空间包含授予超级用户访问API的权限。
kubectl create clusterrolebinding add-on-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default
- 为命名空间中的所有service accounts授予角色:如果希望命名空间中的所有应用程序都具有该角色,无论使用什么service accounts,可以将该角色授予该命名空间的service account group 。例如,将“my-namespace”中的只读权限授予该命名空间中的所有service accounts:
kubectl create rolebinding serviceaccounts-view --clusterrole=view --group=system:serviceaccounts:my-namespace--namespace=my-namespace
- 对集群范围内的所有service accounts(不鼓励)授予有限的权限:如果您不想管理每个命名空间的权限,则可以将群集范围角色授予所有service accounts。例如,将所有命名空间中的只读权限授予群集中的所有service accounts:
kubectl create clusterrolebinding serviceaccounts-view --clusterrole=view --group=system:serviceaccounts
- 授予超级用户访问群集范围内的所有service accounts(强烈不鼓励):如果您根本不关心分区权限,则可以向所有service accounts授予超级用户访问权限。警告:这允许任何具有读取访问权限的用户访问secrets或能够创建一个pod以访问超级用户credentials。
kubectl create clusterrolebinding serviceaccounts-cluster-admin --clusterrole=cluster-admin --group=system:serviceaccounts