云原生探索系列(九):基于角色的权限控制RBAC

177 阅读10分钟

前言

有一些k8s基础的同学都知道,Kubernetes中所有的API对象,都保存到Etcd里。对这些API对象的操作却 一定是通过访问kube-apiserver实现的,其中最重要的原因就是需要apiserver来完成授权工作。负责完成授权 工作的机制,就是RBAC,基于角色的权限控制。

RBAC

使用过程

概念虽然有些复杂,但是使用起来还是相对简单的,大概下面三步:

  1. 在集群中创建一些角色,并为这些角色赋予相应的权限

  2. 将创建的角色绑定到某个账号上

  3. 将账号赋予Pod使用 在K8s中控制角色的对象是Role和ClusterRole,账号是ServiceAccount,而负责将角色和账号 进行绑定的动作定义到了RoleBinding和ClusterRoleBinding对象。

    Role和ClusterRole的区别:

  • Role对象只在某个命名空间下生效
  • ClusterRole对象在整个集群范围内生效。
  • RoleBinding和ClusterRoleBinding也是 这样的。

Role

我们看看Role定义案例:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: nginx
  name: pod-reader
rules:
- apiGroups: [""]  # core API组
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

这个Role对象指定了产生作用的namespace:nginx。 rules 字段,就是它所定义的权限规则。在上面的例子里,这条规则的含义就是:允许“被作用者”,对 nginx 下面的 Pod 对象,进行 GET、WATCH 和 LIST 操作。

RoleBinding

我们看看RoleBinding定义案例:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-readerbinding
  namespace: nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pod-reader
subjects:
  - kind: User
    name: gitlab-runner
    apiGroup: rbac.authorization.k8s.io

我们可以看到roleRef字段,正是通过这个字段,RoleBinding对象就可以直接通过名字来引用我们前面 定义的Role对象,从而定义的被作用者(subject)和角色(Role)之间的绑定关系。

注意:Role和RoleBinding对象,它们对权限的限制规则仅在它们自己的Namespace内有效,roleRef也只能引用当前Namespace里的Role对象。

我们还可以看到subjects字段,它的类型是User,即Kubernetes里的用户,这个用户的名字是gitlab-runner。 但是在Kubernetes中并没有User对象,那这个User从哪里来呢?
它需要通过外部认证服务,比如 Keystone,来提供。或者,你也可以直接给 APIServer 指定一个用户名、密码文件。那么 Kubernetes 的授权系统,就能够从这个文件里找到对应的“用户”了。

ClusterRole、ClusterRoleBinding

这就容易了,前面提到和Role的区别就是,不用指定命名空间。我们来看案例:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-reader
rules:
- apiGroups: [""]  # core API组
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: pod-readerbinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: pod-reader
subjects:
  - kind: User
    name: gitlab-runner
    apiGroup: rbac.authorization.k8s.io

这个例子是ClusterRole 和 ClusterRoleBinding 的组合,意味着gitlab-runner这个用户拥有 对所有命名空间里的Pod进行GET、WATCH和LIST操作的权限。

能够对API对象进行的所有操作

除了上面提到的get、watch、list,还有create、update、patch、delete

resources

需要操作的资源对象类型列表,例 如"pods"、"deployments"、"jobs"等。

apiGroups

资源对象API组列表,例 如""(Core)、"extensions"、"apps"、"batch"等。

rules字段细化控制

先看个案例:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-reader
rules:
- apiGroups: [""]  # core API组
  resources: ["configmaps"]
  resourceNames: ["my-config"]
  verbs: ["get"]

这里我们指定了resourceNames,表面只有对名叫"my-config"的ConfigMap对象进行get操作权限.

ServiceAccount

上面的案例我们指定subjects的类型为User,但是工作中多数情况下不使用用户这个功能,而是直接 使用Kubernetes里的“内置用户”,这个由Kubernetes负责管理的内置用户,就是ServiceAccount。
我们来看案例:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nginx-user
  namespace: nginx

可以看到ServiceAccount的定义很简单,需要注意的是,与Role对象一样需要指定命名空间。 接下来,就可以通过ClusterRoleBinding来绑定他们。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: pod-readerbinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: pod-reader
subjects:
  - kind: ServiceAccount
    name: nginx-user
    namespace: nginx

可以看到subjects 字段的类型变为了ServiceAccount且名字是nginx-user。

使用kubectl命令创建ClusterRole、ServiceAccount、ClusterRoleBinding对象

执行如下命令:

kubectl apply -f cluster-role.yaml
kubectl apply -f service-account.yaml
kubectl apply -f cluster-role-binding.yaml

执行成功后,来看看ServiceAccount的详细信息,执行如下命令

kubectl get sa -n nginx -oyaml

输出内容如下:

...
...
secrets:
- name: nginx-user-token-k9prg

可以看到,kubernetes会自动为一个ServiceAccount创建并分配一个Secret对象,这个Secret就是 这个ServiceAccount对应的用来与apiserver进行交互的授权文件,我们叫Token.Token 文件的内容一般是证书或者密码,它以一个 Secret 对象的方式保存在 Etcd 当中。

pod中指定ServiceAccount

apiVersion: apps/v1
kind: Deployment
...
spec:
  template:
    spec:
      serviceAccountName: nginx-user

pod运行起来后,Secret对象被Kubernetes自动挂载到了容器的/var/run/secrets/kubernetes.io/serviceaccount 目录下.

我们老检验一下,执行如下命令进入pod查看

kubectl exec -it -n nginx nginx-7b8c5978fb-dcrj9 -- /bin/bash

然后执行如下命令:

ls /var/run/secrets/kubernetes.io/serviceaccoun

不出意外的话可以看到三个文件:

ca.crt	namespace  token

当然也可以执行如下命令,查看挂载信息:

kubectl describe po -n nginx nginx-7b8c5978fb-dcrj9

你应该可以找到如下内容:

Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from nginx-user-token-k9prg (ro)

最后

这篇文章主要讲解了RBAC的使用,需要注意的是,如果一个Pod没有声明serviceAccountName, Kubernetes 会自动在它的 Namespace 下创建一个名叫default的默认ServiceAccount, 然后分配给这个 Pod。 但在这种情况下,这个默认 ServiceAccount 并没有关联任何 Role。也就是说,此时它有访问 APIServer 的绝大多数权限。