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
}
}
In our setup, it outputs something like this:
{
"tenant-app" = { "path" = "/data/zenler-app" }
"zenler-app" = { "path" = "/data/zenler-app" }
}
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"
}
}
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
}
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
✅ 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)