概述
k8s的权限控制在实际工作中不那么经常使用,但是却是很重要的,我们需要深入理解才能很好的解决某些问题。在我们现目前的了解中,常用的授权插件有以下几种:
Node(节点认证)
ABAC(基于属性的访问控制)
RBAC(基于角色的访问控制)
Webhook(基于http回调机制的访问控制)
kubernetes 集群相关所有的交互都需要通过apiserver来完成,对于这样集中式管理的系统来说,权限管理尤其重要,Kubernetes的授权是基于插件形式的,在1.5版的时候引入了基于角色的访问控制(Role-Based Access Control, 即”RBAC”)来实现授权决策,允许管理员通过Kubernetes API动态配置策略。
RBAC的理解大概如下:让一个用户(Users)扮演一个角色(Role),角色拥有权限,从而让用户拥有这样的权限,随后在授权机制当中,只需要将权限授予某个角色,此时用户即可获取对应角色的权限,从而实现角色的访问控制。如图:
实际使用中,要启用RBAC,需要在 apiserver 中添加参数–authorization-mode=RBAC,如果使用的kubeadm安装的集群,1.6+版本都默认开启了RBAC。RBAC引入了4个新的顶级资源对象 :Role、ClusterRole、RoleBinding和 ClusterRoleBinding。 同其他 API 资源对象 一样,用户可以通过kubectl 或者 API 调用等方式操作这些资源对象。
在k8s的授权机制当中,采用RBAC的方式进行授权,其工作流程是把对对象的操作权限定义到一个角色当中,再将用户绑定到该角色,从而使用户得到对应角色的权限。此种方式仅作用于当前空间,这是什么意思呢?当User1绑定到Role角色当中,User1就获取了对该NamespaceA的操作权限,但是对NamespaceB是没有权限进行操作的,如get,list,watch等操作。
此外,k8s为此还有一种集群级别的授权机制,就是定义一个集群角色(ClusterRole),对集群内的所有资源都有可操作的权限,从而将User2,User3通过ClusterRoleBinding到ClusterRole,从而使User2、User3拥有集群的操作权限,如下。
这里有2种绑定ClusterRoleBinding、RoleBinding。但是也可以使用RoleBinding去绑定ClusterRole。
当使用这种方式进行绑定时,用户仅能获取当前名称空间的所有权限。为什么这么绕呢??举例有10个名称空间,每个名称空间都需要一个管理员,而该管理员的权限都是一致的。那么此时需要去定义这样的管理员,使用RoleBinding就需要创建10个Role,这样显得更加繁重。为此当使用RoleBinding去绑定一个ClusterRole时,该User仅仅拥有对当前名称空间的集群操作权限,换句话说,此时只需要创建一个ClusterRole就解决了以上的需求。(注意:RoleBinding仅仅对当前名称空间有对应的权限)
在RBAC API中,一个角色就是一组权限的集合, 权限以纯粹的累加形式累积(没有”否定”的规则)。 角色由命名空间(namespace)内的Role对象定义,而整个Kubernetes集群范围内有效的角色则通过ClusterRole对象实现。
示例
下面我们分别说明每个资源对象
角色(Role)
一个角色就是一组权限的集合,这里的权限都是许可形式的,不存在拒绝的规则。在一个命名空间中,可以用角色来定义一个角色,如果是集群级别的,就需要使用ClusterRole了。角色只能对当前命名空间内的资源进行授权,以下示例描述了”default”命名空间中定义的一个Role对象,用于授予对pod的读访问权限:
[root@k8s-m1 tmp]# cat default-role.yml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" 空字符串,表示核心 API 群
resources: ["pods"]
verbs: ["get", "watch", "list"]
[root@k8s-m1 tmp]# kubectl apply -f default-role.yml
role.rbac.authorization.k8s.io/pod-reader created
role中的参数说明如下
- apiGroups:支持的 API 组列表,关于当前版本支持RBAC的apiGroups有哪些可以通过
kubectl api-versions |grep -i rbac
查看 - resource:支持的资源对象列表,例如 pods、deployments、jobs 等。
- verbs:对资源对象的操作方法列表,例如 get, list, watch, create, update, patch, delete,deletecollection 。
集群角色(Cluster Role)
集群角色除了具有和角色一致的名称空间内资源的管理能力,因其集群级别的范围,还可以用于以下特殊元素的授权。
- 集群范围的资源(例如 Node(节点))
- 非资源型的路径(例如 /healthz)
- 包含全部名称空间的资源,例如 pods(用于 kubectl get pods -A 这样的操作授权)。
下面的集群角色可以让用户有权访问任意一个或所有命名空间的 configmaps(取决于其绑定方式):
[root@k8s-m1 tmp]# cat default-clusterrole.yml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: configmaps-reader
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "watch", "list"]
#鉴于ClusterRole是作用于整个集群范围对象,所以这里不需要定义"namespace"字段
[root@k8s-m1 tmp]# kubectl apply -f default-clusterrole.yml
clusterrole.rbac.authorization.k8s.io/configmaps-reader created
RoleBinding与ClusterRoleBinding
角色绑定(Role Binding)和集群角色绑定用于将一个角色中定义的各种权限绑定到一个目标上。 该目标可以是User(用户)、Group(组)或者Service Account。 在命名空间中可以通过RoleBinding对象授予权限,而集群范围的权限授予则通过ClusterRoleBinding对象完成。
RoleBinding可以引用在同一命名空间内定义的Role对象。 下面示例中定义的RoleBinding对象在”default”命名空间中将”pod-reader”角色授予用户”margu”。 这一授权将允许用户”margu”从”default”命名空间中读取pod。
以下角色绑定定义将允许用户"margu"从"default"命名空间中读取pod。(rolebinding+role)
[root@k8s-m1 tmp]# cat default-rolebinding.yml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: read-pods
namespace: default
subjects:
- kind: User # 赋予用户margu pod-reader角色权限
name: margu
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role # 此字段必须是 Role 或 ClusterRole
name: pod-reader # 此字段必须与你要绑定的 Role 或 ClusterRole 的名称匹配,也就是说此 Role 或 ClusterRole必须存在
apiGroup: rbac.authorization.k8s.io
[root@k8s-m1 tmp]# kubectl apply -f default-rolebinding.yml
rolebinding.rbac.authorization.k8s.io/read-pods created
RoleBinding也可以引用ClusterRole进行授权。
RoleBinding对象也可以引用一个ClusterRole对象,用于在RoleBinding所在的命名空间内授予用户对所引用的ClusterRole中 定义的资源的访问权限。这一点允许管理员在整个集群范围内首先定义一组通用的角色,然后再在不同的命名空间中复用这些角色。(这样做的目的是创建一个通用权限的ClusterRole,如果需要创建10个名称空间管理员的时候只需要用RoleBinding和ClusterRole绑定即可,不用创建十个role和十个RoleBinding,只需要一个ClusterRole和十个RoleBinding就搞定了)
例如,尽管下面示例中的RoleBinding引用的是一个ClusterRole对象,但是用户”dave”(即角色绑定主体)还是只能读取”当前命名空间中的secret(即RoleBinding所在的命名空间)。
以下角色绑定允许用户"margu"读取"com-prod"命名空间中的configmap。(rolebinding+clusterrole)
[root@k8s-m1 tmp]# cat default-rolebinding-clusterrole.yml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: read-configmaps
namespace: com-prod # 集群角色中,只有在development命名空间中的权限才能赋予dave
subjects:
- kind: User
name: margu
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: configmaps-reader # 引用上面定义的clusterRole 名称(clusterRole没有指定命名空间,默认可以应用所有,但是在rolebinding时,指定了命名空间,所以只能读取本命名空间的文件)
apiGroup: rbac.authorization.k8s.io
[root@k8s-m1 tmp]# kubectl apply -f default-rolebinding-clusterrole.yml
rolebinding.rbac.authorization.k8s.io/read-configmaps created
以下ClusterRoleBinding对象允许在用户组"manager"中的任何用户都可以读取集群中任何命名空间中的secret。(clusterrolebinding+clusterrole)
可以使用ClusterRoleBinding在集群级别的所有名称空间中授予权限。下面示例中所定义的ClusterRoleBinding 允许在用户组”manager”中的任何用户都可以读取集群中任何名称空间中的configmap。
[root@k8s-m1 tmp]# cat default-clusterrole-clusterrolebinding.yml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: read-configmaps-global
subjects:
- kind: Group
name: manager
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: configmaps-reader
apiGroup: rbac.authorization.k8s.io
[root@k8s-m1 tmp]# kubectl apply -f default-clusterrole-clusterrolebinding.yml
clusterrolebinding.rbac.authorization.k8s.io/read-configmaps-global created
下图展示了上述对Pod的get/watch/list操作进行授权的Role和RoleBinding逻辑关系。
对资源的引用
大多数资源由代表其名字的字符串表示,例如”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,需要配置resources为一个数组:
[root@k8s-m1 tmp]# cat log-reader-role.yml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"] # 根据上面意思表示授予读取pods和pods下log的权限
verbs: ["get", "list"]
[root@k8s-m1 tmp]# kubectl apply -f log-reader-role.yml
role.rbac.authorization.k8s.io/pod-and-pod-logs-reader created
以上都是对某类资源的整体控制,对某些资源还可以进行更细的控制。如可以通过名字(ResourceName)进行引用(这里指的是资源实例的名子)。在指定ResourceName后,使用get、delete、update和patch动词的请求,就会被限制在这个资源实例的范围内。
[root@k8s-m1 tmp]# cat oneresource-role.yml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: configmap-updater
rules:
- apiGroups: [""]
resources: ["configmap"]
resourceNames: ["appvars-cm "]
verbs: ["update", "get"]
#只对default命名空间下的appvars-cm这个configmap有update和get的权限
常用的角色(Role)示例
以下示例均为从 Role 或 ClusterRole 对象中截取出来,这里只展示其 rules 部分
1)允许读取core API Group中定义的资源”pods”:
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
2)允许读写在”extensions”和”apps” API Group中定义的”deployments”:
rules:
- apiGroups: ["extensions", "apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
3)允许读取”pods”以及读写“extensions”和“batch” API Group中jobs”:
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: ["batch", "extensions"]
resources: ["jobs"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
4)允许读取一个名为”app-config”的ConfigMap实例(需要将其通过RoleBinding绑定从而限制针对某一个命名空间中定义的一个ConfigMap实例的访问):
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["app-config"]
verbs: ["get"]
5)允许读取core API Group中的”nodes”资源(由于Node是集群级别资源,所以此ClusterRole定义需要与一个ClusterRoleBinding绑定才能有效):
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
6)允许针对非资源端点 “/healthz” 及其所有子路径的”GET”和”POST”请求(此ClusterRole定义需要与一个ClusterRoleBinding绑定才能有效):
rules:
- nonResourceURLs: ["/healthz", "/healthz/*"] # 在非资源URL中,'*'代表后缀通配符
verbs: ["get", "post"]
角色绑定主体(Subject)
RoleBinding或者ClusterRoleBinding将角色绑定到角色绑定主体(Subject)。 从上面知道可以绑定的主体(kind指定)可以是用户组(Group)、用户(User)或者服务账户(Service Accounts)。
用户由字符串表示。可以是纯粹的用户名,例如”margu”、电子邮件风格的名字,如 “margu@example.com” 或者是用字符串表示的数字id。由Kubernetes管理员配置认证模块以产生所需格式的用户名。对于用户名,RBAC授权系统不要求任何特定的格式。然而,前缀system:是 为Kubernetes系统使用而保留的,所以管理员应该确保用户名不包含这个前缀。
Kubernetes中的用户组信息由授权模块提供。用户组与用户一样由字符串表示。Kubernetes对用户组字符串没有格式要求,但前缀system:同样是被系统保留的。
服务账户(serviceAccount)拥有包含 system:serviceaccount:前缀的用户名,并属于拥有system:serviceaccounts:前缀的用户组。
说明:
- system:serviceaccount: (单数)是用于服务账户用户名的前缀;
- system:serviceaccounts: (复数)是用于服务账户组名的前缀。
角色绑定例子
以下示例中,下面的例子中只包含subjects部分的内容。
1)一个名为”margu@example.com”的用户:
subjects:
- kind: User
name: "margu@example.com"
apiGroup: rbac.authorization.k8s.io
2)一个名为”frontend-admins”的用户组:
subjects:
- kind: Group
name: "frontend-admins"
apiGroup: rbac.authorization.k8s.io
3)kube-system命名空间中的默认服务账户:
subjects:
- kind: ServiceAccount
name: default
namespace: kube-system
4)对于任何名称空间中的 “qa” 组中所有的服务账户:
subjects:
- kind: Group
name: system:serviceaccounts:qa
apiGroup: rbac.authorization.k8s.io
5)对于 “com-prod” 名称空间中 “dev” 组中的所有服务帐户:
subjects:
- kind: Group
name: system:serviceaccounts:dev
apiGroup: rbac.authorization.k8s.io
namespace: com-prod
6)在集群中的所有服务账户:
subjects:
- kind: Group
name: system:serviceaccounts
apiGroup: rbac.authorization.k8s.io
7)所有认证过的用户:
subjects:
- kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
8)所有未认证的用户:
subjects:
- kind: Group
name: system:unauthenticated
apiGroup: rbac.authorization.k8s.io
9)所有用户:
subjects:
- kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: system:unauthenticated
apiGroup: rbac.authorization.k8s.io
注意:在创建Rolebinding 或是Clusterrolebinding时如果是ServiceAccount则需指定Namespace字段,如未指定会报如下错误:
error: serviceaccount must be :
[root@k8s-m1 tmp]# kubectl create rolebinding test --role=pods-reader --serviceaccount=kube-sysem:admin --dry-run -o yaml
W0707 11:25:06.364669 10869 helpers.go:553] --dry-run is deprecated and can be replaced with --dry-run=client.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
creationTimestamp: null
name: test
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pods-reader
subjects:
- kind: ServiceAccount
name: admin
namespace: kube-sysem
#这里的admin必须是真实存在于kubectl get sa -n kube-system中的serviceaccount
默认的角色和角色绑定
API Server 创建了一系列的默认 ClusterRole 和 ClusterRoleBinding 对象, 其中许多对象以 “system:” 前缀开头,代表其中绑定的资源是作为基础设施适用和占有的。修改这些资源会导致整个集群不可用。一个例子是 system:node 。这个ClusterRole角色拥有一系列的kubelet权限,如果这个集群角色被修改了,可能会让kubelet出现异常。
所有默认的集群角色 (ClusterRole) 和其角色绑定(role binding)都带有如下标记
Labels: kubernetes.io/bootstrapping=rbac-defaults
自动协商
每次启动时,API Server都会更新默认ClusterRole所缺乏的各种权限,并更新默认ClusterRoleBinding所缺乏的各个角色绑定主体。 这种自动更新机制允许集群修复一些意外的修改。由于权限和角色绑定主体在新的Kubernetes释出版本中可能变化,这也能够保证角色和角色 绑定始终保持是最新的。
如果需要禁用自动更新,请将默认ClusterRole以及ClusterRoleBinding的rbac.authorization.kubernetes.io/autoupdate 设置成为false。 请注意,缺乏默认权限和角色绑定主体可能会导致非功能性集群问题。而当集群RBAC鉴权机制(RBAC Authorizer)处于开启状态时,则自动协商功能默认是被启用的。
下面对一些常见的默认ClusterRole和ClusterRoleBinding对象进行说明。
对系统角色的说明如下表所示:
默认的ClusterRole | 默认的ClusterRoleBinding | 描述 |
---|---|---|
system:basic-user | system:authenticated和system:unauthenticated组 | 让用户能够读取自身的信息 |
system:discovery | system:authenticated和system:unauthenticated组 | 对API发现Endpoint的只读访问,用于API级别的发现和协商 |
对用户角色的说明如下表所示:
默认的ClusterRole | 默认的ClusterRoleBinding | 描述 |
---|---|---|
cluster-admin | system:masters组 | 让超级用户可以对任何资源执行任何操作。如果在ClusterRoleBinding中使用,则影响的是整个集群的所有namespace中的任何资源;如果使用的是RoleBinding,则能控制这一绑定的namespace中的资源,还包括namespace本身。 |
admin | None | 允许admin访问,可以限制在一个namespace中使用RoleBinding。如果在RoleBinding中使用,则允许对namespace中大多数资源进行读写访问,其中包含创建角色和角色绑定的能力。这一角色不允许操作namespace本身,也不能写入资源限额。 |
edit | None | 允许对命名空间内的大多数资源进行读写操作,不允许查看或修改角色,以及角色绑定。 |
view | None | 允许对多数对象进行只读操作,但是对角色、角色绑定及secret是不可访问的。 |
注:有些默认角色不是以"system:"为前缀的,这部分角色是针对用户的。其中包含超级用户角色(cluster-admin),还有针对namespace的角色(admin,edit,view)。
对核心Master组件角色的说明如下表所示:
默认的ClusterRole | 默认的ClusterRoleBinding | 描述 |
---|---|---|
system:kube-scheduler | system:kube-scheduler用户 | 能够访问kube-scheduler组件所需的资源 |
system:kube-controller-manager | system:kube-controller-manager用户 | 能够访问kube-controller-manager组件所需的资源,不同的控制所需的不同权限参见下表。 |
system:node | system:nodes组 | 允许访问kubelet所需的资源,包括对secret的读取,以及对Pod的写入。未来会把上面的两个权限限制在分配到本Node的对象上。今后的鉴权过程,kubelet必须以system:node及一个system:node形式的用户名进行。 |
system:node-proxier | system:kube-proxy用户 | 允许访问kube-proxy所需的资源 |
system:kube-scheduler | system:kube-scheduler用户 | 能够访问kube-scheduler组件所需的资源 |
对其他组件角色的说明如下表所示:
默认的ClusterRole | 默认的ClusterRoleBinding | 描述 |
---|---|---|
system:auth-delegator | None | 允许对授权和认证进行托管,通常用于附加的API服务器 |
system:heapster | None | Heapster组件的角色 |
system:kube-aggregator | None | kube-aggregator的角色 |
system:kube-dns | 在kube-system namespace中kube-dns的Service Account | kube-dns角色 |
system:node-bootstrapper | None | 允许访问kubelet TLS启动所需的资源 |
system:node-problem-detector | None | 允许访问node-problem-detector组件所需的资源 |
system:persistent-volume-provisioner | None | 允许访问多数动态卷供给所需的资源 |
对Controller角色的说明如下表所示:
Controller角 | 操作对象 |
---|---|
system:controller:attachdetach-controller | attachdetach |
system:controller:certificate-controller | 证书控制器 |
system:controller:cronjob-controller | cronjob控制器 |
system:controller:daemon-set-controller | daemonset控制器 |
system:controller:deployment-controller | deployment控制器 |
system:controller:disruption-controller | 中断 |
system:controller:endpoint-controller | endpoint |
system:controller:generic-garbage-collector | 普通垃圾 |
system:controller:horizontal-pod-autoscaler | 水平伸缩 |
system:controller:job-controller | job |
system:controller:namespace-controller | 命名空间 |
system:controller:node-controller | node |
system:controller:persistent-volume-binder | 永久存储卷 |
system:controller:pod-garbage-collector | 有关pod的垃圾 |
system:controller:replicaset-controller | RS |
system:controller:replication-controller | RC |
system:controller:route-controller | route |
system:controller:service-account-controller | service account |
system:controller:service-controller | service |
system:controller:statefulset-controller | statefulset |
system:controller:ttl-controller | ttl |
#上述的某些资源不清楚可以自行查看相关源码说明
K8s Controller Manager负责的是核心控制流。如果启用–user-service-account-credentials(kubeadm部署默认是启用了的,可以查看文件/etc/kubernetes/manifests/kube-controller-manager.yaml
),则每个控制过程都会使用不同的Service Account启动。因此就有了对应各个控制过程的角色,前缀是system:controller。如果未启用这一功能,则将使用各自的凭据运行各个控制流程,这就需要为该凭据授予所有相关角色。
示例:创建User Account访问Kubernetes集群
role+rolebinding
创建一个只能读取default命名空间下的角色margu,可用于防止某些人员的误操作和减小权限,此方法可以用于除运维人员外的其他人员需要查看集群的某些信息。
此步骤在/etc/kubernetes/pki路径下执行,因为需要用到Kubernetes CA证书
生成证书
[root@k8s-m1 ~]# cd /etc/kubernetes/pki/
[root@k8s-m1 pki]# openssl genrsa -out margu.key 2048
Generating RSA private key, 2048 bit long modulus
..................+++
...+++
e is 65537 (0x10001)
[root@k8s-m1 pki]# openssl req -new -key margu.key -subj "/CN=margu" -out margu.csr
[root@k8s-m1 pki]# openssl x509 -req -in margu.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out margu.crt -days 3650
Signature ok
subject=/CN=margu
Getting CA Private Key
#验证证书信息
[root@k8s-m1 pki]# openssl x509 -in margu.crt -text -noout
授权流程( Role –>Rolebinding)
##role定义
[root@k8s-m1 pki]# cat test-role.yml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" 空字符串,表示核心 API 群
resources: ["pods"]
verbs: ["get", "watch", "list"]
[root@k8s-m1 tmp]# kubectl apply -f test-role.yml
role.rbac.authorization.k8s.io/pod-reader created
##rolebinding定义
[root@k8s-m1 tmp]# cat test-rolebinding.yml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: read-pods
namespace: default
subjects:
- kind: User # 赋予用户margu pod-reader角色权限
name: margu
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role # 此字段必须是 Role 或 ClusterRole
name: pod-reader # 此字段必须与你要绑定的 Role 或 ClusterRole 的名称匹配,也就是说此 Role 或 ClusterRole必须存在
apiGroup: rbac.authorization.k8s.io
[root@k8s-m1 pki]# kubectl apply -f test-rolebinding.yml
rolebinding.rbac.authorization.k8s.io/read-pods created
###上面的yaml文件可以通过下面的方法先初步生成yaml文件再进行修改
#[root@k8s-m1 pki]# kubectl create role pod-reader --verb=get,list,watch --resource=pods --dry-run=client -o yaml > test-role.yaml
#[root@k8s-m1 pki]# kubectl create rolebinding read-pods --role=pod-reader --user=margu --dry-run=client -o yaml > test-rolebinding.yaml
[root@k8s-m1 pki]# kubectl get role
NAME CREATED AT
pod-reader 2023-07-07T00:45:42Z
[root@k8s-m1 pki]# kubectl describe role pod-reader
Name: pod-reader
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get watch list] #此处已经定义了pods-reader这个角色对pods资源拥有get、list、watch的权限
[root@k8s-m1 pki]# kubectl describe rolebindings.rbac.authorization.k8s.io read-pods
Name: read-pods
Labels: <none>
Annotations: <none>
Role:
Kind: Role
Name: pod-reader
Subjects:
Kind Name Namespace
---- ---- ---------
User margu
添加用户认证进行测试使用
[root@k8s-m1 pki]# kubectl config set-credentials margu --client-certificate=./margu.crt --client-key=./margu.key --embed-certs=true
User "margu" set.
[root@k8s-m1 pki]# kubectl config set-context margu@kubernetes --cluster=kubernetes --user=margu
Context "margu@kubernetes" created.
[root@k8s-m1 pki]# kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.2.250:8443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
- context:
cluster: kubernetes
user: margu
name: margu@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
- name: margu
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
[root@k8s-m1 pki]# kubectl config use-context margu@kubernetes #切换margu这个用户,并使用get获取pods资源信息
Switched to context "margu@kubernetes".
[root@k8s-m1 pki]# kubectl get pod
NAME READY STATUS RESTARTS AGE
cm-env-pod-all 0/1 Completed 0 23h
configmap-subpath 1/1 Running 217 9d
configmap-volume-pod 1/1 Running 24 24h
init-demo 1/1 Running 0 4d
init-pod1 1/1 Running 96 4d
liveness-exec-pod-1 1/1 Running 66 2d18h
[root@k8s-m1 pki]# kubectl get cm
Error from server (Forbidden): configmaps is forbidden: User "margu" cannot list resource "configmaps" in API group "" in the namespace "default"
[root@k8s-m1 pki]# kubectl get pod -n kube-system
Error from server (Forbidden): pods is forbidden: User "margu" cannot list resource "pods" in API group "" in the namespace "kube-system"
#可以看到查看当前命名空间的其他资源如configmap,或者其他命名空间的资源都是禁止的。
由于margu账户不具备创建的权限,这也说明普通用户是无法进行创建K8S资源的,除非进行更多授权。如下,我们另开一个终端,将配置到一个普通用户test上,使其使用margu账户进行通信。注意linux的登录账户和k8s的管理账户名可以不一样。
以下步骤在root权限下执行
[root@k8s-m1 ~]# useradd test
[root@k8s-m1 ~]# cp -rp .kube/ /home/test/
[root@k8s-m1 ~]# chown -R test.test /home/test/
[root@k8s-m1 ~]# su - test
#以下步骤在普通用户test下执行,是因为test用户已经切换到margu这个管理账号。
[test@k8s-m1 ~]$ kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.2.250:8443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
- context:
cluster: kubernetes
user: margu
name: margu@kubernetes
current-context: margu@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
- name: margu
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
[test@k8s-m1 ~]$ kubectl create ns test
Error from server (Forbidden): namespaces is forbidden: User "margu" cannot create resource "namespaces" in API group "" at the cluster scope
#发现登录test账号使用k8s中的margu用户管理k8s时,不能创建namespace。其次,我们可以将以上配置文件中关于kubernetes-admin的相关部分删除,这样即使其他人可以切换到kubernetes-admin账号,但是相关操作也是需要账号密码的。
##也可以直接用root切换测试
[root@k8s-m1 ~]$ kubectl config use-context margu@kubernetes
Switched to context "margu@kubernetes".
以下步骤在kubernetes-admin的权限下执行
[root@k8s-m1 ~]# kubectl get rolebinding
NAME ROLE AGE
read-pods Role/pod-reader 3d
[root@k8s-m1 ~]# kubectl delete rolebindings.rbac.authorization.k8s.io read-pods
rolebinding.rbac.authorization.k8s.io "read-pods" deleted
通过`kubectl config view` 查看当前的管理用户(current-context)确保使用的是margu用户
[root@k8s-m1 ~]# kubectl get po
Error from server (Forbidden): pods is forbidden: User "margu" cannot list resource "pods" in API group "" in the namespace "default"
#发现删除rolebinding后,margu账号已经不能使用
clusterrole+clusterrolebinding
授权流程(Clusterrole–> Clusterrolebinding )
[root@k8s-m1 pki]# kubectl config use-context kubernetes-admin@kubernetes #切换会kubernetes-admin用户
Switched to context "kubernetes-admin@kubernetes".
##预生成一个yaml文件
[root@k8s-m1 pki]# kubectl create clusterrole cluster-read --verb=get,list,watch --resource=pods --dry-run -o yaml > test-clusterrole.yml
[root@k8s-m1 pki]# cat clusterrole-demo.yaml #查看定义clusterrole和权限,也可以修改
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: cluster-read
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
[root@k8s-m1 tmp]# kubectl apply -f test-clusterrole.yml
clusterrole.rbac.authorization.k8s.io/cluster-read configured
[root@k8s-m1 pki]# kubectl get clusterrole
NAME CREATED AT
cluster-admin 2022-05-13T07:17:19Z
cluster-read 2023-02-24T03:09:53Z
cluster-readonly 2022-06-28T03:12:42Z
......
clusterrolebinding定义
[root@k8s-m1 pki]# kubectl create clusterrolebinding margu-read-all-pods --clusterrole=cluster-read --user=margu --dry-run=client -o yaml > test-clusterrolebinding.yaml
[root@k8s-m1 pki]# vim test-clusterrolebinding.yaml #创建角色绑定,将k8s-user-test绑定到clusterrole:ye-read-all-pods上
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
creationTimestamp: null
name: margu-read-all-pods
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-read
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: margu
[root@k8s-m1 pki]# kubectl apply -f test-clusterrolebinding.yaml
clusterrolebinding.rbac.authorization.k8s.io/margu-read-all-pods created
[root@k8s-m1 pki]# kubectl get clusterrolebinding
NAME ROLE AGE
admin-user ClusterRole/cluster-admin 375d
blackbox-exporter ClusterRole/blackbox-exporter 250d
calico-kube-controllers ClusterRole/calico-kube-controllers 273d
.........
margu-read-all-pods ClusterRole/cluster-read 34s
[root@k8s-m1 pki]# kubectl describe clusterrolebindings.rbac.authorization.k8s.io margu-read-all-pods
Name: margu-read-all-pods
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: cluster-read
Subjects:
Kind Name Namespace
---- ---- ---------
User margu
[margu@k8s-m1 ~]$ kubectl get pod -A #角色绑定后在test终端上进行获取pods信息,已经不会出现forbidden了
NAME READY STATUS RESTARTS AGE
NAMESPACE NAME READY STATUS RESTARTS AGE
com-prod busybox 1/1 Running 279 11d
default cm-env-pod-all 0/1 Completed 0 3d19h
default configmap-subpath 1/1 Running 285 11d
default configmap-volume-pod 1/1 Running 92 3d20h
default init-demo 1/1 Running 0 6d19h
default init-pod1 1/1 Running 163 6d19h
default liveness-exec-pod-1 1/1 Running 133 5d13h
default liveness-http-pod 1/1 Running 0 6d
default my-nginx-7ff446c4f4-2d9gz 1/1 Running 1 10d
default my-nginx-7ff446c4f4-tbtpc 1/1 Running 1 10d
或者直接使用`kubectl config use-context margu@kubernetes`切换后,测试效果和上面是一样的。主要看集群当前的管理用户
[margu@k8s-m1 ~]$ kubectl delete po cm-env-pod-all
Error from server (Forbidden): pods "cm-env-pod-all" is forbidden: User "margu" cannot delete resource "pods" in API group "" in the namespace "default"
#但是进行删除pod就无法进行,因为在授权时是没有delete权限的
从上面的实验,我们可以知道对用户margu进行集群角色绑定,用户margu将会获取对集群内所有资源的对应权限。
clusterrole+rolebinding
授权流程Clusterrole–> Rolebinding
将margu通过rolebinding到集群角色cluster-read当中,此时,marug仅作用于当前名称空间的所有pods资源的权限。
#先删除原有的clusterrolebinding
[root@k8s-m1 pki]# kubectl delete clusterrolebinding margu-read-all-pods
clusterrolebinding.rbac.authorization.k8s.io "margu-read-all-pods" deleted
#预生成yaml文件
[root@k8s-m1 pki]# kubectl create rolebinding margu-read-pods --clusterrole=cluster-read --user=margu --dry-run=client -o yaml > default-rolebinding-clusterrole.yaml
[root@k8s-m1 pki]# vim default-rolebinding-clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
creationTimestamp: null
name: margu-read-pods
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-read
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: margu
[root@k8s-m1 pki]# kubectl apply -f default-rolebinding-clusterrole.yaml
rolebinding.rbac.authorization.k8s.io/margu-read-pods created
#切换用户,不管用哪个用户都需要先切换上下文`kubectl config use-context margu@kubernetes`
[root@k8s-m1 pki]# kubectl config use-context margu@kubernetes
Switched to context "margu@kubernetes".
[root@k8s-m1 pki]# kubectl get pod
NAME READY STATUS RESTARTS AGE
configmap-subpath 1/1 Running 306 12d
configmap-volume-pod 1/1 Running 113 4d17h
init-demo 1/1 Running 0 7d17h
init-pod1 1/1 Running 184 7d17h
[root@k8s-m1 pki]# kubectl get cm
Error from server (Forbidden): configmaps is forbidden: User "margu" cannot list resource "configmaps" in API group "" in the namespace "default"
[root@k8s-m1 pki]# kubectl get po -n kube-system
Error from server (Forbidden): pods is forbidden: User "margu" cannot list resource "pods" in API group "" in the namespace "kube-system"
#只能查看default命名空间下的pod,其他命名空间和当前命名空间的其他资源都不能查看。
#删除用户
[root@k8s-m1 pki]# kubectl config delete-context margu@kubernetes
deleted context margu@kubernetes from /root/.kube/config
[root@k8s-m1 pki]# kubectl config unset users.margu
Property "users.margu" unset.
示例:创建组访问Kubernetes集群(和user account 类似)
关于绑定group的资料比较少,大家可以参考下面的自行测试。
[root@k8s-m1 pki]# openssl genrsa -out testgroupuser.key 2048
# 用此私钥创建一个csr(证书签名请求)文件
[root@k8s-m1 pki]# openssl req -new -key testgroupuser.key -subj "/O=testgroup/CN=testgroupuser" -out testgroupuser.csr
# 拿着私钥和请求文件生成证书
[root@k8s-m1 pki]# openssl x509 -req -in testgroupuser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out testgroupuser.crt -days 3650
# 生成账号,相当于一个组(testgroupuser)
[root@k8s-m1 pki]# kubectl config set-credentials testgroupuser --client-certificate=./testgroupuser.crt --client-key=./testgroupuser.key --embed-certs=true
# 设置上下文参数,对比下面的两种不同之处
[root@k8s-m1 pki]# kubectl config set-context testgroupuser@kubernetes --cluster=kubernetes --user=testgroupuser
[root@k8s-m1 pki]# kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kubernetes-admin@kubernetes kubernetes kubernetes-admin
margu@kubernetes kubernetes margu
testgroup@kubernetes kubernetes testgroupuser
testgroupuser@kubernetes kubernetes testgroupuser
[root@k8s-m1 pki]# cat testgroup-role-bind.yaml
kind: Role # 角色
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: dev
name: testgroup-role
rules:
- apiGroups: [""] # ""代表核心api组
resources: ["services","pods"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
kind: RoleBinding # 角色绑定
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: testgroup-rolebinding
namespace: dev
subjects:
- kind: Group
name: testgroup # 目标用户组
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: testgroup-role # 角色信息
apiGroup: rbac.authorization.k8s.io
[root@k8s-m1 pki]# kubectl apply -f testgroup-role-bind.yaml
[root@k8s-m1 pki]# kubectl config use-context testgroupuser@kubernetes
Switched to context "testgroupuser@kubernetes".
[root@k8s-m1 pki]# kubectl get po -n dev
No resources found in dev namespace.
[root@k8s-m1 pki]# kubectl config use-context testgroup@kubernetes
Switched to context "testgroup@kubernetes".
[root@k8s-m1 pki]# kubectl get po -n dev
No resources found in dev namespace.
##对比区别
示例: 对Service Account的授权管理
默认的RBAC策略为控制平台组件、节点和控制器授予有限范围的权限,但是在"kube-system"之外的Service Account是没有任何权限的。除了所有认证用户都具有的discovery权限。
在使用中,要求用户为Service Account赋予所需的权限。细粒度的角色分配能够提高安全性,但也会提高管理成本。粗放的授权方式可能会给Service Account多余的权限,但会更易于管理。
授予serviceaccount权限的示例:
1)在命名空间my-namespace内对"my-sa"Service Account 授予只读权限
kubectl create rolebinding my-sa-view --clusterrole=view --serviceaccount=my-namespace:my-sa --namespace=my-namespace
2)在全集群范围内为名为myapp的Service Account授予view ClusterRole
kubectl create clusterrolebinding myapp-view-binding --clusterrole=view --serviceaccount=my-namespace:myapp
更多关于kubernetes的知识分享,请前往博客主页。编写过程中,难免出现差错,敬请指出