DEV Community

Cover image for EFS Data Across Multiple EKS Applications Using Terraform
Santanu Das
Santanu Das

Posted on

EFS Data Across Multiple EKS Applications Using Terraform

Table Of Contents

In the first part of this guide, we walked through setting up Amazon EFS with Amazon EKS using Terraform — covering file system provisioning, IAM integration, and CSI driver configuration. And just after I thought we are back in business, one of the developers very proudly announce: This won't work for all of our apps; at least two of the apps need to share the same data directory. 🤪

Went back to the drawing board with one subtle challenge:

How do we safely share the same EFS directory between multiple EKS applications while keeping our Terraform code clean, not over-engineered, declarative, and idempotent?

Eventually came up with some ideas: This article shows how did we solve that precisely — using distinct EFS access points per unique path, rather than per app, here at Zenler.

⚙️ The Problem

When multiple applications each create their own EFS access point, even if they use the same absolute path (e.g. /data/zenler-app), AWS treats those as separate mount namespaces.

That means:

Actual EFS path Access Point View
/data/zenler-app/file1.txt /file1.txt (inside both access points)
/data/zenler-app / (inside both access points)

However, EFS does not create a shared view between two access points mounted at the same root-path unless they were both created pointing to the same inode (directory object).

Example:

App Configured Path Actual Mount Namespace
tenant-app /data/zenler-app Isolated Access Point A
zenler-app /data/zenler-app Isolated Access Point B

That last bit is subtle: When we created the first access point, AWS created (if not already existing) the path /data/zenler-app and initialized it with UID/GID 1000:1000.
When we created the second access point, even though we wrote the same path (/data/zenler-app), AWS treats that as its own isolated root handle (like a different "view" into the same filesystem), not a symbolic reference to the existing directory.

In effect, each access point got its own chroot view that does not automatically unify — the same logical path string doesn’t mean same underlying inode reference. As a result, pods using these different access points can’t see each other’s files, because each access point’s root_directory.path becomes its own root scope.

✅ The Solution — Access Points per Distinct Path

The solution is simple but powerful: Deduplicate access points by path, so each unique EFS directory has exactly one access point.

1️⃣ First - Normalize the EFS volume paths

Created a local variable:

locals {
  efs_access_points = {
    for K2, V2 in var.apps_config : K2 => {
      path = (V2.efs_volume.path == null ? "/data/${K2}" : V2.efs_volume.path)
    } if V2.efs_volume.attached
  }
}
Enter fullscreen mode Exit fullscreen mode

In our setup, it outputs something like this:

{
  "tenant-app" = { "path" = "/data/zenler-app" }
  "zenler-app" = { "path" = "/data/zenler-app" }
}
Enter fullscreen mode Exit fullscreen mode

2️⃣ Create one EFS Access Point per unique path

resource "aws_efs_access_point" "this" {
  for_each = var.service_enabled ? toset(
    distinct(concat([
      for KV in values(local.efs_access_points) : values(KV)
    ]...))
  ) : []

  file_system_id = aws_efs_file_system.this[var.service_name].id

  posix_user {
    uid = 1000
    gid = 1000
  }

  root_directory {
    path = each.key
    creation_info {
      owner_uid   = 1000
      owner_gid   = 1000
      permissions = "0775"
    }
  }

  tags = {
    Name     = "${local.efs_template_name}ap-${replace(each.key, "/", "-")}"
    Module   = var.tf_module_name
    Resource = "aws_efs_access_point.this"
  }
}
Enter fullscreen mode Exit fullscreen mode

Now Terraform will only create one access point per distinct directory.
If two apps share /data/zenler-app, they’ll reuse the same EFS access point automatically.

3️⃣ Re-associate apps with the correct Access Point

Then, in efs_pvs module, only change the efs_access_points parameter like this:

# ------------------------------------------------------
# EFS-PVS local-module reference
# ------------------------------------------------------
module "efs_pvs" {
  source = "./modules//efs_pvs"
  efs_access_points = {
    for K1, V1 in local.efs_access_points : K1 => {
      apid = aws_efs_access_point.this[V1.path].id
      nmsp = var.apps_config[K1].name_space
    }
  }
  efs_dns_name       = aws_efs_file_system.this.dns_name
  efs_file_system_id = aws_efs_file_system.this.id
  efs_name_prefix    = local.efs_template_name
}
Enter fullscreen mode Exit fullscreen mode

and the rest of the things in the module/efs_pvs stay as it is like before.

And that's what actually it!! 🙌
(until the next call from the app teams 😬)

🧠 Achievements

Benefit Description
1️⃣ Shared access Multiple pods can see the same files in real time
2️⃣ Fewer resources Only one AP per path instead of one per app
3️⃣ Simpler IAM & POSIX model Each directory has a single enforcement layer
4️⃣ Idempotent Terraform Prevents churn and duplicate APs
5️⃣ Flexible design Seamless unique and shared paths

🔍 Quick Verification

aws efs describe-access-points --file-system-id <fs-id>
kubectl exec -it pod/tenant-app -- ls /mnt/efs
kubectl exec -it pod/zenler-app -- ls /mnt/efs
Enter fullscreen mode Exit fullscreen mode

✅ The Conclusion

By deduplicating EFS access points by unique path, you can safely allow multiple EKS applications to share the same directory on Amazon EFS — without namespace conflicts or code complexity.

This pattern keeps your Terraform configuration declarative, scalable, and ready for production.

Top comments (0)