diff --git a/examples/kubernetes/cross_account_mount/README.md b/examples/kubernetes/cross_account_mount/README.md index b2c3e9b43..a77b0a118 100644 --- a/examples/kubernetes/cross_account_mount/README.md +++ b/examples/kubernetes/cross_account_mount/README.md @@ -21,14 +21,22 @@ parameters: gidRangeEnd: "2000" basePath: "/dynamic_provisioning" az: us-east-1a + csi.storage.k8s.io/provisioner-secret-name: x-account + csi.storage.k8s.io/provisioner-secret-namespace: kube-system ``` ### Prerequisite setup -1. Perform [vpc-peering](https://docs.aws.amazon.com/vpc/latest/peering/working-with-vpc-peering.html) between EKS cluster `vpc` in aws account `A` and EFS `vpc` in another aws account `B` . -2. Create an IAM role in Account `B` which has a trust relationship with Account `A` and add an EFS policy with permissions to call `DescribeMountTargets`. This role will be used by CSI-Driver to determine the mount targets for file system in account `B` -3. Create kubenetes secret with `awsRoleArn` as the key and the role from step 2 as the value. For example, `kubectl create secret generic x-account --namespace=default --from-literal=awsRoleArn='arn:aws:iam::1234567890:role/EFSCrossAccountAccessRole'` -4. Create a service account with IAM role for the EKS cluster and attach it node-deamonset. Attach this IAM role with EFS client mount permission policy. -5. Create a [file system policy](https://docs.aws.amazon.com/efs/latest/ug/iam-access-control-nfs-efs.html#file-sys-policy-examples) for file system in account `B` which allows account `A` to perform mount on it. +Lets say you have an EKS cluster in aws account `A` & you wish to mount your file system in another aws account `B` using aws-efs-csi-driver, you'll need to perform the following steps before you proceed with cross account mount between accounts `A` & `B` +1. Perform [vpc-peering](https://docs.aws.amazon.com/vpc/latest/peering/working-with-vpc-peering.html) between EKS cluster `vpc` in aws account `A` and EFS `vpc` in another aws account `B`. +2. Create an IAM role, say `EFSCrossAccountAccessRole` in Account `B` which has a [trust relationship](./iam-policy-examples/trust-relationship-example.json) with Account `A` and add an inline EFS policy with [permissions](./iam-policy-examples/describe-mount-target-example.json) to call `DescribeMountTargets`. This role will be used by CSI-Driver's Controller service running on EKS cluster in account `A` to determine the mount targets for your file system in account `B`. +3. In aws account `A`, attach an inline policy to IAM role of efs-csi-driver's controller service account with necessary [permissions](./iam-policy-examples/cross-account-assume-policy-example.json) to perform `sts assume role` on the IAM role created in step 2. +4. Create a kubernetes secret with `awsRoleArn` as the key and the role from step 2 as the value. For example, `kubectl create secret generic x-account --namespace=default --from-literal=awsRoleArn='arn:aws:iam::123456789012:role/EFSCrossAccountAccessRole'`. +5. Create an IAM role for service accounts for EKS cluster in account `A` with required [permissions](./iam-policy-examples/node-deamonset-iam-policy-example.json) for EFS client mount. Alternatively, you can find this policy under AWS managed policy as `AmazonElasticFileSystemClientFullAccess`. +6. Attach the service account from step 5 to node daemonset. +7. Create a [file system policy](https://docs.aws.amazon.com/efs/latest/ug/iam-access-control-nfs-efs.html#file-sys-policy-examples) for file system in account `B` which allows account `A` to perform mount on it. + +#### Note: +In dynamic provisioning, if you wish to enable delete access points root directory by setting `delete-access-point-root-dir=true`, you must attach the IAM policy from step 5 above to controller service account's IAM role. ### Deploy the Example Create storage class, persistent volume claim (PVC) and the pod which consumes PV: diff --git a/examples/kubernetes/cross_account_mount/iam-policy-examples/cross-account-assume-policy-example.json b/examples/kubernetes/cross_account_mount/iam-policy-examples/cross-account-assume-policy-example.json new file mode 100644 index 000000000..3d00c27a8 --- /dev/null +++ b/examples/kubernetes/cross_account_mount/iam-policy-examples/cross-account-assume-policy-example.json @@ -0,0 +1,8 @@ +{ + "Version": "2012-10-17", + "Statement": { + "Effect": "Allow", + "Action": "sts:AssumeRole", + "Resource": "arn:aws:iam::123456789012:role/EFSCrossAccountAccessRole" + } +} \ No newline at end of file diff --git a/examples/kubernetes/cross_account_mount/iam-policy-examples/describe-mount-target-example.json b/examples/kubernetes/cross_account_mount/iam-policy-examples/describe-mount-target-example.json new file mode 100644 index 000000000..886615bb4 --- /dev/null +++ b/examples/kubernetes/cross_account_mount/iam-policy-examples/describe-mount-target-example.json @@ -0,0 +1,22 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid" : "Stmt1DescribeMountTargets", + "Effect": "Allow", + "Action": [ + "elasticfilesystem:DescribeMountTargets" + ], + "Resource": "arn:aws:elasticfilesystem:us-west-2:123456789012:file-system/file-system-ID" + }, + { + "Sid" : "Stmt2AdditionalEC2PermissionsToDescribeMountTarget", + "Effect": "Allow", + "Action": [ + "ec2:DescribeSubnets", + "ec2:DescribeNetworkInterfaces" + ], + "Resource": "*" + } + ] +} \ No newline at end of file diff --git a/examples/kubernetes/cross_account_mount/iam-policy-examples/node-deamonset-iam-policy-example.json b/examples/kubernetes/cross_account_mount/iam-policy-examples/node-deamonset-iam-policy-example.json new file mode 100644 index 000000000..a624e1712 --- /dev/null +++ b/examples/kubernetes/cross_account_mount/iam-policy-examples/node-deamonset-iam-policy-example.json @@ -0,0 +1,15 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "elasticfilesystem:ClientMount", + "elasticfilesystem:ClientRootAccess", + "elasticfilesystem:ClientWrite", + "elasticfilesystem:DescribeMountTargets" + ], + "Resource": "*" + } + ] +} \ No newline at end of file diff --git a/examples/kubernetes/cross_account_mount/iam-policy-examples/trust-relationship-example.json b/examples/kubernetes/cross_account_mount/iam-policy-examples/trust-relationship-example.json new file mode 100644 index 000000000..b5d4fd5c5 --- /dev/null +++ b/examples/kubernetes/cross_account_mount/iam-policy-examples/trust-relationship-example.json @@ -0,0 +1,13 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam:::root" + }, + "Action": "sts:AssumeRole", + "Condition": {} + } + ] +} \ No newline at end of file diff --git a/examples/kubernetes/cross_account_mount/specs/pod.yaml b/examples/kubernetes/cross_account_mount/specs/pod.yaml new file mode 100644 index 000000000..522a690e1 --- /dev/null +++ b/examples/kubernetes/cross_account_mount/specs/pod.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: efs-claim +spec: + accessModes: + - ReadWriteMany + storageClassName: efs-sc + resources: + requests: + storage: 5Gi +--- +apiVersion: v1 +kind: Pod +metadata: + name: efs-app +spec: + containers: + - name: app + image: centos + command: ["/bin/sh"] + args: ["-c", "while true; do echo $(date -u) >> /data/out; sleep 5; done"] + volumeMounts: + - name: persistent-storage + mountPath: /data + volumes: + - name: persistent-storage + persistentVolumeClaim: + claimName: efs-claim \ No newline at end of file diff --git a/examples/kubernetes/cross_account_mount/specs/storageclass.yaml b/examples/kubernetes/cross_account_mount/specs/storageclass.yaml new file mode 100644 index 000000000..0ec079aa7 --- /dev/null +++ b/examples/kubernetes/cross_account_mount/specs/storageclass.yaml @@ -0,0 +1,15 @@ +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: efs-sc +provisioner: efs.csi.aws.com +parameters: + provisioningMode: efs-ap + fileSystemId: fs-92107410 + directoryPerms: "700" + gidRangeStart: "1000" # optional + gidRangeEnd: "2000" # optional + basePath: "/dynamic_provisioning" # optional + az: us-east-1a + csi.storage.k8s.io/provisioner-secret-name: x-account + csi.storage.k8s.io/provisioner-secret-namespace: kube-system \ No newline at end of file