# S3 Files, enabling S3 buckets as file systems

By [jackk](https://paragraph.com/@jackkdev) · 2026-04-27

---

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.

  

Use Cases
---------

*   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.
    

![](https://storage.googleapis.com/papyrus_images/49b6f06c830d0c00e10b99e063ea45ea0ab5a53b18ce29963bbbca409618cf28.png)

* * *

Templates
---------

This section provides CloudFormation templates for S3 FilesSystem and its integration with Lambda, ECS task, and EC2.

![](https://paragraph.com/editor/callout/information-icon.png)

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/*"

![](https://paragraph.com/editor/callout/information-icon.png)

*   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}/*"

![](https://paragraph.com/editor/callout/information-icon.png)

*   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()

![](https://paragraph.com/editor/callout/information-icon.png)

*   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"

![](https://paragraph.com/editor/callout/information-icon.png)

*   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.

---

*Originally published on [jackk](https://paragraph.com/@jackkdev/s3-files)*
