CloudFormationでS3レプリケーションを試してみた

## はじめに

本記事ではS3レプリケーション機能を使用して、S3オブジェクトが同一アカウントバケット間でレプリケーションされることを確認します。
なお、AWSリソース作成にはCloudFormationを使用します。

※S3やCloudFormationなどの具体的なサービスの説明は、本記事では割愛します。

## 概要

### 作成するAWSリソース

同一アカウントでS3オブジェクトをレプリケーションする際には、以下のAWSリソースを作成します。

※S3レプリケーションの詳しい内容を知りたい方は、[AWS公式サイト](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/replication.html)などをご参照ください。

|    リソース    |     概要                 |リソース物理名|
|:----------:|:------------------------:|:------------------------:|
| S3バケット   | １．レプリケーション元のS3バケット <br> ２．レプリケーション先のS3バケット     |１．s3-replicationtest-stack-source<br>　２．s3-replicationtest-stack-destination|
| IAM Role     | レプリケーション元からレプリケーション先へのレプリケーション権限を付与したIAM Role          |	s3-replicationtest-stack-bucket-source-role|

:::note info
別アカウント間でのレプリケーションを行う場合や、サーバ側で暗号化したオブジェクトをレプリケーションする場合には、一部設定や作成するAWSリソースが異なります。
:::

### テンプレート
リソースの作成には以下のテンプレートを使用します。

:::note warn
ポイント
レプリケーション元とレプリケーション先で、バケットのバージョニングが有効になっている必要があります。
:::

```template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: "S3 Replication Template"
Resources:
  S3BucketSource: # レプリケーション元バケット
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${AWS::StackName}-source"
      VersioningConfiguration:
        Status: Enabled
      ReplicationConfiguration:
        Role: !GetAtt S3BucketSourceRole.Arn
        Rules:
          - Destination:
              Bucket: !Sub "arn:aws:s3:::${AWS::StackName}-destination"
            Status: Enabled
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
  S3BucketDestination: # レプリケーション先バケット
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${AWS::StackName}-destination"
      VersioningConfiguration:
        Status: Enabled
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
  S3BucketSourceRole: # レプリケーション元バケットのレプリケーションルールにアタッチするロール
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${AWS::StackName}-bucket-source-role"
      Description: "Role For S3"
      Path: "/service/"
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - s3.amazonaws.com
            Action:
              - sts:AssumeRole
      Policies:
        - PolicyName: "s3-replication-policy"
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:ListBucket
                  - s3:GetReplicationConfiguration
                Resource:
                  - !Sub "arn:aws:s3:::${AWS::StackName}-source"
              - Effect: Allow
                Action:
                 - s3:GetObjectVersionForReplication
                 - s3:GetObjectVersionAcl
                 - s3:GetObjectVersionTagging
                Resource:
                  - !Sub "arn:aws:s3:::${AWS::StackName}-source/*"
              - Effect: Allow
                Action:
                  - s3:ReplicateObject
                  - s3:ReplicateDelete
                  - s3:ReplicateTags
                Resource:
                  - !Sub "arn:aws:s3:::${AWS::StackName}-destination/*"

```


## リソース作成してみた

### 作成コマンド
今回はローカル環境からAWS CLIコマンドを使用して、スタックの作成を行います。
AWS CLIコマンドを使用するためのアクセスキーの設定に関しては、[こちら](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds)をご参照ください。


```
aws cloudformation deploy \
  --template template.yaml \
  --stack-name s3-replicationtest-stack \
  --capabilities CAPABILITY_NAMED_IAM
```


:::note warn
アクセスキー使用時の注意点
アクセスキーは、万が一流出した場合のセキュリティリスクが高いため、以下の対応などを検討してください。
・MFAを有効にする
・IAMユーザへの権限は最小にし、実行コマンドの権限を持ったIAMロールを作成し、スイッチロールで一時的なセキュリティ認証情報を取得してコマンドを実行する
・アクセスキーを使わないように、EC2やCloudShellでIAM Roleによる認証を行ってコマンドを実行する
:::

参考：AWS アクセスキーを管理するためのベストプラクティス
https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws-access-keys-best-practices.html

作成したスタックは以下になります。
![CFnデプロイ結果.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87924/34311b3a-911d-8bf1-ff55-b89fd66db7bd.png)

### レプリケーションされるか確認してみる

レプリケーション元バケットにファイルをアップロードしていきます。
![アップロード画面.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87924/338720b4-56bf-b9a6-5c46-b52f40c8896e.png)
![アップロード画面2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87924/8d97e49b-549c-73f7-69e1-1458b2f3fac7.png)
![レプリケーション元にファイルをアップロード.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87924/7196579d-27d8-3547-c719-927918d40a50.png)


レプリケーション先のバケットを見てみると、ファイルがレプリケーションされていることが確認できます。
![レプリケーション先にファイルがレプリケートされていることを確認.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87924/4c2d4ebf-7423-8e67-fb4e-7eabe978350f.png)



### おまけ

各オブジェクトのレプリケーションステータスはどうなっているか確認してみましょう。

レプリケーション元バケットのオブジェクトは「COMPLETED」になっており、レプリケーションが成功したことがわかります。
![レプリケーション元にファイルをアップロード2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87924/3bf897fa-c07d-fe22-061f-d85202e92c7c.png)

レプリケーション先バケットのオブジェクトは「REPLICA」になっており、レプリケーションされたオブジェクトであることがわかります。
![レプリケーション先にファイルがレプリケートされていることを確認2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87924/051942d1-d0fa-2a81-24d5-e174210d7356.png)

ちなみに、以下の場合は「-」になります。
・レプリケーション先バケットに直接アップロードしたオブジェクト
・レプリケーションを設定していないバケットにアップロードされたオブジェクト
![レプリケーション先バケットにファイルを直接アップロード.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87924/fe92877a-32a8-3e36-83b7-2776d7bf5483.png)


## おわりに

今回は同一アカウントでのS3レプリケーションを試しました。
次回は、別アカウント間のレプリケーションや多段レプリケーションなど様々なパターンを試してみようと思います。