How do I validate IAM permissions for Amazon S3 Files before enabling bidirectional sync?
Amazon S3 Files requires two IAM roles for bidirectional sync. A common misconfiguration — using aws:SourceAccount instead of aws:ResourceAccount in the sync role's inline policy — causes files to silently get stuck in PendingExport state despite successful file system creation and mounting. This article explains how to configure both roles correctly, validate permissions before enabling sync, and set up CloudWatch alarms to catch permission issues early.
Short description
Amazon S3 Files (GA since April 2026) requires two IAM roles to function: a sync role that the service assumes to read from and write to your S3 bucket, and a compute role attached to your EC2 instance or Lambda function for client access. Misconfiguring either role — particularly confusing aws:SourceAccount with aws:ResourceAccount in condition keys — may cause sync operations to fail silently after file system creation succeeds. This article explains how to configure both roles correctly and validate permissions before enabling sync.
Resolution
Common symptom: File system creates and mounts without error, but files written to the mount remain in a PendingExport state. CloudTrail shows no errors for the CreateFileSystem event itself.
Understand the two IAM roles
S3 Files uses two distinct IAM roles:
| Role | Purpose | Who assumes it | Key condition |
|---|---|---|---|
| Sync role | Reads/writes objects in your S3 bucket, manages EventBridge rules | S3 Files service (elasticfilesystem.amazonaws.com) | aws:ResourceAccount in inline policy |
| Compute role | Mounts the file system, reads objects directly from S3 for optimized performance | Your EC2 instance or Lambda function | s3files:ClientMount, s3files:ClientWrite |
Configure the sync role
The sync role has two parts: a trust policy and an inline permissions policy. When you create a file system using the AWS Management Console, S3 Files creates this role automatically. If you're using CLI, CDK, or CloudFormation, you must create it manually.
For the full policy templates, see IAM role for accessing your bucket from the file system.
Recommendation: Use the IAM policy from the S3 Files prerequisites documentation as-is. The wildcard patterns (s3:GetObject*, s3:PutObject*) are intentional — restricting to individual actions risks missing permissions that S3 Files needs internally.
The critical detail: the trust policy and inline policy use different condition keys for the same role. This is where most misconfigurations occur.
Avoid the aws:SourceAccount vs aws:ResourceAccount pitfall
This is the most common misconfiguration. Both condition keys appear in the same IAM role, but they serve different purposes:
| Where | Correct condition key | Why |
|---|---|---|
| Trust policy | aws:SourceAccount | Verifies which account's S3 Files service is requesting to assume the role |
| Inline policy (S3 permissions) | aws:ResourceAccount | Verifies which account owns the S3 bucket being accessed |
Why this matters: When S3 Files assumes your role and makes S3 API calls, the source of those calls is the S3 Files service — not your account. If you use aws:SourceAccount in the inline policy, the condition evaluates the S3 Files service's account ID against your account ID. They don't match, so every S3 request is denied. (See AWS global condition context keys for details on how aws:SourceAccount vs aws:ResourceAccount behave.)
The file system creates successfully. It mounts successfully. But exports may remain in a PendingExport state because the underlying S3 operations are denied.
How to check: Open your sync role in the IAM console. In the Permissions tab, expand the inline policy. Search for SourceAccount. If it appears anywhere outside the trust policy, replace it with ResourceAccount.
aws iam get-role-policy --role-name S3FilesSyncRole --policy-name <policy-name> \ | grep -i "SourceAccount"
If this returns a match, that's the issue — the inline policy should only use aws:ResourceAccount.
Configure the compute role
Your EC2 instance or Lambda must have an IAM role with two sets of permissions. For full policy templates, see IAM role for attaching your file system to AWS compute resources.
-
Client access — attach one of the AWS managed policies:
AmazonS3FilesClientFullAccess,AmazonS3FilesClientReadWriteAccess, orAmazonS3FilesClientReadOnlyAccess -
Direct S3 read — an inline policy granting
s3:GetObject,s3:GetObjectVersion,s3:GetObjectVersionTagging,s3:ListBucket, ands3:ListBucketVersionson your bucket
Note: The documented sync role policy uses s3:GetObject* (wildcard), which covers all Get operations including s3:GetObjectVersionTagging. If you write explicit permissions instead of wildcards (e.g., listing s3:GetObject, s3:GetObjectVersion individually), ensure you also include s3:GetObjectVersionTagging — S3 Files needs to read version tags during sync. Missing it causes partial sync failures where some objects sync and others don't.
Validate permissions before enabling sync
Run these checks before creating your file system:
1. Verify bucket prerequisites:
# Check versioning is enabled aws s3api get-bucket-versioning --bucket my-bucket # Check encryption type (must be SSE-S3 or SSE-KMS) aws s3api get-bucket-encryption --bucket my-bucket
2. Test the sync role can access your bucket:
Important: The sync role's trust policy only allows the S3 Files service principal (elasticfilesystem.amazonaws.com) to assume it. You won't be able to assume it from your CLI session directly. Temporarily add your IAM user/role as a trusted entity, run the tests below, then remove it before creating the file system.
# Assume the sync role CREDS=$(aws sts assume-role \ --role-arn arn:aws:iam::111122223333:role/S3FilesSyncRole \ --role-session-name test-sync) # Export credentials export AWS_ACCESS_KEY_ID=$(echo $CREDS | jq -r '.Credentials.AccessKeyId') export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq -r '.Credentials.SecretAccessKey') export AWS_SESSION_TOKEN=$(echo $CREDS | jq -r '.Credentials.SessionToken') # Test bucket-level operations aws s3api list-objects-v2 --bucket my-bucket --max-keys 1 # Test object-level operations aws s3api get-object --bucket my-bucket --key test-file.txt /dev/null # Test versioning operations aws s3api list-object-versions --bucket my-bucket --max-keys 1
If any of these commands return AccessDenied, review the inline policy condition keys and bucket policy for explicit denies.
3. Check the bucket policy doesn't block access:
aws s3api get-bucket-policy --bucket my-bucket --output text | jq .
Look for Deny statements that might block the S3 Files service principal or your sync role ARN.
4. Verify KMS access (if using SSE-KMS):
# Get the KMS key ID from bucket encryption config aws s3api get-bucket-encryption --bucket my-bucket # Test decrypt with the assumed sync role aws kms decrypt \ --key-id arn:aws:kms:us-west-2:111122223333:key/your-key-id \ --ciphertext-blob fileb://test-blob
Monitor sync health with CloudWatch after creation
After creating your file system, set up CloudWatch alarms on these key metrics (namespace: AWS/S3/Files, dimension: FileSystemId) to catch permission issues early:
| Metric | What it tells you | Alarm threshold |
|---|---|---|
ImportFailures | Objects that failed to import (often IAM permission issues) | > 0 for 5 minutes |
ExportFailures | Files that failed to export and won't be retried | > 0 for 5 minutes |
PendingExports | Files waiting to sync to S3 — a growing count indicates stuck exports | Increasing over 30 minutes |
The S3 Files client also emits connectivity metrics (namespace: efs-utils/S3Files) on the compute side:
| Metric | What it tells you |
|---|---|
S3BucketAccessible | 1 = compute role has correct S3 permissions, 0 = permission issue |
S3BucketReachable | 1 = bucket exists and is reachable, 0 = network or bucket issue |
NFSConnectionAccessible | 1 = NFS mount is healthy, 0 = connectivity issue |
Recommended alarm: Create a CloudWatch alarm on S3BucketAccessible < 1 — this fires immediately if your compute role loses S3 read permissions, catching the exact class of IAM misconfiguration that causes sync failures.
aws cloudwatch put-metric-alarm \ --alarm-name "S3Files-BucketAccess-Check" \ --namespace "efs-utils/S3Files" \ --metric-name "S3BucketAccessible" \ --statistic Minimum \ --period 60 \ --evaluation-periods 3 \ --threshold 1 \ --comparison-operator LessThanThreshold \ --alarm-actions arn:aws:sns:us-west-2:111122223333:my-alerts
Related information
- Prerequisites for S3 Files
- How S3 Files works with IAM
- AWS managed policies for Amazon S3 Files
- Monitoring S3 Files with Amazon CloudWatch
- Troubleshooting S3 Files
- AWS global condition context keys
- Creating an S3 file system
Note: S3 Files requires the amazon-efs-utils client version 3.0.0 or above. If you see mount.s3files: command not found, ensure the client is installed and updated.
Relevant content
- Accepted Answer
asked 4 years ago
