<p>I have been working for nearly 5 straight days now on this and can't get this to work. According to AWS documentation I should* be able to mount an EFS Volume to a pod deployed to a fargate node in kubernetes (EKS).</p>
<p>I'm doing everything 100% through terraform. I'm lost at this point and my eyes are practically bleeding from the amount of terrible documentation I have read. Any guidance that anyone can give me on getting this to work would be amazing!</p>
<p>Here is what I have done so far:</p>
<ol>
<li>Setup an EKS CSI driver, storage class, and role bindings (not really sure why I need these role bindings tbh)</li>
</ol>
<pre><code>resource &quot;kubernetes_csi_driver&quot; &quot;efs&quot; {
  metadata {
    name = &quot;efs.csi.aws.com&quot;
  }

  spec {
    attach_required        = false
    volume_lifecycle_modes = [
      &quot;Persistent&quot;
    ]
  }
}

resource &quot;kubernetes_storage_class&quot; &quot;efs&quot; {
  metadata {
    name = &quot;efs-sc&quot;
  }
  storage_provisioner = kubernetes_csi_driver.efs.metadata[0].name
  reclaim_policy      = &quot;Retain&quot;
}

resource &quot;kubernetes_cluster_role_binding&quot; &quot;efs_pre&quot; {
  metadata {
    name = &quot;efs_role_pre&quot;
  }
  role_ref {
    api_group = &quot;rbac.authorization.k8s.io&quot;
    kind      = &quot;ClusterRole&quot;
    name      = &quot;cluster-admin&quot;
  }
  subject {
    kind      = &quot;ServiceAccount&quot;
    name      = &quot;default&quot;
    namespace = &quot;pre&quot;
  }
}

resource &quot;kubernetes_cluster_role_binding&quot; &quot;efs_live&quot; {
  metadata {
    name = &quot;efs_role_live&quot;
  }
  role_ref {
    api_group = &quot;rbac.authorization.k8s.io&quot;
    kind      = &quot;ClusterRole&quot;
    name      = &quot;cluster-admin&quot;
  }
  subject {
    kind      = &quot;ServiceAccount&quot;
    name      = &quot;default&quot;
    namespace = &quot;live&quot;
  }
}
</code></pre>
<ol start="2">
<li>Setup The EFS Volume with policies and security groups</li>
</ol>
<pre><code>module &quot;vpc&quot; {
  source    = &quot;../../read_only_data/vpc&quot;
  stackname = var.vpc_stackname
}
resource &quot;aws_efs_file_system&quot; &quot;efs_data&quot; {
    creation_token = &quot;xva-${var.environment}-pv-efsdata-${var.side}&quot;

    # encrypted   = true
    # kms_key_id  = &quot;&quot;

    performance_mode = &quot;generalPurpose&quot; #maxIO
    throughput_mode  = &quot;bursting&quot;
    
    lifecycle_policy {
        transition_to_ia = &quot;AFTER_30_DAYS&quot;
    }
}

data &quot;aws_efs_file_system&quot; &quot;efs_data&quot; {
  file_system_id = aws_efs_file_system.efs_data.id
}

resource &quot;aws_efs_access_point&quot; &quot;efs_data&quot; {
  file_system_id = aws_efs_file_system.efs_data.id
}

/* Policy that does the following:
- Prevent root access by default
- Enforce read-only access by default
- Enforce in-transit encryption for all clients
*/
resource &quot;aws_efs_file_system_policy&quot; &quot;efs_data&quot; {
  file_system_id = aws_efs_file_system.efs_data.id

  policy = jsonencode({
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: [
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Principal&quot;: {
                &quot;AWS&quot;: &quot;*&quot;
            },
            &quot;Action&quot;: &quot;elasticfilesystem:ClientMount&quot;,
            &quot;Resource&quot;: aws_efs_file_system.efs_data.arn
        },
        {
            &quot;Effect&quot;: &quot;Deny&quot;,
            &quot;Principal&quot;: {
                &quot;AWS&quot;: &quot;*&quot;
            },
            &quot;Action&quot;: &quot;*&quot;,
            &quot;Resource&quot;: aws_efs_file_system.efs_data.arn,
            &quot;Condition&quot;: {
                &quot;Bool&quot;: {
                    &quot;aws:SecureTransport&quot;: &quot;false&quot;
                }
            }
        }
    ]
  })
}

# Security Groups for this volume
resource &quot;aws_security_group&quot; &quot;allow_eks_cluster&quot; {
  name        = &quot;xva-${var.environment}-efsdata-${var.side}&quot;
  description = &quot;This will allow the cluster ${data.terraform_remote_state.cluster.outputs.eks_cluster_name} to access this volume and use it.&quot;
  vpc_id      = module.vpc.vpc_id

  ingress {
    description = &quot;NFS For EKS Cluster ${data.terraform_remote_state.cluster.outputs.eks_cluster_name}&quot;
    from_port   = 2049
    to_port     = 2049
    protocol    = &quot;tcp&quot;
    security_groups = [
      data.terraform_remote_state.cluster.outputs.eks_cluster_sg_id
    ]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = &quot;-1&quot;
    cidr_blocks = [&quot;0.0.0.0/0&quot;]
  }

  tags = {
    Name = &quot;allow_tls&quot;
  }
}

# Mount to the subnets that will be using this efs volume
# Also attach sg's to restrict access to this volume
resource &quot;aws_efs_mount_target&quot; &quot;efs_data-app01&quot; {
  file_system_id = aws_efs_file_system.efs_data.id
  subnet_id      = module.vpc.private_app_subnet_01

  security_groups = [
    aws_security_group.allow_eks_cluster.id
  ]
}

resource &quot;aws_efs_mount_target&quot; &quot;efs_data-app02&quot; {
  file_system_id = aws_efs_file_system.efs_data.id
  subnet_id      = module.vpc.private_app_subnet_02

  security_groups = [
    aws_security_group.allow_eks_cluster.id
  ]
}
</code></pre>
<ol start="3">
<li>Create a Persistant Volume referencing the EFS Volume in kubernetes</li>
</ol>
<pre><code>data &quot;terraform_remote_state&quot; &quot;csi&quot; {
  backend = &quot;s3&quot;
  config = {
    bucket  = &quot;xva-${var.account_type}-terraform-${var.region_code}&quot;
    key     = &quot;${var.environment}/efs/driver/terraform.tfstate&quot;
    region  = var.region
    profile = var.profile
  }
}
resource &quot;kubernetes_persistent_volume&quot; &quot;efs_data&quot; {
  metadata {
    name = &quot;pv-efsdata&quot;

    labels = {
        app = &quot;example&quot;
    }
  }

  spec {
    access_modes = [&quot;ReadOnlyMany&quot;]

    capacity = {
      storage = &quot;25Gi&quot;
    }

    volume_mode                      = &quot;Filesystem&quot;
    persistent_volume_reclaim_policy = &quot;Retain&quot;
    storage_class_name               = data.terraform_remote_state.csi.outputs.storage_name

    persistent_volume_source {
      csi {
        driver        = data.terraform_remote_state.csi.outputs.csi_name
        volume_handle = aws_efs_file_system.efs_data.id
        read_only    = true
      }
    }
  }
}
</code></pre>
<ol start="4">
<li>Then create a deployment to fargate with the pod mounting the EFS volume</li>
</ol>
<pre><code>data &quot;terraform_remote_state&quot; &quot;efs_data_volume&quot; {
  backend = &quot;s3&quot;
  config = {
    bucket  = &quot;xva-${var.account_type}-terraform-${var.region_code}&quot;
    key     = &quot;${var.environment}/efs/volume/terraform.tfstate&quot;
    region  = var.region
    profile = var.profile
  }
}
resource &quot;kubernetes_persistent_volume_claim&quot; &quot;efs_data&quot; {
  metadata {
    name      = &quot;pv-efsdata-claim-${var.side}&quot;
    namespace = var.side
  }

  spec {
    access_modes       = [&quot;ReadOnlyMany&quot;]
    storage_class_name =  data.terraform_remote_state.csi.outputs.storage_name
    resources {
      requests = {
        storage = &quot;25Gi&quot;
      }
    }
    volume_name = data.terraform_remote_state.efs_data_volume.outputs.volume_name
  }
}

resource &quot;kubernetes_deployment&quot; &quot;example&quot; {
  timeouts {
    create = &quot;3m&quot;
    update = &quot;4m&quot;
    delete = &quot;2m&quot;
  }

  metadata {
    name      = &quot;deployment-example&quot;
    namespace = var.side

    labels = {
      app      = &quot;example&quot;
      platform = &quot;fargate&quot;
      subnet   = &quot;app&quot;
    }
  }

  spec {
    replicas = 1

    selector {
      match_labels = {
        app = &quot;example&quot;
      }
    }

    template {
      metadata {
        labels = {
          app      = &quot;example&quot;
          platform = &quot;fargate&quot;
          subnet   = &quot;app&quot;
        }
      }

      spec {
        volume {
          name = &quot;efs-data-volume&quot;
          
          persistent_volume_claim {
            claim_name = kubernetes_persistent_volume_claim.efs_data.metadata[0].name
            read_only  = true
          }
        }

        container {
          image = &quot;${var.nexus_docker_endpoint}/example:${var.docker_tag}&quot;
          name  = &quot;example&quot;

          env {
            name  = &quot;environment&quot;
            value = var.environment
          }
          env {
            name = &quot;dockertag&quot;
            value = var.docker_tag
          }

          volume_mount {
            name = &quot;efs-data-volume&quot;
            read_only = true
            mount_path = &quot;/appconf/&quot;
          }

          # liveness_probe {
          #   http_get {
          #     path = &quot;/health&quot;
          #     port = 443
          #   }

          #   initial_delay_seconds = 3
          #   period_seconds        = 3
          # }

          port {
            container_port = 443
          }
        }
      }
    }
  }
}
</code></pre>
<p>It can see the persistant volume in kuberenetes, I can see that it is claimed, heck I can even see that it attempts to mount the volume in the pod logs. However, I inevitably always see the following error when describing the pod:</p>
<pre><code>Volumes:
  efs-data-volume:
    Type:        PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:   pv-efsdata-claim-pre
    ReadOnly:    true
...
...
Events:
  Type     Reason       Age                  From                                                       Message
  ----     ------       ----                 ----                                                       -------
  Warning  FailedMount  11m (x629 over 23h)  kubelet, &lt;redacted-fargate-endpoint&gt;  Unable to attach or mount volumes: unmounted volumes=[efs-data-volume], unattached volumes=[efs-data-volume]: timed out waiting for the condition
  Warning  FailedMount  47s (x714 over 23h)  kubelet, &lt;redacted-fargate-endpoint&gt;  MountVolume.SetUp failed for volume &quot;pv-efsdata&quot; : kubernetes.io/csi: mounter.SetupAt failed: rpc error: code = InvalidArgument desc = Volume capability not supported
</code></pre>

<p>I finally have done it. I have successfully mounted an EFS Volume to a Fargate Pod (nearly 6 days later)! I was able to get the direction I need from this closed github issue: <a href="https://github.com/aws/containers-roadmap/issues/826" rel="nofollow noreferrer">https://github.com/aws/containers-roadmap/issues/826</a></p>
<p>It ended up being that I am using this module to build my eks cluster: <a href="https://registry.terraform.io/modules/cloudposse/eks-cluster/aws/0.29.0?tab=outputs" rel="nofollow noreferrer">https://registry.terraform.io/modules/cloudposse/eks-cluster/aws/0.29.0?tab=outputs</a></p>
<p>If you use the output &quot;security_group_id&quot; it outputs the &quot;Additional Security group&quot;. Which in my experience is good for absolutely nothing in aws. Not sure why it even exists when you can't do anything with it. The security group I needed to use was the &quot;Cluster security group&quot;. So I added the &quot;Cluster security group&quot;'s id on port 2049 ingress rule on the EFS volumes security groups mount point and BAM! I mounted the EFS volume to the deployed pod successfully.</p>
<p>The other important change was I changed the persistant volume type to be ReadWriteMany, since fargate apparently doesn't support ReadOnlyMany.</p>
