1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Amazon S3 Files を IaC で構成して S3 と EFS のいいとこ取りをする ① CloudFormation 編

1
Posted at

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 ロールの ManagedPolicyArnsAmazonS3FilesClientFullAccess を加えてください。

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. 参考リンク

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?