最近リリースされたAWS S3 Filesを触ってみました。AWS Serverless Application Model (AWS SAM) で試していたのですが、思ったより詰まるポイントが多かったのでコードを共有しておきます。
S3 Files とは
S3 Files は S3 バケットをファイルシステムとして EC2・Lambda・EKS・ECS にマウントして使えるようにするものです。
通常の S3 操作はSDK 経由(Pythonだと boto3.client('s3').get_object(...) など)で行いますが、S3 Files を使うと open('data.csv') のような通常のファイル操作で S3 のデータにアクセスできます。SDKの実装部分が不要になって開発が楽になるというわけです。
SAMで作る
S3 Filesを使うには
- LambdaをマウントするVPC
- TCP 2049で通信するセキュリティグループ
- ファイルシステムからバケットにアクセスするためのIAMロール
など、色々と設定する必要があります。
またSAM特有?の問題として、1つのCloudFormation Stackでまとめてデプロイしようとしたところ、AWS::S3Files::MountTarget が作成完了したもの利用可能なステータスになる前にLambdaのリソースを作り始めてしまってエラーになりました。(エラーメッセージ:"mount targets created in all availability zones the function will execute in, but not all are in the available life cycle state yet. Please wait for them to become available and try the request again.")(現時点で最新のSAM CLI ver.1.158.0の問題です)
そこで
- S3 FilesやVPCなどの作成用のStack
- LambdaのStack
に分けて、時間を空けて作ることでうまくデプロイできるようになりました。
S3 Filesなどを作るStackのtemplate.yaml
AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Resources: # S3 Files を利用するための VPC とサブネットを定義 VPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 EnableDnsHostnames: true EnableDnsSupport: true PrivateSubnet: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: 10.0.1.0/24 AvailabilityZone: !Select [0, !GetAZs ""] # TCP 2049で通信するセキュリティグループ(Lambda用とS3Files MountTarget用) LambdaSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security group for Lambda VpcId: !Ref VPC MountTargetSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security group for S3 Files mount target VpcId: !Ref VPC LambdaToMountTargetEgress: Type: AWS::EC2::SecurityGroupEgress Properties: GroupId: !GetAtt LambdaSecurityGroup.GroupId Description: Allow NFS to S3 Files mount target IpProtocol: tcp FromPort: 2049 ToPort: 2049 DestinationSecurityGroupId: !GetAtt MountTargetSecurityGroup.GroupId MountTargetFromLambdaIngress: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !GetAtt MountTargetSecurityGroup.GroupId Description: Allow NFS from Lambda IpProtocol: tcp FromPort: 2049 ToPort: 2049 SourceSecurityGroupId: !GetAtt LambdaSecurityGroup.GroupId # ファイルシステムからバケットにアクセスするためのIAMロール # 参考: https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-files-prereq-policies.html#s3-files-prereq-iam S3AccessRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Sid: AllowS3FilesAssumeRole Effect: Allow Principal: Service: elasticfilesystem.amazonaws.com Action: sts:AssumeRole Condition: StringEquals: aws:SourceAccount: !Ref AWS::AccountId ArnLike: aws:SourceArn: !Sub "arn:aws:s3files:${AWS::Region}:${AWS::AccountId}:file-system/*" Policies: - PolicyName: S3AccessPolicy PolicyDocument: Version: "2012-10-17" Statement: - Sid: S3BucketPermissions Effect: Allow Action: - s3:ListBucket - s3:ListBucketVersions Resource: !Sub "arn:aws:s3:::${S3Bucket}" 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:s3:::${S3Bucket}/*" Condition: StringEquals: aws:ResourceAccount: !Ref AWS::AccountId - Sid: EventBridgeManage Effect: Allow Action: - events:DeleteRule - events:DisableRule - events:EnableRule - events:PutRule - events:PutTargets - events:RemoveTargets Resource: "arn:aws:events:*:*:rule/DO-NOT-DELETE-S3-Files*" Condition: StringEquals: events:ManagedBy: elasticfilesystem.amazonaws.com - Sid: EventBridgeRead Effect: Allow Action: - events:DescribeRule - events:ListRuleNamesByTarget - events:ListRules - events:ListTargetsByRule Resource: "arn:aws:events:*:*:rule/*" S3Bucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub "${AWS::AccountId}-s3-files-example" VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 S3Files: Type: AWS::S3Files::FileSystem Properties: Bucket: !GetAtt S3Bucket.Arn RoleArn: !GetAtt S3AccessRole.Arn SynchronizationConfiguration: ExpirationDataRules: # キャッシュされたデータが期限切れになるまでの日数 - DaysAfterLastAccess: 1 ImportDataRules: - Prefix: "" # SizeLessThan: 特定のサイズ未満のファイルをキャッシュ対象にする SizeLessThan: 1073741824 # 1GB Trigger: ON_DIRECTORY_FIRST_ACCESS S3FilesAccessPoint: Type: AWS::S3Files::AccessPoint Properties: FileSystemId: !GetAtt S3Files.FileSystemArn PosixUser: Uid: "1000" Gid: "1000" RootDirectory: Path: /accesspoint # /にするとPermission deniedで書き込めなかったため指定(S3FilesがマウントされたLambda内で/mnt/s3filesに保存するとS3上の/accesspointディレクトリに保存される) CreationPermissions: OwnerUid: "1000" OwnerGid: "1000" Permissions: "0755" S3FilesMountTarget: Type: AWS::S3Files::MountTarget Properties: FileSystemId: !Ref S3Files SubnetId: !Ref PrivateSubnet SecurityGroups: - !GetAtt MountTargetSecurityGroup.GroupId # Lambdaデプロイ用のStackで参照しやすくするためParameter storeに保存 PrivateSubnetIdParam: Type: AWS::SSM::Parameter Properties: Name: /s3-files/PrivateSubnetId Type: String Value: !Ref PrivateSubnet S3FilesAccessPointArnParam: Type: AWS::SSM::Parameter Properties: Name: /s3-files/S3FilesAccessPointArn Type: String Value: !GetAtt S3FilesAccessPoint.AccessPointArn LambdaSecurityGroupIdParam: Type: AWS::SSM::Parameter Properties: Name: /s3-files/LambdaSecurityGroupId Type: String Value: !GetAtt LambdaSecurityGroup.GroupId
Lambdaを作るStackのtemplate.yaml
AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Resources: LambdaFunction: Type: AWS::Serverless::Function Properties: FunctionName: LambdaFunction CodeUri: src/ Handler: app.handler Runtime: python3.12 Architectures: - x86_64 Timeout: 60 MemorySize: 1024 Environment: Variables: S3_BUCKET_NAME: !Sub "${AWS::AccountId}-s3-files-example" Role: !GetAtt S3FilesRoleForFunction.Arn VpcConfig: SubnetIds: - "{{resolve:ssm:/s3-files/PrivateSubnetId}}" SecurityGroupIds: - "{{resolve:ssm:/s3-files/LambdaSecurityGroupId}}" FileSystemConfigs: - Arn: "{{resolve:ssm:/s3-files/S3FilesAccessPointArn}}" LocalMountPath: /mnt/s3files LambdaFunctionLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/aws/lambda/${LambdaFunction}" RetentionInDays: 14 # S3 Files を Lambda から利用するための IAM ロールを定義 # ref: https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-files-prereq-policies.html#s3-files-prereq-iam S3FilesRoleForFunction: 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/AWSLambdaBasicExecutionRole - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole Policies: - PolicyName: S3FilesClientPolicy PolicyDocument: Version: "2012-10-17" Statement: - Sid: S3FilesMount Effect: Allow Action: - s3files:ClientMount - s3files:ClientWrite Resource: "{{resolve:ssm:/s3-files/S3FilesAccessPointArn}}" - Sid: S3ReadWriteAccess Effect: Allow Action: - s3:Get* - s3:Put* Resource: !Sub "arn:aws:s3:::${AWS::AccountId}-s3-files-example/*" - Sid: S3BucketListAccess Effect: Allow Action: - s3:ListBucket Resource: !Sub "arn:aws:s3:::${AWS::AccountId}-s3-files-example"
















![[改訂第9版]LaTeX美文書作成入門 [改訂第9版]LaTeX美文書作成入門](https://m.media-amazon.com/images/I/414goKtaBjL._SL500_.jpg)
