AWS has introduced S3 Files, which allows you to access S3 buckets as a filesystem across compute services such as EC2, Lambda, ECS and EKS.
Previously, working with S3 followed a download-process-upload pattern:
Download objects from S3 to local storage
Process them
Upload the results back to S3
With S3 Files, this pattern is no longer necessary. Applications can interact with S3 objects as if they were a local filesystem, making S3 behave like a "shared drive" across your compute environments.
AI Agents
AI agents often need to read and write data across multiple steps. With S3 Files, they can work directly on S3 as a filesystem, making it easier to share state and coordinate without extra syncing.
ML pipelines
ML workflows such as preprocessing, feature engineering, and model training work primarily with files. Every run typically involves pulling data from S3, processing it locally, and writing the results back. With S3 files, data can be accessed and modified in place, removing the unnecessary data movement.

This section provides CloudFormation templates for S3 FilesSystem and its integration with Lambda, ECS task, and EC2.
The following values used in the examples are arbitrary and can be adjusted as needed.
UID, GID (non-root Linux user)
Access point root path
Mount path
S3 FilesSystem
AWSTemplateFormatVersion: "2010-09-09"
Description: S3 Files
Parameters:
S3BucketName:
Type: String
VpcId:
Type: AWS::EC2::VPC::Id
SubnetId:
Type: AWS::EC2::Subnet::Id
Ec2AmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
Resources:
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref S3BucketName
VersioningConfiguration:
Status: Enabled
S3FilesSystem:
Type: AWS::S3Files::FileSystem
Properties:
Bucket: !GetAtt S3Bucket.Arn
RoleArn: !GetAtt S3FilesSystemRole.Arn
# For production use, consider creating mount targets in multiple AZs for high availability.
S3FilesMountTarget:
Type: AWS::S3Files::MountTarget
Properties:
FileSystemId: !Ref S3FilesSystem
SubnetId: !Ref SubnetId
SecurityGroups:
- !Ref S3FilesSecurityGroup
S3FilesSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub "${AWS::StackName}-s3-files-sg"
VpcId: !Ref VpcId
S3FilesSystemRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: elasticfilesystem.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: !Sub "${AWS::StackName}-s3-files"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- s3:ListBucket
- s3:ListBucketVersions
Resource:
- !Sub "arn:aws:s3:::${S3Bucket}"
Condition:
StringEquals:
aws:ResourceAccount: !Ref AWS::AccountId
- Effect: Allow
Action:
- s3:AbortMultipartUpload
- s3:DeleteObject*
- s3:GetObject*
- s3:List*
- s3:PutObject*
Resource:
- !Sub "arn:aws:s3:::${S3Bucket}/*"
Condition:
StringEquals:
aws:ResourceAccount: !Ref AWS::AccountId
- Effect: Allow
Action:
- kms:GenerateDataKey
- kms:Encrypt
- kms:Decrypt
- kms:ReEncryptFrom
- kms:ReEncryptTo
Resource:
- !Sub "arn:aws:kms:${AWS::Region}:${AWS::AccountId}:*"
Condition:
StringLike:
kms:ViaService: !Sub "s3.${AWS::Region}.amazonaws.com"
"kms:EncryptionContext:aws:s3:arn":
- !Sub "arn:aws:s3:::${S3Bucket}"
- !Sub "arn:aws:s3:::${S3Bucket}/*"
- Effect: Allow
Action:
- events:DeleteRule
- events:DisableRule
- events:EnableRule
- events:PutRule
- events:PutTargets
- events:RemoveTargets
Resource:
- !Sub "arn:aws:events:${AWS::Region}:${AWS::AccountId}:rule/DO-NOT-DELETE-S3-Files*"
Condition:
StringEquals:
events:ManagedBy: elasticfilesystem.amazonaws.com
- Effect: Allow
Action:
- events:DescribeRule
- events:ListRuleNamesByTarget
- events:ListRules
- events:ListTargetsByRule
Resource:
- !Sub "arn:aws:events:${AWS::Region}:${AWS::AccountId}:rule/*"Enable S3 bucket versioning.
The mount target for S3 Files must to be within the same VPC as your compute services.
Lambda
# ===== Lambda =====
S3FilesAccessPointLambda:
Type: AWS::S3Files::AccessPoint
Properties:
FileSystemId: !Ref S3FilesSystem
PosixUser:
Gid: 1000
Uid: 1000
RootDirectory:
Path: "/lambda"
# Allow User ID 1000 to read/write/execute in the root directory
CreationPermissions:
OwnerGid: 1000
OwnerUid: 1000
Permissions: "755"
S3FilesSecurityGroupIngressLambda:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref S3FilesSecurityGroup
IpProtocol: tcp
FromPort: 2049
ToPort: 2049
SourceSecurityGroupId: !Ref LambdaSecurityGroup
LambdaSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub "${AWS::StackName}-lambda-sg"
VpcId: !Ref VpcId
# S3 File System uses NFS (port 2049) over the VPC
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 2049
ToPort: 2049
DestinationSecurityGroupId: !Ref S3FilesSecurityGroup
# NOTE: Ensure the S3 VPC Endpoint or NAT Gateway is configured to allow access between VPC and S3
Lambda:
Type: AWS::Lambda::Function
DependsOn: S3FilesMountTarget
Properties:
FunctionName: s3-files-demo
Role: !GetAtt LambdaExecutionRole.Arn
Handler: index.lambda_handler
Runtime: python3.14
MemorySize: 512
Timeout: 30
Code:
ZipFile: |
import os
import json
import time
MOUNT_PATH = "/mnt/lambda"
def lambda_handler(event, context):
timestamp = int(time.time())
filename = f"demo-{timestamp}.txt"
filepath = os.path.join(MOUNT_PATH, filename)
content = f"Hello from Lambda! Written at {timestamp}"
with open(filepath, "w") as f:
f.write(content)
files = os.listdir(MOUNT_PATH)
return {
"statusCode": 200,
"body": json.dumps({"files_in_mount": files[:20]}),
}
VpcConfig:
SecurityGroupIds:
- !Ref LambdaSecurityGroup
SubnetIds:
- !Ref SubnetId
# Mount the S3 Files System at /mnt/lambda
FileSystemConfigs:
- Arn: !GetAtt S3FilesAccessPointLambda.AccessPointArn
LocalMountPath: /mnt/lambda
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
- arn:aws:iam::aws:policy/AmazonS3FilesClientReadWriteAccess
Policies:
- PolicyName: !Sub "${AWS::StackName}-LambdaS3FilesAccess"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- s3:GetObject
- s3:GetObjectVersion
Resource: !Sub "arn:aws:s3:::${S3Bucket}/*"CreationPermissions for S3Files AccessPoint should be set to enable the user (UID 1000) to create S3 prefix (/lambda), as well as perform read and write operations on S3 objects under that prefix.
FileSystemConfigs for Lambda must be configured and the LocalMountPath defines where it is accessible within the Lambda function.
Inbound traffic from Lambda for S3 Files Mount Target's security group.
Outbound traffic to S3 Files Mount Target for Lambda's security group.
ECS Task
# ===== ECS Task =====
S3FilesAccessPointEcs:
Type: AWS::S3Files::AccessPoint
Properties:
FileSystemId: !Ref S3FilesSystem
PosixUser:
Gid: 1001
Uid: 1001
RootDirectory:
Path: "/ecs"
# Allow User ID 1001 to read/write/execute in the root directory
CreationPermissions:
OwnerGid: 1001
OwnerUid: 1001
Permissions: "755"
S3FilesSecurityGroupIngressECS:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref S3FilesSecurityGroup
IpProtocol: tcp
FromPort: 2049
ToPort: 2049
SourceSecurityGroupId: !Ref EcsTaskSecurityGroup
EcsTaskSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub "${AWS::StackName}-ecs-task-sg"
VpcId: !Ref VpcId
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: ECR image pull and CloudWatch Logs via NAT Gateway
- IpProtocol: tcp
FromPort: 2049
ToPort: 2049
DestinationSecurityGroupId: !Ref S3FilesSecurityGroup
Description: S3 Files mount target
EcrRepository:
Type: AWS::ECR::Repository
Properties:
RepositoryName: !Sub "${AWS::StackName}"
# NOTE: Ensure the S3 VPC Endpoint or NAT Gateway is configured to allow access between VPC and S3
# NOTE: Ensure the ECR VPC endpoint or NAT Gateway is configured to allow access for image pulls from ECR
EcsCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Sub "${AWS::StackName}-cluster"
EcsLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/ecs/${AWS::StackName}"
RetentionInDays: 7
EcsTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
EcsTaskRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonS3FilesClientReadWriteAccess
Policies:
- PolicyName: !Sub "${AWS::StackName}-ECSTaskS3Access"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- s3:GetObject
- s3:GetObjectVersion
Resource: !Sub "arn:aws:s3:::${S3Bucket}/*"
EcsTaskDefinition:
Type: AWS::ECS::TaskDefinition
DependsOn: S3FilesMountTarget
Properties:
Family: !Sub "${AWS::StackName}-s3-files"
RequiresCompatibilities:
- FARGATE
NetworkMode: awsvpc
Cpu: "256"
Memory: "512"
ExecutionRoleArn: !GetAtt EcsTaskExecutionRole.Arn
TaskRoleArn: !GetAtt EcsTaskRole.Arn
Volumes:
- Name: s3-files
S3FilesVolumeConfiguration:
FileSystemArn: !GetAtt S3FilesSystem.FileSystemArn
AccessPointArn: !GetAtt S3FilesAccessPointEcs.AccessPointArn
ContainerDefinitions:
- Name: !Sub "${AWS::StackName}-s3-files"
Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${EcrRepository}:latest"
Essential: true
User: "1001:1001"
MountPoints:
- SourceVolume: s3-files
ContainerPath: /mnt/ecs
ReadOnly: false
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref EcsLogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: ecs
EcsService:
Type: AWS::ECS::Service
DependsOn: S3FilesMountTarget
Properties:
Cluster: !Ref EcsCluster
TaskDefinition: !Ref EcsTaskDefinition
LaunchType: FARGATE
DesiredCount: 1
NetworkConfiguration:
AwsvpcConfiguration:
Subnets:
- !Ref SubnetId
SecurityGroups:
- !Ref EcsTaskSecurityGroup# ===== Example in ECS task =====
import json
import os
import time
MOUNT_PATH = "/mnt/ecs"
def main():
timestamp = int(time.time())
filename = f"demo-{timestamp}.txt"
filepath = os.path.join(MOUNT_PATH, filename)
content = f"Hello from ECS! Written at {timestamp}"
with open(filepath, "w") as f:
f.write(content)
files = os.listdir(MOUNT_PATH)
print(json.dumps({"files_in_mount": files[:20]}))
if __name__ == "__main__":
main()CreationPermissions for S3Files AccessPoint should be set to enable the user (UID 1001) to create S3 prefix (/ecs), as well as perform read and write operations on S3 objects under that prefix.
MountPoints in ContainerDefinitions must be configured and the ContainerPath specifies where S3 Files is mounted inside the container.
Inbound traffic from ECS Task for S3 Files Mount Target's security group.
Outbound traffic to S3 Files Mount Target for ECS Task's security group.
EC2
# ===== EC2 =====
S3FilesAccessPointEc2:
Type: AWS::S3Files::AccessPoint
Properties:
FileSystemId: !Ref S3FilesSystem
PosixUser:
Gid: 1002
Uid: 1002
RootDirectory:
Path: "/ec2"
CreationPermissions:
OwnerGid: 1002
OwnerUid: 1002
Permissions: "755"
S3FilesSecurityGroupIngressEc2:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref S3FilesSecurityGroup
IpProtocol: tcp
FromPort: 2049
ToPort: 2049
SourceSecurityGroupId: !Ref Ec2SecurityGroup
Ec2SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub "${AWS::StackName}-ec2-sg"
VpcId: !Ref VpcId
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 2049
ToPort: 2049
DestinationSecurityGroupId: !Ref S3FilesSecurityGroup
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: SSM and S3 via NAT Gateway
Ec2InstanceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- arn:aws:iam::aws:policy/AmazonS3FilesClientReadWriteAccess
Policies:
- PolicyName: !Sub "${AWS::StackName}-Ec2S3Access"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- s3:GetObject
- s3:GetObjectVersion
Resource: !Sub "arn:aws:s3:::${S3Bucket}/*"
Ec2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref Ec2InstanceRole
# NOTE: Ensure the S3 VPC Endpoint or NAT Gateway is configured to allow access between VPC and S3
Ec2Instance:
Type: AWS::EC2::Instance
DependsOn: S3FilesMountTarget
Properties:
ImageId: !Ref Ec2AmiId
InstanceType: t3.micro
SubnetId: !Ref SubnetId
IamInstanceProfile: !Ref Ec2InstanceProfile
SecurityGroupIds:
- !Ref Ec2SecurityGroup
UserData:
Fn::Base64: !Sub |
#!/bin/bash
set -e
# Mount S3 Files access point
sudo yum install -y amazon-efs-utils
sudo mkdir -p /mnt/ec2
sudo mount -t s3files -o accesspoint=${S3FilesAccessPointEc2.AccessPointId} ${SC3FilesSystem.FileSystemId} /mnt/ec2
# Test writing a file (to be deleted)
TIMESTAMP=$(date +%s)
FILE="/mnt/ec2/demo-$TIMESTAMP.txt"
echo "Hello from EC2! Written at $TIMESTAMP" > "$FILE"CreationPermissions for S3Files AccessPoint should be set to enable the user (UID 1002) to create S3 prefix (/ec2), as well as perform read and write operations on S3 objects under that prefix.
Command to mount S3 Files using an access point.
Inbound traffic from EC2 for S3 Files Mount Target's security group.
Outbound traffic to S3 Files Mount Target for EC2's security group.
