Amazon S3 Files went GA in April 2026. It lets you mount an S3 bucket as a proper NFS file system on EC2 — ls, cat, vim, the works. Your data never leaves S3, but applications interact with it using standard POSIX file operations instead of the S3 API.
That's a big deal for workloads that expect a filesystem (legacy apps, ML training pipelines, shared datasets). But it also means you now have two access planes to the same data: the S3 API and the NFS mount. Each has its own authorization model, and they don't automatically agree with each other.
This post focuses on the security side: how the layers stack, where the gaps are, and how to lock it down properly.
The Security Layer Cake
S3 Files has five layers of access control. A request must pass all of them to succeed:
- IAM identity policies — what the caller's role/user is allowed to do
- File system resource policies — what the file system itself allows
- S3 bucket policies — what the underlying bucket allows (for read-path optimization)
- POSIX permissions — Unix-style uid/gid/mode bits on files and directories
- Security groups — network-level firewall between compute and mount targets

Miss any one of these and you'll either lock yourself out or leave a hole. Let's go through each.
Layer 1: IAM Identity Policies
S3 Files introduces three new IAM actions for client access (the NFS mount path):
| Action | What it grants |
|---|---|
s3files:ClientMount | Read-only access to the file system |
s3files:ClientWrite | Write access to the file system |
s3files:ClientRootAccess | Root user (uid 0) access on the file system |
These are separate from the S3 API actions (s3:GetObject, s3:PutObject, etc.). A role can have full S3 API access to the bucket but zero NFS access if it lacks the s3files:Client* actions.
AWS provides managed policies to get started:
AmazonS3FilesFullAccess— manage file systems, mount targets, access pointsAmazonS3FilesReadOnlyAccess— view configurations onlyAmazonS3FilesClientFullAccess— mount, read, write, and root access
Least-Privilege Example
For an application that needs to read and write files but should never operate as root:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3files:ClientMount",
"s3files:ClientWrite"
],
"Resource": "arn:aws:s3files:eu-west-2:111122223333:file-system/fs-0abc123def456"
}
]
}No s3files:ClientRootAccess means the mount operates as the POSIX user mapped to the connecting identity — not root. Files owned by root are read-only to this role.
The Read-Path Optimization
S3 Files has an "intelligent read routing" feature that reads file data directly from the underlying S3 bucket for performance. For this to work, the EC2 instance's IAM role also needs s3:GetObject on the bucket:
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}The mount helper adds this automatically if you use the recommended setup, but it's worth knowing it exists — it means the role has S3 API read access to the bucket, not just NFS access.
Layer 2: File System Resource Policies
Like S3 bucket policies, S3 Files supports resource-based policies attached directly to the file system. These control what clients can do once connected.
A file system with no explicit policy uses a permissive default. Always attach an explicit policy.
Read-Only Policy
{
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111122223333:role/AppReadOnly"
},
"Action": [
"s3files:ClientMount"
]
}
]
}This role can mount and read. It cannot write or access files as root.
Deny Root Access Globally
{
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": "*" },
"Action": [
"s3files:ClientMount",
"s3files:ClientWrite"
]
},
{
"Effect": "Deny",
"Principal": { "AWS": "*" },
"Action": "s3files:ClientRootAccess",
"Condition": {
"StringNotEquals": {
"aws:PrincipalArn": "arn:aws:iam::111122223333:role/FileSystemAdmin"
}
}
}
]
}Everyone can mount and write, but only FileSystemAdmin gets root. This is the pattern I'd recommend for most setups.
Access Points
S3 Files access points let you scope access further. Each access point can enforce a specific POSIX identity (uid/gid) for all requests through it, regardless of the connecting role. Use the s3files:AccessPointArn condition key to restrict which access point a policy applies to.

Layer 3: S3 Bucket Policies
Your S3 bucket still has its own bucket policy. Because S3 Files reads data from the bucket (for the intelligent read routing path), the bucket policy must not deny access from the compute role or the file system.
Common mistake: a bucket policy with an explicit Deny on s3:GetObject for principals outside a specific VPC endpoint will block the read-path optimization. The file system itself accesses the bucket from within AWS's infrastructure, not from your VPC endpoint.
Layer 4: POSIX Permissions
After IAM authorization succeeds, S3 Files enforces standard Unix permissions: owner, group, others, with read/write/execute bits. This is the same model as any Linux filesystem.
Key points:
- New files inherit the default permissions based on the creating process's umask
- Root access (uid 0) bypasses POSIX permission checks — which is why
s3files:ClientRootAccessis so sensitive - Access points can force a specific uid/gid for all operations, overriding whatever the connecting role would normally map to
- Ownership matters: if your app creates files as uid 1000 and another service connects as uid 2000, the second service can't read those files unless group or other permissions allow it
Practical Pattern: Shared Dataset
For a shared ML training dataset where multiple teams need read access but only the data pipeline should write:
- Data pipeline role → access point with uid 1000,
ClientMount+ClientWrite - Training roles → access point with uid 2000,
ClientMountonly - Set directory permissions to
755(owner rwx, group/other rx) - Set file permissions to
644(owner rw, group/other r)
The training roles can read everything but can't modify the dataset.
Layer 5: Security Groups
S3 Files uses mount targets (similar to EFS) that live in your VPC subnets. Security groups control which compute resources can reach these mount targets over the network.
resource "aws_security_group" "s3_files_mount_target" {
name_prefix = "s3-files-mt-"
vpc_id = aws_vpc.main.id
ingress {
from_port = 2049
to_port = 2049
protocol = "tcp"
security_groups = [aws_security_group.app_instances.id]
description = "NFS from app instances only"
}
}
Encryption
At Rest
S3 Files encrypts all data and metadata at rest automatically. Two options:
- AWS-owned KMS key (default) — zero config, no cost, AWS manages the key lifecycle
- Customer-managed KMS key — you control the key policy, rotation, and can revoke access by disabling the key
For regulated workloads, use a customer-managed key. It gives you an independent kill switch: disable the KMS key and the file system becomes unreadable, even if IAM policies still allow access.
resource "aws_kms_key" "s3_files" {
description = "S3 Files encryption key"
enable_key_rotation = true
policy = data.aws_iam_policy_document.s3_files_key_policy.json
}In Transit
Data between your EC2 instance and the mount target is encrypted in transit using TLS. The S3 Files mount helper handles this transparently — you don't need to configure certificates or TLS settings.
The intelligent read routing path (direct reads from S3) also uses TLS. All data paths are encrypted in transit by default with no opt-out.
Common Security Mistakes
1. Using the FullAccess Managed Policy for Applications
AmazonS3FilesClientFullAccess grants root. Your app doesn't need root. Write a custom policy with only ClientMount and ClientWrite.
2. No Explicit File System Policy
Without one, the default is permissive. Always attach a policy that explicitly names which principals get which actions.
3. Forgetting the Bucket Policy Interaction
The S3 bucket policy and the file system policy are independent. A restrictive bucket policy can break the read-path optimization without any obvious error — reads just get slower.
4. Wide-Open Security Groups
Don't allow 0.0.0.0/0 on port 2049. Scope inbound NFS to the specific security groups of instances that need to mount.
5. Ignoring POSIX Permissions
IAM says "yes" but POSIX says "no" → access denied. If your app creates files as one uid and another service reads as a different uid, you'll get silent permission failures. Use access points to enforce consistent identities.
Audit and Monitoring
S3 Files operations appear in CloudTrail. Look for:
s3files:CreateFileSystem,s3files:DeleteFileSystem— lifecycle eventss3files:CreateMountTarget— new network exposures3files:PutFileSystemPolicy— policy changes
For data-plane monitoring (who's reading/writing what), enable S3 server access logging on the underlying bucket. NFS reads that go through the intelligent read routing path show up as GetObject calls from the file system's internal role.
Wrapping Up
S3 Files is genuinely useful — it removes the "do I use EFS or S3?" decision for many workloads. But the security model is more complex than either EFS or plain S3 alone because you're layering NFS access control on top of S3's existing model.
The short version:
- Write least-privilege IAM policies — no
ClientRootAccessfor apps - Attach an explicit file system resource policy — don't rely on defaults
- Check your bucket policy doesn't block the read-path optimization
- Use access points to enforce POSIX identities per consumer
- Lock down security groups to port 2049 from specific source groups
- Use a customer-managed KMS key if you need an independent kill switch
- Monitor CloudTrail for
s3files:*events
Get those right and you've got a filesystem that's as secure as your S3 bucket — which, if you've been following AWS best practices, should be pretty locked down already.