k8s权限控制RBAC
RBAC介绍
官方文档:https://kubernetes.io/zh/docs/reference/access-authn-authz/rbac/
基于角色(Role)的访问控制(RBAC)是一种基于组织中用户的角色来调节控制对 计算机或网络资源的访问的方法。RBAC 鉴权机制使用 rbac.authorization.k8s.io API 组来驱动鉴权决定,允许你通过 Kubernetes API 动态配置策略。要启用 RBAC,在启动api-server服务器时将 --authorization-mode 参数设置为一个逗号分隔的列表并确保其中包含 RBAC
--authorization-mode=Example,RBAC
RBAC中的API对象
RBAC API 声明了四种 Kubernetes 对象:Role、ClusterRole、RoleBinding 和 ClusterRoleBinding,你可以像使用其他 Kubernetes 对象一样, 通过类似 kubectl 这类工具创建对象, 或修改对象
Role和ClusterRole
RBAC 的 Role 或 ClusterRole 中包含一组代表相关权限的规则。 这些权限是纯粹累加的(不存在拒绝某操作的规则)。Role 总是用来在某个命名空间内设置访问权限;在你创建 Role 时,你必须指定该 Role 所属的名字空间。与之相对,ClusterRole 则是一个集群作用域的资源。这两种资源的名字不同(Role 和ClusterRole)是因为 Kubernetes 对象要么是名字空间作用域的,要么是集群作用域的, 不可两者兼具。如果你希望在名字空间内定义角色,应该使用 Role; 如果你希望定义集群范围的角色,应该使用 ClusterRole
role示例
apiVersion: rbac.authorization.k8s.io/v1 #api版本
kind: Role #资源类型
metadata: #源数据定义
namespace: default #命名空间
name: pod-reader #名称
rules: #权限定义
- apiGroups: [""] #api组,可以使用kubectl api-resources查看,不写表示匹配所有,大多数情况不写
resources: ["pods"] #资源类型
verbs: ["get", "watch", "list"] #可以进行的操作权限
- apiGroups: [""]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
ClusterRole示例
因为ClusterRole属于集群范围,所以它也可以为没有命名空间限定(全局资源)设置权限,而role不可用,例如:
- 集群范围资源比如节点Node
- 非资源端点(比如 /healthz)
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"]
RoleBinding和ClusterRoleBinding
角色绑定(Role Binding)是将角色中定义的权限赋予一个或者一组用户。 它包含若干 主体(用户、组或服务账户)的列表和对这些主体所获得的角色的引用,RoleBinding 在指定的名字空间中执行授权,而 ClusterRoleBinding 在集群范围执行授权。一个 RoleBinding 可以引用同一的名字空间中的任何 Role。 或者一个 RoleBinding 可以引用某 ClusterRole 并将该 ClusterRole 绑定到 RoleBinding 所在的名字空间。 如果你希望将某 ClusterRole 绑定到集群中所有名字空间,你要使用 ClusterRoleBinding。
所绑定的权限是对整个集群生效还是只对某个命名空间生效取决于使用RoleBinding还是ClusterRoleBinding绑定权限
RoleBinding 示例
apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定允许 "java" 读取 "default" 名字空间中的 Pods
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
# 你可以指定不止一个“subject(主体)”
- kind: User
name: java # "name" 是区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
# "roleRef" 指定与某 Role 或 ClusterRole 的绑定关系
kind: Role # 此字段必须是 Role 或 ClusterRole
name: pod-reader # 此字段必须与你要绑定的 Role 或 ClusterRole 的名称匹配
apiGroup: rbac.authorization.k8s.io
ClusterRoleBinding示例
apiVersion: rbac.authorization.k8s.io/v1
# 此集群角色绑定允许 “manager” 组中的任何人访问任何名字空间中的 secrets
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subjects:
- kind: Group
name: manager # 'name' 是区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
创建了绑定之后,你不能再修改绑定对象所引用的 Role 或 ClusterRole。 试图改变绑定对象的 roleRef 将导致合法性检查错误。 如果你想要改变现有绑定对象中 roleRef 字段的内容,必须删除重新创建绑定对象
Role权限定义详解
不管是Role还是clusterrole中最重要的配置为rules下的配置,具体如下
- apiGroups:一般都是不写让自己进行匹配
- resources:用于指定对那些资源授权
- verbs:对指定的资源授权那些权限,也就是动作
resources中的资源除去一些特定的系统资源,有些资源其中还包括一些下级资源比如pods资源有许多常用的资源pods/logPod日志,pods/statusPod状态,pods/exec是否可进入Pod控制台权限。只有授权过的资源会有权操作,没有设置的一律没有权限,资源也可以使用进行全部资源匹配也可以匹配某一个资源下的所有资源pods/
verbs可以设置的权限常用的有查看类型的get、list、watch,创建修改类型create、update、delete、patch等
对资源的引用
子资源权限
在 Kubernetes API 中,大多数资源都是使用对象名称的字符串表示来呈现与访问的。 例如,对于 Pod 应使用 “pods”。 RBAC 使用对应 API 端点的 URL 中呈现的名字来引用资源。 有一些 Kubernetes API 涉及 子资源(subresource),例如 Pod 的日志。 对 Pod 日志的请求看起来像这样:
GET /api/v1/namespaces/{namespace}/pods/{name}/log
在这里,pods 对应名字空间作用域的 Pod 资源,而 log 是 pods 的子资源。 在 RBAC 角色表达子资源时,使用斜线(/)来分隔资源和子资源。 要允许某主体读取 pods 同时访问这些 Pod 的 log 子资源,你可以这么写
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list"]
某些资源特定权限
对于某些请求,也可以通过 resourceNames 列表按名称引用资源。 在指定时,可以将请求限定为资源的单个实例。 下面的例子中限制可以 “get” 和 “update” 一个名为 my-configmap 的ConfigMap:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: configmap-updater
rules:
- apiGroups: [""]
# 在 HTTP 层面,用来访问 ConfigMap 的资源的名称为 "configmaps"
resources: ["configmaps"]
resourceNames: ["my-configmap"]
verbs: ["update", "get"]
注意:你不能使用资源名字来限制 create 或者 deletecollection 请求。 对于 create 请求而言,这是因为在鉴权时可能还不知道新对象的名字。 如果你使用 resourceName 来限制 list 或者 watch 请求, 客户端必须在它们的 list 或者 watch 请求里包含一个与指定的 resourceName 匹配的 metadata.name 字段选择器。 例如,kubectl get configmaps --field-selector=metadata.name=my-configmap
聚合的ClusterRole
你可以将若干 ClusterRole 聚合(Aggregate) 起来,形成一个复合的 ClusterRole。 某个控制器作为集群控制面的一部分会监视带有 aggregationRule 的 ClusterRole 对象集合。aggregationRule 为控制器定义一个标签 选择算符供后者匹配 应该组合到当前 ClusterRole 的 roles 字段中的 ClusterRole 对象
聚合ClusterRole 的示例:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.example.com/aggregate-to-monitoring: "true"
rules: [] # 控制面自动填充这里的规则
如果你创建一个与某个已存在的聚合 ClusterRole 的标签选择算符匹配的 ClusterRole, 这一变化会触发新的规则被添加到聚合 ClusterRole 的操作。 下面的例子中,通过创建一个标签同样为 rbac.example.com/aggregate-to-monitoring: true 的 ClusterRole,新的规则可被添加到 “monitoring” ClusterRole 中
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring-endpoints
labels:
rbac.example.com/aggregate-to-monitoring: "true"
# 当你创建 "monitoring-endpoints" ClusterRole 时,
# 下面的规则会被添加到 "monitoring" ClusterRole 中
rules:
- apiGroups: [""]
resources: ["services", "endpoints", "pods"]
verbs: ["get", "list", "watch"]
验证
[root@k8s RBAC]# kubectl get clusterrole test -oyaml
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.example.com/aggregate-to-monitoring: "true"
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring
rules:
- apiGroups:
- ""
resources:
- services
- endpoints
- pods
verbs:
- get
- list
- watch
serviceaccounts服务账号
k8s有了RBAC之后可以很好的控制k8s的集群权限,但是role与clusterrole需要授权给某个用户、组或者服务账号来使用,使用用户与组其实并不太方便,所以推荐使用服务账号
服务账号创建
apiVersion: v1 #api版本
kind: ServiceAccount #资源类型
metadata:
name: test #名称
namespace: default #sa有命名空间隔离性
推荐直接使用命令创建
kubectl create sa test -n riped
[root@k8s-master RBAC]# kubectl get secrets zhang-token-jxknr
NAME TYPE DATA AGE
test-token-jxknr kubernetes.io/service-account-token 3 4m20s
[root@k8s-master RBAC]# kubectl describe secrets test-token-jxknr
Name: test-token-jxknr
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: test
kubernetes.io/service-account.uid: bef2f5b9-b32a-4b1d-94a6-86ef7158da7d
Type: kubernetes.io/service-account-token
Data
====
namespace: 7 bytes
token:
...
使用RoleBinding和ClusterRoleBinding给sa绑定权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: test
namespace: default
使用命令绑定
[root@k8s01 ~]# kubectl create clusterrolebinding zhang --clusterrole=cluster-admin --serviceaccount=default:test
[root@k8s01 ~]# kubectl create rolebinding test --clusterrole=cluster-admin --serviceaccount=riped:test -n engage
--serviceaccount #格式为<namespace>:<serviceaccountname>
RBAC示例
实际环境中推荐创建一个专门用于存放用户认证的serviceaccount的命名空间,所有的服务账号创建到这个命名空间方便之后的管理,按照公司的实际情况设计并创建一些符合自己的通用权限(也就是创建clusterrole),这里推荐使用clusterrole。之后根据情况使用clusterrolebinding 或者rolebinding进行权限的绑定
创建命名空间
[root@k8s01 ~]# kubectl create ns user
创建通用的role
创建一个查看namespaces资源并且可以查看Pod资源的role,但是没有Pod下级资源的权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespace-readonly
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get","list","watch"]
创建一个允许删除Pod的role
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-delete
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","delete"]
创建一个可以进入Pod控制台的role
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-exec
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
创建一个可以查看Pod日志的role
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-log
rules:
- apiGroups: [""]
resources: ["pods","pods/log"]
verbs: ["get","list","watch"]
创建服务账户
[root@k8s01 ~]# kubectl create sa test-log -n user
[root@k8s01 ~]# kubectl create sa test-exec -n user
[root@k8s01 ~]# kubectl create sa test-delete -n user
权限绑定
创建clusterrolebinding绑定全局权限,绑定后可以对所有命名空间相应的资源进行操作
#创建这个权限后test-log的服务账户就可以查看你集群的Pod的日志,但是这个服务账户并不能进行命名空间的查看,可以使用token登录dashboard进行测试,可以创建多个绑定绑定多个role,权限会一起生效
[root@k8s01 ~]# kubectl create clusterrolebinding test-log-1 --clusterrole=pod-log --serviceaccount=user:test-log
[root@k8s01 ~]# kubectl create clusterrolebinding test-log-2 --clusterrole=pod-log --serviceaccount=user:test-log
创建rolebinding绑定单个命名空间的权限,绑定后只会对创建绑定的命名空间的资源有效
#由于namespace是集群资源无法使用rolebinding绑定
[root@k8s01 ~]# kubectl create rolebinding test-exec-1 --clusterrole=pod-exec --serviceaccount=user:test-exec -n test-env
#权限只对test-env命名空间有效,自行dashboard测试,可以查看Pod资源并且可以进入Pod控制台
[root@k8s01 ~]# kubectl create clusterrolebinding test-exec-2 --clusterrole=namespace-readonly --serviceaccount=user:test-exec
权限验证方法
可以直接使用Apifox验证,直接发送api请求的方式验证,认证方法使用token
输入验证的api资源的url地址,常规写法为
#这样可以请求到资源类型的列表,输出方式为json
/api/v1/namespaces/{命名空间名称}/{资源类型}
#如果在加上具体的资源名称,可以显示详细的资源信息
/api/v1/namespaces/{命名空间名称}/{资源类型}/{资源名称}
#加上下级资源可以验证是否有下级资源的权限
/api/v1/namespaces/{命名空间名称}/{资源类型}/{资源名称}/{下级资源}
添加认证方式:Bearer Token,写入token的值
这样就可以点击请求进行测试,如果资源url地址没有填错且有权限,返回的状态码200,如果权限拒绝返回的状态码403