如何允许非 root 用户写入 EKS 中挂载的 EFS

How to allow a non-root user to write to a mounted EFS in EKS

我在配置静态配置的 EFS 时遇到问题,因此多个 pods 作为非 root 用户可以读写文件系统。

我正在使用 AWS EFS CSI 驱动程序。我的版本信息如下:

Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.18", GitCommit:"6f6ce59dc8fefde25a3ba0ef0047f4ec6662ef24", GitTreeState:"clean", BuildDate:"2021-04-15T03:31:30Z", GoVersion:"go1.13.15", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"18+", GitVersion:"v1.18.9-eks-d1db3c", GitCommit:"d1db3c46e55f95d6a7d3e5578689371318f95ff9", GitTreeState:"clean", BuildDate:"2020-10-20T22:53:22Z", GoVersion:"go1.13.15", Compiler:"gc", Platform:"linux/amd64"}

我按照 github 存储库 (https://github.com/kubernetes-sigs/aws-efs-csi-driver/tree/master/examples/kubernetes/multiple_pods) 中的示例适当地更新了 volumeHandle。该示例的规范中定义的 busybox 容器能够读取和写入文件系统,但是当我将相同的 PVC 添加到一个不是 运行 作为根用户的 pod 时,该 pod 无法写入安装 EFS。 我已经尝试了其他一些方法来使它按照我的预期工作:

None 这些配置允许非 root 用户写入已安装的 EFS。 在配置静态配置的 EFS 方面我缺少什么,以便多个 pods,所有这些 运行 作为非 root 用户,可以在安装的 EFS 中读取和写入?

此处的 pod 定义供参考:

apiVersion: v1
kind: Pod
metadata:
  name: app1
spec:
  containers:
  - name: app1
    image: busybox
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo $(date -u) >> /data/out1.txt; sleep 5; done"]
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: efs-claim
---
apiVersion: v1
kind: Pod
metadata:
  name: app2
spec:
  containers:
  - name: app2
    image: busybox
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo $(date -u) >> /data/out2.txt; sleep 5; done"]
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: efs-claim
---
apiVersion: v1
kind: Pod
metadata:
  name: app3
spec:
  containers:
  - name: app3
    image: busybox
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo $(date -u) >> /data/out3.txt; sleep 5; done"]
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  securityContext:
    runAsUser: 1000
    runAsGroup: 1337
    fsGroup: 1337
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: efs-claim

和 SC/PVC/PV:

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: efs-sc
provisioner: efs.csi.aws.com
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: efs-claim
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: efs-sc
  resources:
    requests:
      storage: 5Gi  
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: efs-pv
  annotations:
    pv.beta.kubernetes.io/gid: {{ .Values.groupId | quote }}
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: efs-sc
  csi:
    driver: efs.csi.aws.com
    volumeHandle: fs-asdf123

我想出两种方法来解决这个问题,我想我应该更新这个以防其他人 运行 遇到同样的问题。

第一个可能更好的方法是只使用 dynamically provisioned EFS PersistentVolume。这种方式在 EFS 中创建了一个访问点,该访问点由所有使用 PersistentVolumeClaim 的容器共享。

这是 StorageClass、PersistentVolumeClaim 和使用 PVC 的 pod 的示例。

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: efs-sc
provisioner: efs.csi.aws.com
parameters:
  provisioningMode: efs-ap
  fileSystemId:  {{ .Values.efsVolumeHandle }}
  directoryPerms: "775"
reclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: efs-claim
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: efs-sc
  resources:
    requests:
      storage: 5Gi  # Not actually used - see https://aws.amazon.com/blogs/containers/introducing-efs-csi-dynamic-provisioning/
---
apiVersion: v1
kind: Pod
metadata:
  name: app3
spec:
  containers:
  - name: app3
    image: busybox
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo $(date -u) >> /data/out3.txt; sleep 5; done"]
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  securityContext:
    runAsUser: 1000
    runAsGroup: 1337
    fsGroup: 1337
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: efs-claim

注意 StorageClass 中指定的 directoryPerms (775),以及 Pod 中指定的 runAsGroupfsGroup。在 运行 作为非根用户共享的 Pod 中使用此 PVC 时,用户组号是关键。

runAsUser 仅指定为确保 busybox 内容不会 运行 作为 root


第二种方法是我最初制定的方法,可能是“核”选项,但确实适用于静态配置的 EFS。

为了简洁起见,我省略了 pod 定义的其余部分。您可以使用 initContainer 来确保在安装的 EFS 卷上设置某些权限。

      initContainers:
      - name: fs-permission-update
        image: busybox
        command:
        - chown
        - "root:{{ .Values.groupId }}"
        - "/efs-fs"
        volumeMounts:
        - mountPath: /efs-fs
          name: efs-storage

再次确保以非 root 用户身份安装卷和 运行s 的任何 Pod 使用 fsGrouprunAsGroup 以确保用户是允许的一部分用户组。


总而言之,可能不要使用静态配置的 EFS,而是使用动态配置的 EFS。请注意,这特定于 Kubernetes 的 EFS CSI 驱动程序。查看 EKS CSI Driver GitHub 以获取更多示例和一些其他详细信息。