【 云原生 kubernetes 】- 基于角色的访问控制RBAC

时间:2022-10-18 14:59:23

【 云原生 kubernetes 】- 基于角色的访问控制RBAC

简述

RBAC是一种基于组织中用户的角色来调节控制对计算机或网络资源的访问的方法。 简言之,不同用户之间拥有不同的访问权限,就像我们在使用ELK日志系统时,运维人员具有最高权限,根据其他人员的需求对不同的index分配可读,可写,只读,只写,其他各种权限。

在k8s中,负责完成授权工作的机制,就是RBAC

基本概念

  • Role/ClusterRole:角色,它包含了一组代表相关权限的规则,这些规则就是对不同 API 的不同操作权限
  • Subject:被作用者,用于绑定不同的角色. 可以是组,用户或者服务账户
  • RoleBinding/ClusterRoleBinding:定义了Role/ClusterRoleSubject的绑定关系

【 云原生 kubernetes 】- 基于角色的访问控制RBAC

Role

定义一个Role对象,用来授予对Pod的读访问权限

[root@ycloud ycloud]# cat role.yaml 
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: ycloud
  name: example-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

Role对象指定了产生作用的Namespace是:ycloud

Namespace是k8s的一个逻辑管理单位。不同的Namespace的API对象,是相互隔离的。

这个Role对象的rules字段,其实就是它定义的一组权限规则。

允许"被作用者",对ycloud下面的Pod对象,进行get、watch、list操作。

在Role或者ClusterRole中,如果要赋予用户所有权限,那就可以给verbs字段所有权限

verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

RoleBinging

下面例子中定义了一个RoleBinding对象。

[root@ycloud ycloud]# cat rolebinding.yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: example-rolebinding
  namespace: ycloud
subjects:
- kind: User
  name: system:anonymous
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: example-role
  apiGroup: rbac.authorization.k8s.io

可以看到,这个RoleBinding对象中定义了一个subjects字段,即"被作用者"。它的类型是User,即k8s中的用户。

将"example-role"Role授予在"ycloud"NameSpace中的用户" system:anonymous "。 这样,用户 " system:anonymous " 就具有了读取 "ycloud" NameSpace中所有 Pod 的权限。

实践

我们先在k8s集群中创建名为example的上下文,指定user为匿名用户

[root@ycloud ycloud]# kubectl config set-context example --namespace=ycloud --cluster=kubernetes --user=system:anonymous
Context "example" created.

我们在ycloud这个Namespace下,创建一个简单的Pod对象

[root@ycloud ycloud]# kubectl create ns ycloud
namespace/ycloud created
[root@ycloud ycloud]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
  namespace: ycloud
  labels:
    app: pod-demo
spec:
  containers:
    - name: pod-container-name
      image: nginx
      ports:
        - containerPort: 80
          name: http-server
[root@ycloud ycloud]# kubectl apply -f pod.yaml -n ycloud
pod/pod-demo create

切换上下文

[root@ycloud ycloud]# kubectl config set-context example
Context "example" modified.
[root@ycloud ycloud]# kubectl get po 
Please enter Username: admin
Please enter Password: NAME       READY   STATUS    RESTARTS   AGE
pod-demo   1/1     Running   0          13m

因为我们这里指定的匿名用户,所以我们用户名和密码任意输入,回车即可查看ycloud下面所创建的Pod。

如果我们尝试get deploy或者查看别的Namespace下的pod,查看返回结果,会提示我们这个用户没有权限。

[root@ycloud ycloud]# kubectl get deploy 
Please enter Username: admin
Please enter Password: Error from server (Forbidden): deployments.apps is forbidden: User "system:anonymous" cannot list resource "deployments" in API group "apps" in the namespace "ycloud"
---
[root@ycloud ycloud]# kubectl get po -A 
Please enter Username: admin
Please enter Password: Error from server (Forbidden): pods is forbidden: User "system:anonymous" cannot list resource "pods" in API group "" at the cluster scope

ClusterRole和ClusterRoleBinding

RoleRoleBinding 对象都是 Namespaced 对象,它们仅在自身的 Namespace 内有效,roleRef 也只能引用当前 Namespace 里的 Role 对象。

如果我们想让某一个Role作用到所有的Namespace中去,这时候我们就需要使用到ClusterRole和ClusterRoleBinding这个组合了,这两个API对象跟Role和RoleBinding一样。只不过,不需要我们定义Namespace。

ClusterRole用法:

  1. 定义对某Namespace的访问权限,并将在个别Namespace内被授予访问权限;
  2. 为Namespace作用域的对象设置访问权限,并被授予跨所有Namespace的访问权限;
  3. 为集群作用域的资源定义访问权限。

实践

[root@ycloud ycloud]# cat rolebinding.yaml 
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: example-clusterrole
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: example-clusterrolebinding
subjects:
- kind: User
  name: example-user
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: example-clusterrole
  apiGroup: rbac.authorization.k8s.io

这里如果你还切换在上个实践中,我们可以通过如下命令切换回原来的上下文:

[root@ycloud ycloud]# kubectl config get-contexts 
CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
*         example                       kubernetes   system:anonymous   ycloud
          kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   default
[root@ycloud ycloud]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".          

我这里的名称叫"kubernetes-admin@kubernetes",根据自己的来修改。

接下来让我们创建一下:

[root@ycloud ycloud]# kubectl apply  -f clusterrole.yaml 
clusterrole.rbac.authorization.k8s.io/example-clusterrole created
clusterrolebinding.rbac.authorization.k8s.io/example-clusterrolebinding created

这里我们已经创建成功,让我们重新切换回我们新建的上下文来验证一下,

[root@ycloud ycloud]# kubectl get po -n default
Please enter Username: admin
Please enter Password: NAME                               READY   STATUS              RESTARTS        AGE
nginx-deployment-585449566-hvpqd   1/1     Running             0               12d
nginx-deployment-585449566-k7rjr   1/1     Running             0               12d
nginx-deployment-585449566-ptb2q   1/1     Running             0               12d
---
[root@ycloud ycloud]# kubectl get po -n traefik
Please enter Username: admin
Please enter Password: NAME                       READY   STATUS    RESTARTS   AGE
traefik-84b7798f44-pczfd   1/1     Running   0          12d
whoami-78447d957f-hs9r6    1/1     Running   0          12d
whoami-78447d957f-vmsbl    1/1     Running   0          12d

我们发现可以对所有的Namespace进行Pod访问。最后移除权限

[root@ycloud ycloud]# kubectl delete -f ../ycloud/
clusterrole.rbac.authorization.k8s.io "example-clusterrole" deleted
clusterrolebinding.rbac.authorization.k8s.io "example-clusterrolebinding" deleted
pod "pod-demo" deleted
role.rbac.authorization.k8s.io "example-role" deleted
rolebinding.rbac.authorization.k8s.io "example-rolebinding" deleted

ServiceAccount

大多数时候我们不太使用"用户"这个功能,而是直接使用K8s的内置用户ServiceAccount,不过在使用上是一样的。

首先我们定义一个ServiceAccount

apiVersion: v1
kind: ServiceAccount
metadata:
  namespace: ycloud
  name: sa

我们只需要指定是作用于某个Namespace即可

然后我们可以通过Role和RoleBinding,来对ServiceAccout进行权限分配和绑定

[root@ycloud ycloud]# cat rbac.yaml 
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: ycloud
  name: role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: rolebinding
  namespace: ycloud
subjects:
- kind: ServiceAccount
  name: sa
  namespace: mynamespace
roleRef:
  kind: Role
  name: role
  apiGroup: rbac.authorization.k8s.io

可以看到,RoleBinding对象中,subjects字段不再是一个User,而是一个serviceaccount。

[root@ycloud ycloud]# kubectl apply -f serviceaccount.yaml 
serviceaccount/sa created
[root@ycloud ycloud]# kubectl apply -f rbac.yaml 
role.rbac.authorization.k8s.io/role created
rolebinding.rbac.authorization.k8s.io/rolebinding created

创建好之后,让我们查看一下ServiceAccount的描述内容:

[root@ycloud ycloud]# kubectl describe  serviceaccount sa  -n ycloud 
Name:                sa
Namespace:           ycloud
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   sa-token-pxc28
Tokens:              sa-token-pxc28
Events:              <none>

我们会发现,k8s会为ServiceAccount对象自动分配一个secrets。这个secrets是用来ServiceAccount和APIserver进行交互的授权文件,一般保存的会是证书或者是密码。

让我们将"用户"和Pod进行绑定,在之前的pod文件中添加一行。

[root@ycloud ycloud]# cat pod.yaml 
`````
spec:
  serviceAccountName: sa     ###指定ServiceAccount
  containers:
    - name: pod-container-name
      image: nginx
 `````

如果pod没有绑定serviceAccount,k8s也会自动在它的Namespace下创建一个名叫default的默认ServiceAccount,分配给这个Pod。

除了这些,k8s还提供了几种定义好的ClusterRole来供我们使用,分别是超级用户、可读、可写

  • cluster-admin
  • admin
  • edit
  • view
[root@ycloud ycloud]# kubectl describe clusterrole cluster-admin
Name:         cluster-admin
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  *.*        []                 []              [*]
             [*]                []              [*]

"*"代表了所有权限

总结

我们了解了什么是RBAC,之后我们可以根据我们的需要分配不同的权限。