From 82401cbdcc5a6dcace7da56179f548bb5f3252ef Mon Sep 17 00:00:00 2001 From: Ryan Stankiewicz Date: Thu, 25 Jan 2024 22:07:18 +0000 Subject: [PATCH 1/2] Allow controller SA to describe x-account Secret For cross account provisioning, the controller pods need to be able to describe the x-account K8s Secret in the kube-system namespace. Additionally, I modified the IAM Role used in our cross-account mount example. Users should use the managed AmazonEFSCSIDriverPolicy, which I've copied here. Eventually, we will update the documentation to reference the managed policy instead of this file. (cherry picked from commit cc355e19f4cc2683d9d59de562f55502944aa90c) --- .../templates/controller-serviceaccount.yaml | 34 ++++++-- .../base/controller-serviceaccount.yaml | 33 +++++++- .../describe-mount-target-example.json | 78 ++++++++++++++----- 3 files changed, 117 insertions(+), 28 deletions(-) diff --git a/charts/aws-efs-csi-driver/templates/controller-serviceaccount.yaml b/charts/aws-efs-csi-driver/templates/controller-serviceaccount.yaml index bc1d11d1a..48d1a90c1 100644 --- a/charts/aws-efs-csi-driver/templates/controller-serviceaccount.yaml +++ b/charts/aws-efs-csi-driver/templates/controller-serviceaccount.yaml @@ -40,12 +40,19 @@ rules: - apiGroups: ["coordination.k8s.io"] resources: ["leases"] verbs: ["get", "watch", "list", "delete", "update", "create"] - # - apiGroups: [ "" ] - # resources: [ "secrets" ] - # verbs: [ "get", "watch", "list" ] - --- - +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: efs-csi-external-provisioner-role-describe-secrets + labels: + app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }} +rules: + - apiGroups: [ "" ] + resources: [ "secrets" ] + resourceNames: ["x-account"] + verbs: [ "get", "watch", "list" ] +--- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: @@ -60,3 +67,20 @@ roleRef: kind: ClusterRole name: efs-csi-external-provisioner-role apiGroup: rbac.authorization.k8s.io +--- +# We use a RoleBinding to restrict Secret access to the namespace that the +# RoleBinding is created in (typically kube-system) +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: efs-csi-provisioner-binding-describe-secrets + labels: + app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }} +subjects: + - kind: ServiceAccount + name: {{ .Values.controller.serviceAccount.name }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: efs-csi-external-provisioner-role-describe-secrets + apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/deploy/kubernetes/base/controller-serviceaccount.yaml b/deploy/kubernetes/base/controller-serviceaccount.yaml index 655c0268c..41fce01af 100644 --- a/deploy/kubernetes/base/controller-serviceaccount.yaml +++ b/deploy/kubernetes/base/controller-serviceaccount.yaml @@ -36,9 +36,19 @@ rules: - apiGroups: ["coordination.k8s.io"] resources: ["leases"] verbs: ["get", "watch", "list", "delete", "update", "create"] - # - apiGroups: [ "" ] - # resources: [ "secrets" ] - # verbs: [ "get", "watch", "list" ] +--- +# Source: aws-efs-csi-driver/templates/controller-serviceaccount.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: efs-csi-external-provisioner-role-describe-secrets + labels: + app.kubernetes.io/name: aws-efs-csi-driver +rules: + - apiGroups: [ "" ] + resources: [ "secrets" ] + resourceNames: ["x-account"] + verbs: [ "get", "watch", "list" ] --- # Source: aws-efs-csi-driver/templates/controller-serviceaccount.yaml kind: ClusterRoleBinding @@ -55,3 +65,20 @@ roleRef: kind: ClusterRole name: efs-csi-external-provisioner-role apiGroup: rbac.authorization.k8s.io +--- +# We use a RoleBinding to restrict Secret access to the namespace that the +# RoleBinding is created in (typically kube-system) +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: efs-csi-provisioner-binding-describe-secrets + labels: + app.kubernetes.io/name: aws-efs-csi-driver +subjects: + - kind: ServiceAccount + name: efs-csi-controller-sa + namespace: kube-system +roleRef: + kind: ClusterRole + name: efs-csi-external-provisioner-role-describe-secrets + apiGroup: rbac.authorization.k8s.io \ 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 index 93b4428c5..102ec526c 100644 --- 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 @@ -1,24 +1,62 @@ { "Version": "2012-10-17", "Statement": [ - { - "Sid" : "Stmt1DescribeMountTargets", - "Effect": "Allow", - "Action": [ - "elasticfilesystem:DescribeFileSystems", - "elasticfilesystem:DescribeMountTargets", - "elasticfilesystem:CreateAccessPoint" - ], - "Resource": "arn:aws:elasticfilesystem:us-west-2:123456789012:file-system/file-system-ID" - }, - { - "Sid" : "Stmt2AdditionalEC2PermissionsToDescribeMountTarget", - "Effect": "Allow", - "Action": [ - "ec2:DescribeSubnets", - "ec2:DescribeNetworkInterfaces" - ], - "Resource": "*" - } + { + "Sid": "AllowDescribe", + "Effect": "Allow", + "Action": [ + "elasticfilesystem:DescribeAccessPoints", + "elasticfilesystem:DescribeFileSystems", + "elasticfilesystem:DescribeMountTargets", + "ec2:DescribeAvailabilityZones" + ], + "Resource": "*" + }, + { + "Sid": "AllowCreateAccessPoint", + "Effect": "Allow", + "Action": [ + "elasticfilesystem:CreateAccessPoint" + ], + "Resource": "*", + "Condition": { + "Null": { + "aws:RequestTag/efs.csi.aws.com/cluster": "false" + }, + "ForAllValues:StringEquals": { + "aws:TagKeys": "efs.csi.aws.com/cluster" + } + } + }, + { + "Sid": "AllowTagNewAccessPoints", + "Effect": "Allow", + "Action": [ + "elasticfilesystem:TagResource" + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "elasticfilesystem:CreateAction": "CreateAccessPoint" + }, + "Null": { + "aws:RequestTag/efs.csi.aws.com/cluster": "false" + }, + "ForAllValues:StringEquals": { + "aws:TagKeys": "efs.csi.aws.com/cluster" + } + } + }, + { + "Sid": "AllowDeleteAccessPoint", + "Effect": "Allow", + "Action": "elasticfilesystem:DeleteAccessPoint", + "Resource": "*", + "Condition": { + "Null": { + "aws:ResourceTag/efs.csi.aws.com/cluster": "false" + } + } + } ] -} +} \ No newline at end of file From 62364749356a31ff86bd93c3d4dae7046604a2bf Mon Sep 17 00:00:00 2001 From: rimaulana Date: Wed, 15 Nov 2023 20:21:18 +0000 Subject: [PATCH 2/2] Added Fargate support for EFS CSI Controller (cherry picked from commit b002dd3c23c6dc8fa9d273b5d0f3506b6612e129) --- pkg/cloud/k8s_metadata.go | 2 +- pkg/cloud/k8s_metadata_test.go | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/pkg/cloud/k8s_metadata.go b/pkg/cloud/k8s_metadata.go index bf250aa6d..91ab339cc 100644 --- a/pkg/cloud/k8s_metadata.go +++ b/pkg/cloud/k8s_metadata.go @@ -44,7 +44,7 @@ func (k kubernetesApiMetadataProvider) getMetadata() (MetadataService, error) { return nil, fmt.Errorf("node providerID empty, cannot parse") } - re := regexp.MustCompile("i-[a-z0-9]+$") + re := regexp.MustCompile("i-[a-z0-9]+$|[a-z0-9]{32}") instanceID := re.FindString(providerId) if instanceID == "" { return nil, fmt.Errorf("did not find aws instance ID in node providerID string") diff --git a/pkg/cloud/k8s_metadata_test.go b/pkg/cloud/k8s_metadata_test.go index 6c329c624..54edc45da 100644 --- a/pkg/cloud/k8s_metadata_test.go +++ b/pkg/cloud/k8s_metadata_test.go @@ -78,6 +78,20 @@ func TestInstanceIdParsedFromProviderIdCorrectly(t *testing.T) { } } +func TestTaskIdParsedFromProviderIdCorrectly(t *testing.T) { + clientSet := setupKubernetesClient(t, nodeName, createFargateNode()) + k8sMp := kubernetesApiMetadataProvider{api: clientSet} + + metadata, err := k8sMp.getMetadata() + + if err != nil { + t.Fatalf("Error occurred when parsing instance ID, %v", err) + } + if metadata.GetInstanceID() != taskId { + t.Fatalf("Instance ID not extracted correctly, expected %s, got %s", taskId, metadata.GetInstanceID()) + } +} + func TestRegionAndZoneExtractedCorrectlyFromLabels(t *testing.T) { clientSet := setupKubernetesClient(t, nodeName, createDefaultNode()) k8sMp := kubernetesApiMetadataProvider{api: clientSet} @@ -123,3 +137,7 @@ func createNode(nodeName string, nodeRegion string, nodeZone string, providerId func createDefaultNode() *v1.Node { return createNode(nodeName, nodeRegion, nodeZone, fmt.Sprintf("aws:///%s/%s", nodeZone, instanceId)) } + +func createFargateNode() *v1.Node { + return createNode(nodeName, nodeRegion, nodeZone, fmt.Sprintf("aws:///%s/1234567890-%s/%s", nodeZone, taskId, nodeName)) +}