简介

rbac权限控制是role based access control的简写,中文名基于角色的权限控制。

RBAC API 对象

Kubernetes有一个很基本的特性就是它的所有资源对象都是模型化的 API 对象,允许执行 CRUD(Create、Read、Update、Delete)操作(也就是我们常说的增、删、改、查操作),比如下面的这下资源:

  • Pods
  • ConfigMaps
  • Deployments
  • Nodes
  • Secrets
  • Namespaces

上面这些资源对象的可能存在的操作有:

  • create
  • get
  • delete
  • list
  • update
  • edit
  • watch
  • exec

在更上层,这些资源和 API Group 进行关联,比如Pods属于 Core API Group,而Deployements属于 apps API Group,要在Kubernetes中进行RBAC的管理,除了上面的这些资源和操作以外,我们还需要另外的一些对象:

  • Rule:规则,规则是一组属于不同 API Group 资源上的一组操作的集合
  • Role 和 ClusterRole:角色和集群角色,这两个对象都包含上面的 Rules 元素,二者的区别在于,在 Role 中,定义的规则只适用于单个命名空间,也就是和 namespace 关联的,而 ClusterRole 是集群范围内的,因此定义的规则不受命名空间的约束。另外 Role 和 ClusterRole 在Kubernetes中都被定义为集群内部的 API 资源,和我们前面学习过的 Pod、ConfigMap 这些类似,都是我们集群的资源对象,所以同样的可以使用我们前面的kubectl相关的命令来进行操作
  • Subject:主题,对应在集群中尝试操作的对象,集群中定义了3种类型的主题资源:
    • User Account:用户,这是有外部独立服务进行管理的,管理员进行私钥的分配,用户可以使用 KeyStone或者 Goolge 帐号,甚至一个用户名和密码的文件列表也可以。对于用户的管理集群内部没有一个关联的资源对象,所以用户不能通过集群内部的 API 来进行管理
    • Group:组,这是用来关联多个账户的,集群中有一些默认创建的组,比如cluster-admin
    • Service Account:服务帐号,通过Kubernetes API 来管理的一些用户帐号,和 namespace 进行关联的,适用于集群内部运行的应用程序,需要通过 API 来完成权限认证,所以在集群内部进行权限操作,我们都需要使用到 ServiceAccount,这也是我们这节课的重点
  • RoleBinding 和 ClusterRoleBinding:角色绑定和集群角色绑定,简单来说就是把声明的 Subject 和我们的 Role 进行绑定的过程(给某个用户绑定上操作的权限),二者的区别也是作用范围的区别:RoleBinding 只会影响到当前 namespace 下面的资源操作权限,而 ClusterRoleBinding 会影响到所有的 namespace。

部署管理员权限的kubernetes-dashboard

  1. 部署dashboard-ui

此处使用helm3部署:

## 添加仓库
helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/
## 刷新
helm repo update
## 拉取charts
helm pull kubernetes-dashboard/kubernetes-dashboard 
## 解压后修改端口暴露方式为NodePort
helm install . --generate-name
  1. 部署rbac和rbacbind

dashboard-admin.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: kubernetes-dashboard
    namespace: kubernetes-dashboard
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard

解释: 注意上述的name: cluster-admin,集群中内置了cluster-admin 角色对象,该角色定义了几乎所有资源的所有权限。

root@instance-1:~/rbac# kubectl get clusterrole cluster-admin -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2020-10-13T09:39:17Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  managedFields:
  - apiVersion: rbac.authorization.k8s.io/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .: {}
          f:rbac.authorization.kubernetes.io/autoupdate: {}
        f:labels:
          .: {}
          f:kubernetes.io/bootstrapping: {}
      f:rules: {}
    manager: k3s
    operation: Update
    time: "2020-10-13T09:39:17Z"
  name: cluster-admin
  resourceVersion: "43"
  selfLink: /apis/rbac.authorization.k8s.io/v1/clusterroles/cluster-admin
  uid: 7f29873a-8f9e-4455-8e94-53bf1bfb10ba
rules:
- apiGroups:
  - '*'
  resources:
  - '*'
  verbs:
  - '*'
- nonResourceURLs:
  - '*'
  verbs:
  - '*'
  1. 生成访问密钥
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep kubernetes-dashboard | awk '{print $1}')

注意此处的过滤条件,不一定是kubernetes-dashboard,应该前缀和ClusterRole名字一致。

部署一般权限的用户

第1步:创建用户凭证

我们前面已经提到过,Kubernetes没有 User Account 的 API 对象,不过要创建一个用户帐号的话也是挺简单的,利用管理员分配给你的一个私钥就可以创建了,这个我们可以参考官方文档中的方法,这里我们来使用OpenSSL证书来创建一个 User,当然我们也可以使用更简单的cfssl工具来创建:

  • 给用户 haimaxy 创建一个私钥,命名成:haimaxy.key:

    openssl genrsa -out haimaxy.key 2048
    
    • 使用我们刚刚创建的私钥创建一个证书签名请求文件:haimaxy.csr,要注意需要确保在-subj参数中指定用户名和组(CN表示用户名,O表示组): shell $ openssl req -new -key haimaxy.key -out haimaxy.csr -subj "/CN=haimaxy/O=youdianzhis"
  • 然后找到我们的Kubernetes集群的CA,我们使用的是kubeadm安装的集群,CA相关证书位于/etc/kubernetes/pki/目录下面,如果你是二进制方式搭建的,你应该在最开始搭建集群的时候就已经指定好了CA的目录,我们会利用该目录下面的ca.crtca.key两个文件来批准上面的证书请求

  • 生成最终的证书文件,我们这里设置证书的有效期为500天:

    openssl x509 -req -in haimaxy.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out haimaxy.crt -days 500
    

    现在查看我们当前文件夹下面是否生成了一个证书文件:

    $ ls
    haimaxy.csr haimaxy.key haimaxy.crt
    
  • 现在我们可以使用刚刚创建的证书文件和私钥文件在集群中创建新的凭证和上下文(Context):

    kubectl config set-credentials haimaxy --client-certificate=haimaxy.crt  --client-key=haimaxy.key
    

    我们可以看到一个用户haimaxy创建了,然后为这个用户设置新的 Context:

    kubectl config set-context haimaxy-context --cluster=kubernetes --namespace=kube-system --user=haimaxy
    

到这里,我们的用户haimaxy就已经创建成功了,现在我们使用当前的这个配置文件来操作kubectl命令的时候,应该会出现错误,因为我们还没有为该用户定义任何操作的权限呢:

$ kubectl get pods --context=haimaxy-context
Error from server (Forbidden): pods is forbidden: User "haimaxy" cannot list pods in the namespace "default"

第2步:创建角色

用户创建完成后,接下来就需要给该用户添加操作权限,我们来定义一个YAML文件,创建一个允许用户操作 Deployment、Pod、ReplicaSets 的角色,如下定义:(haimaxy-role.yaml)

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: haimaxy-role
  namespace: kube-system
rules:
- apiGroups: ["", "extensions", "apps"]
  resources: ["deployments", "replicasets", "pods"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # 也可以使用['*']

其中Pod属于 core 这个 API Group,在YAML中用空字符就可以,而Deployment属于 apps 这个 API Group,ReplicaSets属于extensions这个 API Group(我怎么知道的?点这里查文档),所以 rules 下面的 apiGroups 就综合了这几个资源的 API Group:[“”, “extensions”, “apps”],其中verbs就是我们上面提到的可以对这些资源对象执行的操作,我们这里需要所有的操作方法,所以我们也可以使用[’*‘]来代替。

然后创建这个Role

kubectl create -f haimaxy-role.yaml

注意这里我们没有使用上面的haimaxy-context这个上下文了,因为木有权限啦

第3步:创建角色权限绑定

Role 创建完成了,但是很明显现在我们这个 Role 和我们的用户 haimaxy 还没有任何关系,对吧?这里我就需要创建一个RoleBinding对象,在 kube-system 这个命名空间下面将上面的 haimaxy-role 角色和用户 haimaxy 进行绑定:(haimaxy-rolebinding.yaml)

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: haimaxy-rolebinding
  namespace: kube-system
subjects:
- kind: User
  name: haimaxy
  apiGroup: ""
roleRef:
  kind: Role
  name: haimaxy-role
  apiGroup: ""

上面的YAML文件中我们看到了subjects关键字,这里就是我们上面提到的用来尝试操作集群的对象,这里对应上面的 User 帐号 haimaxy,使用kubectl创建上面的资源对象:

kubectl create -f haimaxy-rolebinding.yaml

第4步. 测试

现在我们应该可以上面的haimaxy-context上下文来操作集群了:

$ kubectl get pods --context=haimaxy-context
....

我们可以看到我们使用kubectl的使用并没有指定 namespace 了,这是因为我们已经为该用户分配了权限了,如果我们在后面加上一个-n default试看看呢?

$ kubectl --context=haimaxy-context get pods --namespace=default
Error from server (Forbidden): pods is forbidden: User "haimaxy" cannot list pods in the namespace "default"

是符合我们预期的吧?因为该用户并没有 default 这个命名空间的操作权限