1. 概要
Amazon S3 Files が今月 (2026 年 4 月) GA となったので、CloudFormation と Ansible を使って構成しました。
前回の記事 で IaC したのは Mountpoint for Amazon S3 で、またそれとは別に Amazon S3 File Gateway もあって混乱しましたが、どの方式も容量単価の安い S3 を普通のファイルシステムのように扱いたいという目的は同じです。
これらを時系列で簡単にまとめると、以下のような違いになります。
| 名称 | 主なクライアント | 提供形態 | リリース時期 | 特徴 |
|---|---|---|---|---|
| Amazon S3 File Gateway | オンプレミス (Linux, Windows) | ハイブリッド | 2016年 | オンプレミスからの接続用ゲートウェイ |
| Mountpoint for Amazon S3 | EC2 (Linux) | ソフトウェア | 2023 年 GA 2025 年 5 月 自動マウント対応 |
EC2 内で動作 |
| Amazon S3 Files | EC2, Lambda (Linux) | マネージドサービス | 2026 年 4 月 | EFS と同じようにマウントして使える |
新しい S3 Files は Mountpoint for Amazon S3 に似ていますが、マネージドサービスであること、自動的に冗長化されていること、複数クライアントからの同時アクセスが可能なこと、また EC2 だけでなく Lambda でも使用できるなどの違いがあります。
今回は ① CloudFormation 編、次回は ② Ansible 編 として、最終的に Amazon Linux 2023 に S3 Files のファイルシステムをマウントする構成を自動化します。
2. EC2 インスタンス
EC2 インスタンス本体の構成は本題と関係がないので省略しますが、IAM ロールに注意点がであります。
2.1. IAM ロールとインスタンスプロファイル
EC2 が S3 Files にアクセスできるように、IAM ロールの ManagedPolicyArns に AmazonS3FilesClientFullAccess を加えてください。
Resources:
MyEc2Role:
Type: AWS::IAM::Role
Properties:
RoleName: my-ec2-role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
Path: /
ManagedPolicyArns:
- !Sub arn:${AWS::Partition}:iam::aws:policy/CloudWatchAgentServerPolicy
- !Sub arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore
- !Sub arn:${AWS::Partition}:iam::aws:policy/AmazonS3FullAccess
- !Sub arn:${AWS::Partition}:iam::aws:policy/AmazonS3FilesClientFullAccess # これが必要
MyEc2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: my-ec2-instance-profile
Path: /
Roles:
- !Ref MyEc2Role
3. S3 バケット
S3 バケットなんか何回も作ったから簡単だよ、と思った人はちょっと待ってください。S3 Files 用のバケットとポリシーにはいくつか注意点があります。
3.1. バケット本体
VersioningConfiguration を有効化する必要があります。普通のファイルと同じように上書き保存ができるようにするために、S3 Files が内部でバージョニングを使用しているようです。
MyS3FilesBucket:
Type: AWS::S3::Bucket
Metadata:
Properties:
BucketName: my-s3files-backet
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
OwnershipControls:
Rules:
- ObjectOwnership: ObjectWriter
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
VersioningConfiguration:
Status: Enabled # S3 Files に必要
3.2. バケットポリシー
MyS3FilesBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref MyS3FilesBucket
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: AllowS3FilesAndEC2RoleAccess
Effect: Allow
Principal:
AWS:
- !GetAtt MyEc2Role.Arn
- !GetAtt MyS3FilesFileSystemRole.Arn # これが必要 (後述)
Action:
- s3:GetObject
- s3:PutObject
- s3:DeleteObject
- s3:ListBucket
Resource:
- !GetAtt MyS3FilesBucket.Arn
- !Sub ${MyS3FilesBucket.Arn}/*
- Sid: AllowSSLRequestsOnly
Effect: Deny
Principal: '*'
Action: s3:*
Resource:
- !GetAtt MyS3FilesBucket.Arn
- !Sub ${MyS3FilesBucket.Arn}/*
Condition:
Bool:
aws:SecureTransport: false
バケットには EC2 以外に S3 Files のファイルシステムからのアクセスも許可する必要があるので、後で定義する S3 Files ファイルシステムの IAM ロールの ARN を追加してください。
- Sid: AllowS3FilesAndEC2RoleAccess
Effect: Allow
Principal:
AWS:
- !GetAtt MyEc2Role.Arn
- !GetAtt MyS3FilesFileSystemRole.Arn # これが必要 (後で定義する)
また S3 Files に必須ではありませんが、以下のような非暗号化アクセスを拒否するステートメントが推奨されています。
- Sid: AllowSSLRequestsOnly
Effect: Deny
Principal: '*'
Action: s3:*
Resource:
- !GetAtt MyS3FilesBucket.Arn
- !Sub ${MyS3FilesBucket.Arn}/*
Condition:
Bool:
aws:SecureTransport: false
4. S3 Files ファイルシステム
4.1. ファイルシステムと IAM ロール
新しい AWS::S3Files::FileSystem タイプのリソースにアタッチする IAM ロールがつまづきポイントです。
MyS3FilesFileSystem:
Type: AWS::S3Files::FileSystem
Properties:
AcceptBucketWarning: true
Bucket: !GetAtt MyS3FilesBucket.Arn
RoleArn: !GetAtt MyS3FilesFileSystemRole.Arn
MyS3FilesFileSystemRole:
Type: AWS::IAM::Role
Properties:
RoleName: my-s3files-filesystem-role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
# IAM ロールを引き受ける(AssumeRole)際のサービスプリンシパルは
# s3files ではなく elasticfilesystem.amazonaws.com を指定する.
Service:
- elasticfilesystem.amazonaws.com
Action:
- sts:AssumeRole
Condition:
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
ArnLike:
aws:SourceArn: !Sub arn:${AWS::Partition}:s3files:${AWS::Region}:${AWS::AccountId}:file-system/*
ManagedPolicyArns:
- !Sub arn:${AWS::Partition}:iam::aws:policy/AmazonS3FullAccess
AssumeRole を許可する対象のサービスが s3files ではなく、elasticfilesystem (EFS) という罠があります。
- Effect: Allow
Principal:
# IAM ロールを引き受ける(AssumeRole)際のサービスプリンシパルは
# s3files ではなく elasticfilesystem.amazonaws.com を指定する.
Service:
- elasticfilesystem.amazonaws.com
Action:
- sts:AssumeRole
本件と直接関係ありませんが、最近のベストプラクティスとしてプリンシパルをサービス全体としつつ、条件で AWS アカウントや対象の ARN に制限することが推奨されています。また ARN の arn:aws: を arn:${AWS::Partition}: と書いて、aws を抽象化することも推奨されているようです。
Condition:
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
ArnLike:
aws:SourceArn: !Sub arn:${AWS::Partition}:s3files:${AWS::Region}:${AWS::AccountId}:file-system/*
4.2. ファイルシステムの IAM ポリシー
上で定義した IAM ロールにアタッチするポリシーですが、以下の公式情報が無かったらほぼムリでした。
KMS による暗号化が必須になっていることと、EFS と S3 間でデータを同期するためのイベントブリッジがポリシーを複雑にしています。
# https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-files-prereq-policies.html
MyS3FilesFileSystemRolePolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: my-s3files-filesystem-role-policy
Roles:
- !Ref MyS3FilesFileSystemRole
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: S3BucketPermissions
Effect: Allow
Action:
- s3:ListBucket
- s3:ListBucketVersions
Resource: !Sub arn:${AWS::Partition}:s3:::${MyS3FilesBucket}
Condition:
StringEquals:
aws:ResourceAccount: !Ref AWS::AccountId
- Sid: S3ObjectPermissions
Effect: Allow
Action:
- s3:AbortMultipartUpload
- s3:DeleteObject*
- s3:GetObject*
- s3:List*
- s3:PutObject*
Resource: !Sub arn:${AWS::Partition}:s3:::${MyS3FilesBucket}/*
Condition:
StringEquals:
aws:ResourceAccount: !Ref AWS::AccountId
- Sid: UseKmsKeyWithS3Files
Effect: Allow
Action:
- kms:GenerateDataKey
- kms:Encrypt
- kms:Decrypt
- kms:ReEncryptFrom
- kms:ReEncryptTo
Condition:
StringLike:
kms:ViaService: !Sub s3.${AWS::Region}.amazonaws.com
kms:EncryptionContext:aws:s3:arn:
- !Sub arn:${AWS::Partition}:s3:::${MyS3FilesBucket}
- !Sub arn:${AWS::Partition}:s3:::${MyS3FilesBucket}/*
Resource: !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:*
- Sid: EventBridgeManage
Effect: Allow
Action:
- events:DeleteRule
- events:DisableRule
- events:EnableRule
- events:PutRule
- events:PutTargets
- events:RemoveTargets
Condition:
StringEquals:
events:ManagedBy: elasticfilesystem.amazonaws.com
Resource:
- !Sub arn:${AWS::Partition}:events:*:*:rule/DO-NOT-DELETE-S3-Files*
- Sid: EventBridgeRead
Effect: Allow
Action:
- events:DescribeRule
- events:ListRuleNamesByTarget
- events:ListRules
- events:ListTargetsByRule
Resource:
- !Sub arn:${AWS::Partition}:events:*:*:rule/*
4.3. ファイルシステムポリシー
IAM ポリシーとは別に、S3 Files ファイルシステム用のポリシーが必要です。
MyS3FilesFileSystemFileSystemPolicy:
Type: AWS::S3Files::FileSystemPolicy
Properties:
FileSystemId: !Ref MyS3FilesFileSystem
Policy:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal: '*'
Action:
- s3files:ClientMount
Resource: !Ref MyS3FilesFileSystem
Condition:
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
4.4. ファイルシステム ID の保存
必須ではありませんが、生成されたファイルシステム ID を Systems Manager パラメータストアに保存します。このパラメータは後で Ansible が参照するためです。
MyS3FilesFileSystemFsIdParameter:
Type: AWS::SSM::Parameter
Properties:
Name: my-s3files-filesystem-id
Type: String
Value: !GetAtt MyS3FilesFileSystem.FileSystemId
Name: には任意のパラメータ名を指定してください。
4.5. マウントターゲット
ファイルシステムを NFS マウントするためのマウントターゲットを定義します。以下の例では別のスタックで定義した 2 つのサブネットを !ImportValue で参照しています。アタッチするセキュリティグループは次で定義します。
MyS3FilesMountTarget1:
Type: AWS::S3Files::MountTarget
Properties:
FileSystemId: !Ref MyS3FilesFileSystem
IpAddressType: IPV4_ONLY
SubnetId: !ImportValue my-private-subnet-1
SecurityGroups:
- !Ref MyS3FilesSecurityGroup
MyS3FilesMountTarget2:
Type: AWS::S3Files::MountTarget
Properties:
FileSystemId: !Ref MyS3FilesFileSystem
IpAddressType: IPV4_ONLY
SubnetId: !ImportValue my-private-subnet-2
SecurityGroups:
- !Ref MyS3FilesSecurityGroup
この例では別々のサブネットに 2 つのマウントターゲットを作って冗長化していますが、実際にどちらのターゲットにマウントされるかは、ファイルシステム ID の参照によって動的に決定されます。
4.6. セキュリティグループ
ファイルシステムへのアクセスを許可するセキュリティグループを定義します。以下の例では my-ec2-sg というセキュリティグループがアタッチされた EC2 インスタンスからの、NFS v4.x プロトコルによる接続だけを許可しています。VPC は別のスタックで定義済みとして !ImportValue で参照しています。
MyS3FilesSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: my-s3files-sg
GroupDescription: SecurityGroup for S3 Files Storage.
VpcId: !ImportValue my-vpc-id
# バックエンド EC2 からの NFS v4.0/4.1 接続を許可する.
MyS3FilesSgIngressFromEc2Sg:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref MyS3FilesSecurityGroup
SourceSecurityGroupId: !ImportValue my-ec2-sg
IpProtocol: tcp
FromPort: 2049
ToPort: 2049
イングレスルールはセキュリティグループにインラインで定義するほうが簡単ですが、この例のように別に定義してアタッチすればルール変更の自由度が高くなります。
以上で CloudFormation による構成は完了です。
次回は Ansible を使用して、Amazon Linux 2023 に S3 Files のファイルシステムをマウントする構成を自動化します。
5. 参考リンク
- Amazon S3 ファイルゲートウェイとは - AWS Storage Gateway
- S3 Files の提供開始 – S3 バケットがファイルシステムとしてアクセス可能に | Amazon Web Services ブログ
- Prerequisites for S3 Files - Amazon Simple Storage Service
- Creating and managing S3 Files resources - Amazon Simple Storage Service
- How S3 Files works with IAM - Amazon Simple Storage Service
- S3 Filesで消えるアーキテクチャ層、生まれるアーキテクチャ
- Amazon S3 Files の料金体系を図解で整理してみた | DevelopersIO
- Amazon S3 Files が GA — S3 バケットをファイルシステムとしてマウント、EFS と比較してみた | DevelopersIO