Kubernetes CSI 存储端到端多租户隔离

Kubernetes 里对一些资源的引用限制是比较弱的,比如 Pod 里可以使用 Secret 与 ConfigMap、PVC 里可以使用 StorageClass。想对这种情况进行限制,必须通过额外的手段来做。

在 Kubernetes 中,CSI 存储的端到端多租户如下所示,除了存储侧多租户之外,Kubernetes 侧也需要多租户来对应着存储侧的多租户,这样才能保证端到端的多租户功能。

k8s-tenant

理想状态下,存储侧的租户 S1/S2 分别与 Kubernetes 侧的 K1/K2 租户对应,K1 租户不能使用 S2 中的存储资源,但是 Kubernetes Dynamic PV Provisioning 中所使用的 StorageClass 却可以被任意 Namespace 里的资源使用,这个就导致了整个端到端多租户并不完整。

要解决 Kubernetes 侧租户之间的隔离问题,可以使用 Kubernetes 的 RBAC 权限控制与 Validating Webhook。

首先创建一个 ClusterRole 来定义 Verb 为 use,Object 为 StorageClass 名字:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: use-storageclass-sc1
rules:
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    resourceNames: ["sc1"]
    verbs: ["use"]

其次在租户 Namespace 里创建 RoleBinding,来定义允许该 Namespace 使用这个 StorageClass:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: use-storageclass-sc1
  namespace: ns1
subjects:
  - kind: Group
    name: system:serviceaccounts:ns1
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: use-storageclass-sc1
  apiGroup: rbac.authorization.k8s.io

最后 PVC Validating Webhook 根据 PVC 信息构造 SAR 并向 Kubernetes 查询权限并返回结果:

apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
  groups:
    - system:serviceaccounts:ns1
  resourceAttributes:
    group: storage.k8s.io
    resource: storageclasses
    name: sc1
    namespace: ns1
    verb: use

k8s-rbac

具体代码实现可参考:https://github.com/chenzhiwei/k8s-storage-webhook

使用Kubernetes原生RBAC这种方式反而是比较麻烦的,其实也可以自己定义一个规则,将规则放进ConfigMap里挂载到Webhook Pod中,Webhook直接读取并做相应判断更简单一些。比如:

apiVersion: v1
kind: ConfigMap
metadata:
  name: storageclass-rules
data:
  rules.json: |
    {
      "sc1": ["ns1", "ns2", "ns3"],
      "sc2": ["ns4", "ns5"]
    }

更新:Kubernetes v1.26 版本中添加了 Validating Admission Policy 功能,可以实现该功能,相对简单一些。