Skip to Content
Kubernetes实践权限及审计RBAC 权限管理实践

权限管理实践

本文主要通过一个例子来介绍如何基于 Kubernetes 的 RBAC 实现授权决策,允许集群管理员通过 Kubernetes API 动态配置策略,让非集群管理员具有某个 namespace 下的所有权限,并可通过 Dashboard 或者 kubectl 来管理该 ns 下的资源。

如果要更加深入地了解和掌握 RBAC,可以查看官方文档

K8S里面有两类用户,

  • Service Account,Kubernetes 中一种用于非人类用户的账号,在 Kubernetes 集群中提供不同的身份标识。详细可参考官方文档
  • 普通用户(user),K8S本身不并管理user,而是交由外部独立服务管理,不能通过K8SAPI来创建user;

目前是通过kubectl和Dashboard来管理集群,Service account已经足够满足要求,而且可以在Kubernetes中直接管理。因此这里不介绍如何使用user这个对象来管理集群。

1. 创建NS

kubectl create ns pre

上面的示例创建了一个名为”pre”的命名空间,用于部署预发布的服务。

2. 创建Service Account

kubectl create sa mingpianwang -n pre

在pre的命名空间下创建一个名为”mingpianwang”的Service account,给到某个特定的用户使用。

3. 赋予权限

由于我们已经预先说明,需要给mingpianwang这个用户赋予pre 这个命名空间下的所有权限,即admin权限。

重点来了RoleBinding对象是可以引用一个ClusterRole对象的,然后这个ClusterRole所拥有的权限只会在这个NS下面有效。这一点允许管理员在整个集群范围内首先定义一组通用的角色,然后再在不同的名字空间中复用这些角色。

我们先看下集群内默认的ClusterRole有哪些,执行get clusterrole命名可以看到,有admin、cluster-admin、edit等角色,那我们可以直接使用admin这个clusterrole角色,通过rolebinding的方式赋予”mingpianwang“这个用户。

[root@10-9-149-7 ~]# kubectl get clusterrole NAME AGE admin 4h53m cluster-admin 4h53m edit 4h53m

示例的yaml如下,我们只要执行下kubectl apply -f rolebinding.yaml 即可。

apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: kubernetes-dashboard-minimal namespace: pre roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: admin subjects: - kind: ServiceAccount name: mingpianwang namespace: pre

当然,我们也可以创建一个Namespace级别的role,并将这个角色绑定到ServiceAccount。

apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: pre name: admin rules: - apiGroups: [""] # "" indicates the core API group resources: ["*"] verbs: ["*"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: kubernetes-dashboard-minimal namespace: pre roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: admin subjects: - kind: ServiceAccount name: mingpianwang namespace: pre

只是这个role不能复用到其他Namespace,一般只有在做精细化权限管理的时候,我们才会创建Role对象,比如一个只能查看pod 名称为test-pod的Role。其他场景下,我们推荐集群管理员使用ClusterRole。

4. 访问Dashboard

在 Kubernetes 1.22 之前的版本中,Kubernetes 会以Secret 形式为ServciceAccount 提供一个长期的有效的静态令牌, Kubernetes v1.22 及更高版本中,需要用户自己配置;详细的可参考官方文档手动获取 ServiceAccount 凭据

Kubernetes 1.22 之前的版本

就要获取到”mingpianwang“的token,其实就是secret了。通过下面的方式来获取,最后的token复制下来就可以了。

bash-4.4# kubectl describe sa/mingpianwang -n pre Name: mingpianwang Namespace: pre Labels: <none> Annotations: <none> Image pull secrets: <none> Mountable secrets: mingpianwang-token-4l8xj Tokens: mingpianwang-token-4l8xj Events: <none> bash-4.4# kubectl describe secret/mingpianwang-token-4l8xj -n pre Name: mingpianwang-token-4l8xj Namespace: pre Labels: <none> Annotations: kubernetes.io/service-account.name: mingpianwang kubernetes.io/service-account.uid: d7bb847d-7621-11e9-9679-5254007e7ba9 Type: kubernetes.io/service-account-token Data ==== ca.crt: 1359 bytes namespace: 5 bytes token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9/....

Kubernetes 1.22 之后的版本

如果你需要为 ServiceAccount 获得一个 API 令牌,你可以创建一个新的、带有特殊注解 kubernetes.io/service-account.name 的 Secret 对象。详细可参考官方文档手动获取一个长久的Token

bash-4.4# kubectl -n pre apply -f - <<EOF apiVersion: v1 kind: Secret metadata: name: mingpianwang-secret annotations: kubernetes.io/service-account.name: mingpianwang type: kubernetes.io/service-account-token EOF

可以通过下面的命令来查看 Secret:

bash-4.4# kubectl -n pre describe secrets/mingpianwang-secret Name: mingpianwang-secret Namespace: pre Labels: <none> Annotations: kubernetes.io/service-account.name: mingpianwang kubernetes.io/service-account.uid: 0c3e9a16-6962-45ee-9e6e-e7f0107cd9a8 Type: kubernetes.io/service-account-token Data ==== ca.crt: 1359 bytes namespace: 3 bytes token: ...

这里将 token 的内容抹去了。当你删除一个与某 Secret 相关联的 ServiceAccount 时,Kubernetes 的控制面会自动清理该 Secret 中长期有效的令牌。

可以使用以下命令查看 ServiceAccount:

kubectl -n pre get serviceaccount mingpianwang -o yaml

在 ServiceAccount API 对象中看不到 mingpianwang-secret Secret, .secrets 字段, 因为该字段只会填充自动生成的 Secret。

登陆Dashboard

复制到登录框,我们发现可以登录到Dashboard首页,不过需要注意的是,由于这个账号只有pre这个命名空间的权限,而Dashboard默认是default,所以进去之后会报一堆错咯,没关系,只要将左侧的NS改为pre即可。

5. 通过 kubectl 管理集群

由于我们还需要支持 kubectl 命令行管理 NS,因此还需要为 mingpianwang 生成kubeconfig,一个用户还好,多个用户就很麻烦了,因此这里我们使用一个自动生成 kubeconfig 的脚本,代码如下:

#!/bin/bash -e # Usage ./k8s-service-account-kubeconfig.sh ( namespace ) ( service account name ) TEMPDIR=$( mktemp -d ) trap "{ rm -rf $TEMPDIR ; exit 255; }" EXIT SA_SECRET=$( kubectl get sa -n $1 $2 -o jsonpath='{.secrets[0].name}' ) # Pull the bearer token and cluster CA from the service account secret. BEARER_TOKEN=$( kubectl get secrets -n $1 $SA_SECRET -o jsonpath='{.data.token}' | base64 -d ) kubectl get secrets -n $1 $SA_SECRET -o jsonpath='{.data.ca\.crt}' | base64 -d > $TEMPDIR/ca.crt CLUSTER_URL=$( kubectl config view -o jsonpath='{.clusters[0].cluster.server}' ) KUBECONFIG=kubeconfig kubectl config --kubeconfig=$KUBECONFIG \ set-cluster \ $CLUSTER_URL \ --server=$CLUSTER_URL \ --certificate-authority=$TEMPDIR/ca.crt \ --embed-certs=true kubectl config --kubeconfig=$KUBECONFIG \ set-credentials $2 --token=$BEARER_TOKEN kubectl config --kubeconfig=$KUBECONFIG \ set-context registry \ --cluster=$CLUSTER_URL \ --user=$2 \ --namespace=$1 kubectl config --kubeconfig=$KUBECONFIG \ use-context registry echo "kubeconfig written to file \"$KUBECONFIG\""

直接在master节点执行sh kubeconfig.sh pre mingpianwang,即可自动生成一个kubeconfig文件,将这个kubeconfig文件分发给使用者,让其复制到~/.kube/config下即可,而且默认NS就是pre,get nodes等操作都是不被允许的。

自动生成kubeconfig的源代码在这里,generator kubeconfig,我们只是加了一个默认NS,这样不需要在执行kubectl命令的时候追加-n pre。