本文由作者授权发布,未经许可,请勿转载。
作者:李岚清,网易数帆轻舟事业部资深工程师
基于角色的访问控制(Role-Based Access Control, 即“RBAC”)使用 “rbac.authorization.k8s.io” API Group 实现授权控制,用户可以通过 Kubernetes API 动态配置策略。
API 对象
RBAC 共包含4个类型的资源对象:Role、ClusterRole、RoleBinding、ClusterRoleBinding
。用户可以通过增删改查上述四个API对象来实现访问权限的动态控制。
假如没有创建任何ClusterRole和Role,则所有用户是无权限访问任何K8S的API的,K8S的权限控制是类似于白名单的,通过创建 Role&RoleBinding 和 ClusterRole&ClusterRoleBinding 将用户权限添加到“白名单”中,以此来实现授权。
Role 和 ClusterRole
在 RBAC API 中,Role 和 Cluster 都表示一组权限的集合,Role 是 namespace-scoped的,定义的是某一个namespace中的资源权限;而如果想要实现集群级别的或者跨namespace的权限控制,则需要创建 ClusterRole。
Role example
如上文所说,Role 是 namespace-scoped的,定义的是某一个namespace中的资源权限。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:namespace: defaultname: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API groupresources: ["pods"]verbs: ["get", "watch", "list"]
上述 pod-reader
role,表示可以get/list/watch default namespce下面的pods资源。
Role 中可以定义多条rules,每条rule表示一个权限,rule类型定义如下:
type Rule struct {// Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule. VerbAll represents all kinds.Verbs []string// APIGroups is the name of the APIGroup that contains the resources.// If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed.APIGroups []string// Resources is a list of resources this rule applies to. '*' represents all resources in the specified apiGroups.// '*/foo' represents the subresource 'foo' for all resources in the specified apiGroups.Resources []string// ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed.ResourceNames []string// NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path// If an action is not a resource API request, then the URL is split on '/' and is checked against the NonResourceURLs to look for a match.// Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding.// Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both.NonResourceURLs []string
}
ClusterRole example
ClusterRole 是用来实现集群级别的或者跨namespace的权限控制:
- cluster-scoped 类型的资源,比如
nodes
- non-resource 类型的api,比如/healthz`
- namespace-scoped 类型的资源,实现跨namespace的权限控制
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:# "namespace" omitted since ClusterRoles are not namespacedname: secret-reader
rules:
- apiGroups: [""]## at the HTTP level, the name of the resource for accessing Secret# objects is "secrets"resources: ["secrets"]verbs: ["get", "watch", "list"]
secret-reader
表示 get/list/watch 所有namespaces下面的secrets资源的权限。
RoleBinding 和 ClusterRoleBinding
Role 和 ClusterRole 都表示了权限的集合,权限只有授予某个user或者group才有实际意义。权限和用户之间的关联关系 是通过 RoleBinding 和 ClusterRoleBinding 两个API资源来实现的。RoleBinding 是 namespace-scoped的,而 ClusterRoleBinding是 cluster-scoped的。
RoleBinding example
RoleBinding 可以引用在同一命名空间内定义的 Role 对象。 下面示例中定义的 RoleBinding 对象在“default” 命名空间中将“pod-reader” 角色授予用户“jane”。 这一授权将允许用户“jane” 从“default” 命名空间中读取 pod。
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:name: read-podsnamespace: default
subjects:
- kind: Username: janeapiGroup: rbac.authorization.k8s.io
roleRef:kind: Rolename: pod-readerapiGroup: rbac.authorization.k8s.io
RoleBinding 对象也可以引用一个 ClusterRole 对象用于在 RoleBinding 所在的命名空间内授予用户对所引用的 ClusterRole 中 定义的命名空间资源的访问权限。这一点允许管理员在整个集群范围内首先定义一组通用的角色,然后再在不同的命名空间中复用这些角色。
例如,尽管下面示例中的 RoleBinding 引用的是一个 ClusterRole 对象,但是用户”dave”(即角色绑定主体)还是只能读取”development” 命名空间中的 secret(即 RoleBinding 所在的命名空间)。
# 以下角色绑定允许用户 "dave" 读取 "development" 命名空间中的 secret。
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:name: read-secretsnamespace: development # 这里表明仅授权读取 "development" 命名空间中的资源。
subjects:
- kind: Username: daveapiGroup: rbac.authorization.k8s.io
roleRef:kind: ClusterRolename: secret-readerapiGroup: rbac.authorization.k8s.io
ClusterRoleBinding example
可以使用ClusterRoleBinding在集群级别和所有命名空间中授予权限。下面示例中所定义的ClusterRoleBinding允许在用户组”manager” 中的任何用户都可以读取集群中任何命名空间中的 secret。
以下 ClusterRoleBinding 对象允许在用户组 "manager" 中的任何用户都可以读取集群中任何命名空间中的 secret。
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:name: read-secrets-global
subjects:
- kind: Groupname: managerapiGroup: rbac.authorization.k8s.io
roleRef:kind: ClusterRolename: secret-readerapiGroup: rbac.authorization.k8s.io
更多类型的资源引用
大多数资源由代表其名字的字符串表示,例如”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: defaultname: pod-and-pod-logs-reader
rules:
- apiGroups: [""]resources: ["pods", "pods/log"]verbs: ["get", "list"]
通过resourceNames
列表,角色可以针对不同种类的请求根据资源名引用资源实例。当指定了resourceNames列表时,不同动作 种类的请求的权限,如使用get、delete、update、patch
等动词的请求,将被限定到资源列表中所包含的资源实例上。 例如,如果需要限定一个角色绑定主体只能“get” 或者“update” 一个 configmap 时,您可以定义以下角色:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:namespace: defaultname: configmap-updater
rules:
- apiGroups: [""]resources: ["configmap"]resourceNames: ["my-configmap"]verbs: ["update", "get"]
值得注意的是,如果设置了resourceNames
,则请求所使用的动词不能是 list、watch、create 或者 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"]
- 允许读取 pods 以及读写 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绑定从而限制针对某一个命名空间中定义的一个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"]
- 所有api 访问权限
rules:
- apiGroups: ["*"]resources: ["*"]verbs: ["*"]
角色绑定示例
- 一个名为 alice@example.com 的用户:
subjects:
- kind: Username: "alice@example.com"apiGroup: rbac.authorization.k8s.io
- 一个名为 frontend-admins 的用户组:
subjects:
- kind: Groupname: "frontend-admins"apiGroup: rbac.authorization.k8s.io
- kube-system 命名空间中的默认服务账户:
subjects:
- kind: ServiceAccountname: defaultnamespace: kube-system
- 名为 qa 命名空间中的所有服务账户:
subjects:
- kind: Groupname: system:serviceaccounts:qaapiGroup: rbac.authorization.k8s.io
- 集群中的所有服务账户
subjects:
- kind: Groupname: system:serviceaccountsapiGroup: rbac.authorization.k8s.io
- 所有认证过的用户
subjects:
- kind: Groupname: system:authenticatedapiGroup: rbac.authorization.k8s.io
- 所有没认证的用户
subjects:
- kind: Groupname: system:unauthenticatedapiGroup: rbac.authorization.k8s.io
- 所有用户
subjects:
- kind: Groupname: system:authenticatedapiGroup: rbac.authorization.k8s.io
- kind: Groupname: system:unauthenticatedapiGroup: rbac.authorization.k8s.io
作者简介
李岚清,网易数帆轻舟事业部资深系统开发工程师,具有多年 Kubernetes 开发运维经验,负责在 / 离线业务混部、容器网络编排等多个项目,推动和协助网易内部多个业务实现容器化。目前专注于云原生、分布式系统架构等技术领域。