Service Reference
EFS — Amazon Elastic File System
Control-plane emulation of EFS: file systems, mount targets, access points, policies, lifecycle and backup configuration, and tagging.
EFS — Amazon Elastic File System
Control-plane emulation of EFS: file systems, mount targets, access points,
file-system policies, lifecycle and backup configuration, tagging (current and
legacy APIs), and account preferences. The REST-JSON API is served under the
real AWS /2015-02-01/ path prefix, so unmodified AWS SDKs and the AWS CLI
work as-is.
EFS supports two modes:
live(default): each file system is backed by a named Docker volume (overcast-efs-<FileSystemId>), created onCreateFileSystemand removed onDeleteFileSystem. On startup, volumes are reconciled against persisted file systems: missing volumes are recreated, and volumes this instance created whose file system is gone are removed. The sweep is scoped to volumes carrying this instance’s identity, so two Overcasts sharing a Docker daemon cannot delete each other’s file data; with the defaultmemorystate backend that identity is minted afresh on every start, so a restart sweeps nothing at all and orphans wait fordocker volume prune --filter label=overcast.managed=true.EFS_DOCKER_SOCKEToverrides the Docker socket (defaults to the Lambda socket). Volume operations are best-effort: the control plane keeps working when Docker is unavailable, and reconciliation heals the gap when it returns.mock(opt out withOVERCAST_EFS_MODE=mock): metadata-only control plane, and EFS touches Docker for nothing.
Live mode is the default because it asks nothing of a machine that cannot
provide it. It creates a volume only for a file system someone created, and
without a reachable Docker daemon it creates nothing at all and behaves exactly
like mock — so the setting to reach for is mock, only if you want EFS kept
away from Docker deliberately.
Within live mode, OVERCAST_EFS_NFS=true additionally opts into the NFS
data plane: each mount target runs an NFS-Ganesha container exporting its file
system’s volume. See Mounting over NFS.
Behavior notes
- Data sharing works without NFS. In
livemode the backing volume is mounted into Lambda containers (FileSystemConfigs) and ECS task containers (efsVolumeConfiguration), scoped to the access point’s root directory (or the ECSrootDirectory) via Docker volume subpaths — Docker Engine 26+ required for subpath mounts. Because both sides mount the same named volume, a Lambda function and an ECS task genuinely share bytes with no NFS hop. Access points withCreationInfohave their root directory created in the volume with the declared ownership and permissions before the first mount; withoutCreationInfo, a missing directory makes the mount fail, as on AWS (seedocs/plans/efs-data-plane.md). - In
mockmode — and inlivemode while no Docker daemon is reachable — there is no data plane at all: mount targets are metadata with deterministic synthesized network fields (availability zone, IP address, ENI ID derived from the subnet ID). DescribeMountTargets.IpAddressis always synthetic, including with NFS exports on — the export is reached through its published host port or the export network, never through that address.- Resources follow the real lifecycle (
creating→available→deleting). Transitions complete inline with a real clock, so a resource is usable as soon as its create call returns; under a mock clock the intermediate states are observable. CreateFileSystemis idempotent onCreationTokenand enforces the performance/throughput-mode pairing rules (provisionedrequiresProvisionedThroughputInMibps;maxIOis incompatible withelasticthroughput and One Zone file systems).DeleteFileSystemreturnsFileSystemInUsewhile mount targets exist, and removes the file system’s access points, tags, and policy with it.- Mount targets are limited to one per availability zone/subnet per file
system (
MountTargetConflict) and at most 5 security groups; security groups are stored, not validated against EC2. - The file-system policy is stored and echoed verbatim (JSON-validated), but not enforced on requests.
PutBackupPolicystoresENABLED/DISABLEDdirectly without the transitionalENABLING/DISABLINGstates, and there is no AWS Backup integration.- Replication configuration APIs are not implemented and return
501. - Generated resource IDs are always long-form (
fs-/fsmt-/fsap-+ 17 hex chars) regardless of the account preference.
Mounting over NFS
OVERCAST_EFS_NFS=true (live mode only) gives every mount target a real,
mountable NFSv4 export. CreateMountTarget starts one NFS-Ganesha container
named overcast-efs-nfs-<MountTargetId> that exports the file system’s volume
and publishes container port 2049 on a free host port at or above
EFS_NFS_PORT_BASE; DeleteMountTarget removes it. Ganesha runs entirely in
userspace — no --privileged and no kernel modules — so the export works on
Linux, macOS and Windows Docker hosts alike. The container is granted exactly
one Linux capability, CAP_DAC_READ_SEARCH: Ganesha’s VFS backend resolves NFS
file handles with open_by_handle_at(), which the kernel gates on it. Without
it the export accepts one mount and then serves nothing.
It is opt-in because most testing does not need it: Lambda and ECS already share bytes through the volume, and an export costs a container and a port per mount target.
The mount target stays creating until the export answers an NFSv4 call, then
becomes available — so a successful DescribeMountTargets means the export
is genuinely serving. An export that never answers settles the mount target in
error instead, with a warning naming the container whose logs say why. The
resource is never stranded in creating, and it never reports available
without a data plane behind it. (With OVERCAST_EFS_NFS off there is no export
to fail: mount targets go straight to available, as before.)
Where to mount from:
| Client | Address |
|---|---|
| The Docker host | localhost:<published port> (DescribeMountTargets does not report it — read it from docker ps) |
| A sibling container | The mount target’s DNS name on the shared data plane (OVERCAST_NETWORK), or the export container’s address there |
Pseudo-paths follow the file system’s access points: / is the volume root,
and /<AccessPointId> is that access point’s root directory, squashed onto
its PosixUser when it declares one. Two consequences worth knowing:
- An empty directory named after each access point appears in the file
system root. Ganesha grafts a pseudo-path onto a name that already exists
in the exported volume, so the export container creates one anchor directory
per access point before it starts. Mounting
/<AccessPointId>shows the access point’s root directory, never the anchor — the anchor is only visible to something listing the volume root. - Exports are fixed when the mount target starts. Ganesha reloads exports
only on restart, and churning a live NFS server on every
CreateAccessPointwould break clients holding open files. An access point created after the mount target therefore has no pseudo-path: delete and recreate the mount target to pick it up. Its data is reachable in the meantime at the equivalent path under the root export (an access point rooted at/app/datais/app/databelow/), just without thePosixUsersquash.
Mounting the export requires CAP_SYS_ADMIN on the client, which is the
client’s business — the server side needs only the one capability above.
| Variable | Default | Purpose |
|---|---|---|
OVERCAST_EFS_NFS | false | Opt into exports (needs live mode, which is the default) |
EFS_NFS_PORT_BASE | 22049 | First host port considered for publishing 2049 |
EFS_NFS_IMAGE | digest-pinned NFS-Ganesha | Override the export image |
OVERCAST_NETWORK | overcast | Docker network the export containers join, shared with every other container Overcast starts |
CloudFormation
AWS::EFS::FileSystem, AWS::EFS::MountTarget, and AWS::EFS::AccessPoint
are fully supported, including FileSystemPolicy, LifecyclePolicies,
BackupPolicy, FileSystemProtection, and tag updates. Ref returns the
resource ID; GetAtt supports Arn/FileSystemId (file system),
Id/IpAddress (mount target), and AccessPointId/Arn (access point).
Property changes that replace on real AWS (encryption, performance mode,
subnet, POSIX identity, …) trigger replacement here too.
Summary
| Category | ✅ Supported | ❌ Unsupported |
|---|---|---|
| File systems | 5 | |
| Mount targets | 5 | |
| Access points | 3 | |
| Lifecycle | 2 | |
| Backup | 2 | |
| Policy | 3 | |
| Tags | 6 | |
| Account | 2 | |
| Replication | 3 |
Endpoints
File systems
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
CreateFileSystem | ✅ Supported | Creation-token idempotency, performance/throughput mode validation, One Zone metadata, optional Backup flag and inline tags; lifecycle creating → available | docs |
DescribeFileSystems | ✅ Supported | Filters by FileSystemId or CreationToken; Marker/MaxItems pagination | docs |
UpdateFileSystem | ✅ Supported | Updates ThroughputMode and ProvisionedThroughputInMibps with pairing validation | docs |
DeleteFileSystem | ✅ Supported | Rejects deletion while mount targets exist (FileSystemInUse); cascades access points, tags, and policy | docs |
UpdateFileSystemProtection | ✅ Supported | Stores ReplicationOverwriteProtection | docs |
Mount targets
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
CreateMountTarget | ✅ Supported | Serves a real NFSv4 export with OVERCAST_EFS_NFS=true, metadata only otherwise. One mount target per AZ/subnet enforced; AZ and IP are synthesized deterministically from the subnet ID | docs |
DescribeMountTargets | ✅ Supported | Lookup by FileSystemId, MountTargetId, or AccessPointId; Marker/MaxItems pagination | docs |
DeleteMountTarget | ✅ Supported | Lifecycle deleting → removed | docs |
DescribeMountTargetSecurityGroups | ✅ Supported | docs | |
ModifyMountTargetSecurityGroups | ✅ Supported | Enforces the 5-security-group limit; groups are stored, not validated against EC2 | docs |
Access points
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
CreateAccessPoint | ✅ Supported | Client-token idempotency conflict, PosixUser/RootDirectory stored, inline tags; lifecycle creating → available | docs |
DescribeAccessPoints | ✅ Supported | Filters by AccessPointId or FileSystemId (mutually exclusive); NextToken/MaxResults pagination | docs |
DeleteAccessPoint | ✅ Supported | docs |
Lifecycle
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
PutLifecycleConfiguration | ✅ Supported | Validates transition enums and the one-transition-per-policy rule; storage-class transitions are metadata only | docs |
DescribeLifecycleConfiguration | ✅ Supported | docs |
Backup
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
PutBackupPolicy | ✅ Supported | Stores ENABLED/DISABLED directly (no ENABLING/DISABLING transitional states); no AWS Backup integration | docs |
DescribeBackupPolicy | ✅ Supported | docs |
Policy
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
PutFileSystemPolicy | ✅ Supported | Stores the policy document (JSON-validated); not enforced on requests | docs |
DescribeFileSystemPolicy | ✅ Supported | docs | |
DeleteFileSystemPolicy | ✅ Supported | docs |
Tags
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
TagResource | ✅ Supported | Accepts file-system and access-point IDs or ARNs | docs |
UntagResource | ✅ Supported | docs | |
ListTagsForResource | ✅ Supported | docs | |
CreateTags | ✅ Supported | Legacy alias of TagResource (file systems only) | docs |
DeleteTags | ✅ Supported | Legacy alias of UntagResource (file systems only) | docs |
DescribeTags | ✅ Supported | Legacy alias of ListTagsForResource (file systems only) | docs |
Account
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
DescribeAccountPreferences | ✅ Supported | Defaults to LONG_ID | docs |
PutAccountPreferences | ✅ Supported | Stores the preference; generated IDs are always long-form | docs |
Replication
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
CreateReplicationConfiguration | ❌ Unsupported | docs | |
DeleteReplicationConfiguration | ❌ Unsupported | docs | |
DescribeReplicationConfigurations | ❌ Unsupported | docs |