【AWS S3】クロスアカウントレプリケーションで別々のKMSを利用する際のポイントと手順

## はじめに
AWS S3には、別リージョンや別AWSアカウントのS3にオブジェクト（ファイルなど）をコピー（レプリケーション）する機能があります。
本記事では、以下の要件を前提として、S3のレプリケーションの設定方法を記載しています。
- 別AWSアカウントのS3へのコピー
- コピー元のAWSアカウントとコピー先のAWSアカウントでそれぞれ別のKMSを使用

上記に加えて、レプリケーション失敗時のログの出力方法についても記載しています。

:::note info
本記事の情報は2025年2月時点のものです。
最新情報については公式ドキュメントをご確認ください。
:::


## 目次

[必要なリソース](#必要なリソース)
[重要ポイント](#重要ポイント)
[構築手順](#構築手順)
[検証ならびにメトリクス確認とログ出力](#検証ならびにメトリクス確認とログ出力)
[まとめ](#まとめ)


## 必要なリソース

![S3レプリケーション.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/6843c9a1-f9c7-2468-4fcd-c9558ebc7bb2.png)

### コピー元のAWSアカウント
- KMS(カスタマー管理型キー)
- S3（バージョニング有効:必須）
- IAMポリシー・ロール
- Lambda:ログ出力用(SNSなどでも代替可能)

### コピー先のAWSアカウント
- KMS（カスタマー管理型キー）
- S3（バージョニング有効:必須）

:::note info
本記事では、すべてのリソースは同一リージョン（ap-northeast-1）に作成しています。
:::

## 重要ポイント

### KMS

:::note warn
カスタマー管理型キーを選択してください。
AWSマネージド型キーはクロスアカウントレプリケーションに対応していません。
なお、同一アカウント内のレプリケーションはAWSマネージドキーでも可能です。
:::

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/replication-config-for-kms-objects.html

### S3

:::note warn
バージョニングを有効にしないと、レプリケーションルールを作成できません。
必ず有効にしてください。
:::

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/replication-requirements.html

### ログ出力

:::note warn
レプリケーションが失敗した場合のログがレプリケーションルール自体では確認ができません。
コピー元のS3のイベント通知を設定し、LambdaやSNSなどを利用してログを確認する必要があります。
:::

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/replication-metrics.html

## 構築手順
以下では、画面キャプチャとともに、詳細な設定手順を記載しています。

### 1.コピー元AWSアカウントの設定

#### 1.1 コピー元AWSアカウントでKMSの作成

- 該当のリージョンのKMSコンソール画面を開き、「カスタマー管理型キー」をクリック

:::note warn
カスタマー管理型キーを選択してください。
AWSマネージド型キーはクロスアカウントレプリケーションに対応していません。
:::

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/UsingKMSEncryption.html

- 「キーの作成」をクリック

![スクリーンショット 2025-01-27 164156.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/bc089b09-477a-bb11-1d90-b924ce7faae0.png)

- キーのタイプは「対称」を選択
- キーの使用法は「暗号化および複合化」を選択
- 詳細オプションはそのままで、右下の「次へ」をクリック

![スクリーンショット 2025-01-27 164313.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/b29f1b52-4791-7d8e-42b0-1d0d15ccbd88.png)


- エイリアスには任意のキー名を入力
- 説明やタグも任意で設定することが可能
- 上記2点を記載後、「次へ」をクリック

![スクリーンショット 2025-01-27 164346.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/a55afd9a-fbb5-67ac-54f0-c04a05c667ed.png)

- キー管理者やキーの削除に関しては、案件や会社ごとの取り決めに従って設定
- 「次へ」をクリック
- キーユーザーはなくても問題なし
- 別のAWSアカウントも設定なし
- キーポリシーはデフォルトのままで「次へ」をクリック
- 確認画面が表示されるので、ページ右下の「完了」をクリック

#### 1.2 コピー元AWSアカウントでS3バケットの作成

- 該当リージョンのS3コンソール画面を開く
- 「バケットを作成」をクリック
- バケットタイプは、本記事では「汎用」としています
- バケット名は任意のもの入力（グローバルで一意とする必要あり）
- オブジェクト所有者は、本記事では「ACL無効（推奨）」を選択

![スクリーンショット 2025-01-27 164954.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/a48f6227-d80b-4368-d7c2-cf723941c249.png)

- このバケットのブロックパブリックアクセス設定は、「すべてブロック」にチェック（デフォルト）

![スクリーンショット 2025-01-27 165100.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/83370ad5-6ab0-fc3a-94c3-66451eff9fff.png)

- バケットのバージョニングを「有効にする」にチェック

:::note warn
バージョニングを有効にしないと、レプリケーションルールを作成できません。
必ず有効にしてください。
:::

![スクリーンショット 2025-01-27 165116.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/ab927cc3-7b2c-a093-1a93-0049f88b843f.png)

- タグは任意で付与

- デフォルトの暗号化の「暗号化タイプ」は「AWS Key Management Service キーを使用したサーバー側の暗号化 (SSE-KMS)」を選択
- AWS KMSキーで「コピー元AWSアカウントでKMSの作成」で作成したキーを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/73d2a761-b9e7-ec0a-6af5-94bb95cf0714.png)

- バケットキーは、本記事では「有効にする」を選択
- 上記の設定が完了後、画面右下の「バケットを作成」をクリック

#### 1.3 コピー元AWSアカウントでIAMロールとポリシーの作成

- IAMのコンソール画面を開き、「ロール」を選択し、「ロールを作成」をクリック
- 信頼されたエンティティタイプは「AWSのサービス」、ユースケースは「S3」を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/218f6b05-966f-b645-4def-08e74522a7c0.png)

- 許可ポリシーはのちほど追加するので、選択せず、「次へ」をクリック
- ロール名および説明は任意のものを入力
- 信頼ポリシーではPrincipalがS3となっており、ActionがSTSのAssumeRole
- 画面右下の「ロールを作成」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/649c6a7e-ab7e-d415-f68b-0bc18ae4fc50.png)


### 2. コピー先AWSアカウントの設定
:::note warn
コピー先のAWSアカウントで作業を行います。
:::

#### 2.1 コピー先AWSアカウントでKMSの作成

:::note warn
カスタマー管理型キーを選択してください。
AWSマネージド型キーはクロスアカウントレプリケーションに対応していません。
:::

基本的には「[1.1 コピー元AWSアカウントでKMSの作成](https://qiita.com/oho-kiyotaka/items/2c53f111e95c57936cbc#11-%E3%82%B3%E3%83%94%E3%83%BC%E5%85%83aws%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%81%A7kms%E3%81%AE%E4%BD%9C%E6%88%90)」と同様の手順で作成してください。
異なる点は以下です。

- キーポリシーは以下のJsonを参考にし、以下2点は環境ごとに変更してください
    - Principalにコピー元IAMロールのARN
    - Resourceにコピー先KMSのARN

```jsonc
{
    "Version": "2012-10-17",
    "Id": "key-consolepolicy-3",
    "Statement": [
        {
            "Sid": "Allow attachment of persistent resources",
            "Effect": "Allow",
            "Principal": {
                "AWS":"<コピー元のAWSアカウントで作成したIAMロールのARN>"
            },
            "Action": "kms:CreateGrant",
            "Resource": "<設定しているKMSのARN>",
            "Condition": {
                "Bool": {
                    "kms:GrantIsForAWSResource": "true"
                }
            }
        },
        {
            "Sid": "Allow use of the key for S3 replication from Amazon Connect AWS Account",
            "Effect": "Allow",
            "Principal": {
                "AWS": "<コピー元のAWSアカウントで作成したIAMロールのARN>"
            },
            "Action": [
                "kms:Encrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "<設定しているKMSのARN>"
        }
    ]
}
```

- キーポリシーの設定後、「次へ」をクリック
- 確認画面が表示されるので、ページ右下の「完了」をクリック


#### 2.2 コピー先AWSアカウントでS3バケットの作成

:::note warn
バージョニングを有効にしないと、レプリケーションルールを作成できません。
必ず有効にしてください。
:::

基本的には「コピー元AWSアカウントでS3バケットの作成」と同様の手順で作成してください。
異なる点はバケットポリシーの設定です。

- バケット作成後、バケット名をクリック
- 上部にある「アクセス許可」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/95748a47-c73f-b06e-c90e-ca9ec30a7275.png)

- バケットポリシーを編集し、以下のJSONを追加

```jsonc
{
    "Version": "2012-10-17",
    "Id": "S3-replication-bucket-policy",
    "Statement": [
        {
            "Sid": "S3-replication-bucket-policy",
            "Effect": "Allow",
            "Principal": {
                "AWS": "<コピー元のAWSアカウントで作成したIAMロールのARN>"
            },
            "Action": [
                "s3:GetBucketVersioning",
                "s3:List*",
                "s3:PutBucketVersioning",
                "s3:ReplicateObject",
                "s3:ReplicateDelete",//オプション:削除マーカーのレプリケーションを有効化の際に必要
                "s3:ObjectOwnerOverrideToBucketOwner"
            ],
            "Resource": [
                "<コピー先のAWSアカウントで作成したS3のARN>",
                "<コピー先のAWSアカウントで作成したS3のARN>/*"
            ]
        }
    ]
}
```

### 3. コピー元AWSアカウントでの最終設定

#### 3.1 コピー元AWSアカウントのKMSのポリシー修正

- コピー元のAWSアカウントで作成したKMSの画面を開く
- 左サイドバーのカスタマー管理型キーをクリックし、KMSの一覧を開く
- 作成したKMSのエイリアス名をクリックし、詳細画面を開く
- キーポリシーのタブをクリックし、編集を行う


コピー元KMS
```jsonc
{
    "Version": "2012-10-17",
    "Id": "key-consolepolicy-3",
    "Statement": {
        "Sid": "Allow use of the key for S3 replication",
        "Effect": "Allow",
        "Principal": {
            "AWS": "<コピー元のAWSアカウントで作成したIAMロールのARN>"
        },
        "Action": [
            "kms:Decrypt",
            "kms:DescribeKey"
        ],
        "Resource": "<設定しているKMSのARN>"
    }
}
```

- kms:Decryptは暗号化されているS3の複合化に必要です

#### 3.2 コピー元AWSアカウントのIAMロールの修正

- コピー元AWSアカウントのIAMのコンソール画面を開く
- ロールから先ほど作成したIAMロールを検索し、詳細を開く
- 「許可」のタブをクリック
- 「許可を追加」をクリックし、「インラインポリシーを作成」をクリック
- ポリシーエディターで「Json」を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/1e60f378-4cbe-e077-c5ea-bf55b64c79a7.png)

- 以下のJsonを追加

```jsonc
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:ListBucket",
                "s3:GetReplicationConfiguration",
                "s3:GetObjectVersionForReplication",
                "s3:GetObjectVersionAcl",
                "s3:GetObjectVersionTagging",
                "s3:GetObjectRetention",//オプション:保持ポリシーを設定する場合に必要
            ],
            "Effect": "Allow",
            "Resource": [
                "<コピー元のAWSアカウントで作成したS3バケットのARN>",
                "<コピー元のAWSアカウントで作成したS3バケットのARN>/*"
            ]
        },
        {
            "Action": [
                "s3:ReplicateObject",
                "s3:ReplicateTags",
                "s3:GetObjectVersionTagging",
                "s3:ObjectOwnerOverrideToBucketOwner",
                "s3:ReplicateDelete"//オプション:削除マーカーのレプリケーションを有効化の際に必要
            ],
            "Effect": "Allow",
            "Condition": {
                "StringLikeIfExists": {
                    "s3:x-amz-server-side-encryption":"aws:kms"
                }
            },
            "Resource": [
                "<コピー先のAWSアカウントで作成したS3バケットのARN>/*"
            ]
        },
        {
            "Action": [
                "kms:Decrypt"
            ],
            "Effect": "Allow",
            "Condition": {
                "StringLike": {
                    "kms:ViaService": "s3.ap-northeast-1.amazonaws.com",
                    "kms:EncryptionContext:aws:s3:arn": [
                        "<コピー元のAWSアカウントで作成したS3バケットのARN>",
                        "<コピー元のAWSアカウントで作成したS3バケットのARN>/*"
                    ]
                }
            },
            "Resource": [
                "<コピー元のAWSアカウントで作成したKMSのARN>"
            ]
        },
        {
            "Action": [
                "kms:Encrypt"
            ],
            "Effect": "Allow",
            "Condition": {
                "StringLike": {
                    "kms:ViaService": [
                        "s3.ap-northeast-1.amazonaws.com"
                    ],
                    "kms:EncryptionContext:aws:s3:arn": [
                        "<コピー先のAWSアカウントで作成したS3バケットのARN>",
                        "<コピー先のAWSアカウントで作成したS3バケットのARN>/*"
                    ]
                }
            },
            "Resource": [
                "<コピー先のAWSアカウントで作成したKMSのARN>"
            ]
        }
    ]
}

```

#### 3.3 S3のレプリケーションルール作成

- コピー元のAWSアカウントにあるS3バケットの詳細画面を開く
- 「管理」タブをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/f771de48-1f50-ded7-120b-9aab897a2b94.png)

- レプリケーションルールのセクションにある「レプリケーションルールを作成」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/d6ec1746-cf95-6c39-1d9b-4c2aedb724f6.png)

- レプリケーションルール名は任意のものを入力
- ステータスは、本記事では、有効
- ソースバケットは、必要があれば設定

![スクリーンショット 2025-01-27 171138.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/bca1db16-ba90-9c27-35e0-7896a1a60fa9.png)

- 送信先のセクションで「別のアカウントのバケットを指定する」を選択
- コピー先のAWSアカウントIdとバケット名を入力
    - 送信先に「別のアカウントのバケットを指定する」を選択し、コピー先のAWSアカウントIDとバケット名を入力
- 本記事では、「オブジェクト所有者を送信先バケット所有者に変更」を有効

![スクリーンショット 2025-01-27 171207.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/81ecad22-2e0b-b1cd-0adb-39c6ff7fb471.png)

- IAMロールは、コピー元のAWSアカウントで作成したIAMロールを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/40bf7677-21b9-2faa-7c53-ab3908ddf411.png)

- 暗号化のセクションにある「AWS Key Management Service (AWS KMS)で暗号化されたオブジェクトをレプリケートする」にチェック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/07a7db53-e656-e6dd-b51c-38db526f26ad.png)

- 「送信先オブジェクトを暗号化するためのAWS KMSキー」はコピー先のAWSアカウントで作成したKMSのARNを入力

- 送信先ストレージクラスは、必要があれば設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/15d93f5b-afa4-41fa-0431-a29ddc251f2c.png)

- 追加のレプリケーションオプション
    - 本記事では、「レプリケーションメトリクス」のみ有効
    - レプリケーション時間のコントロール (RTC)
        - レプリケーションを99.99%、15分以内に行うことを保証するものです
        - 追加費用がかかります
        - 有効にしない場合でも、1,2分でレプリケーションされることが多いと感じていますが、要件によっては選択してください
    - 削除マーカーのレプリケーション
        - こちらを有効化すると、コピー元が特定のオブジェクトを削除した場合、コピー先のオブジェクトも削除されます
        - デフォルトでは、コピー元のオブジェクトを削除した場合でも、コピー先のオブジェクトは残ります
    - レプリカ変更の同期
        - こちらは、コピー先のS3のオブジェクトに変更があった場合に、コピー元のオブジェクトにも変更を反映するものです
        - デフォルトでは、コピー元のオブジェクトの変更のみが、コピー先に反映されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/80b04ac6-42b0-4f6b-5645-0b14b378462f.png)

- 設定が完了したら、ページ右下の「保存」をクリック

## 検証ならびにメトリクス確認とログ出力

### 4. 検証

コピー元S3バケットにファイルをアップロードし、コピー先バケットにレプリケートされるか確認してください。 
メトリクス確認およびエラー検知方法については次のセクションを参照してください。


#### 4.1 S3レプリケーションのメトリクス確認方法

本記事では、S3のレプリケーションルールで「レプリケーションメトリクス」を有効化していますが、残念ながらこちらのメトリクスでは失敗した理由がわかりません。

なお、レプリケーションメトリクスの確認方法は以下の通りです。

- コピー元のS3バケットの詳細画面にある「メトリクス」タブをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/d50124fd-3cf8-b8fd-db11-7b3d6485d6cb.png)

- 画面下部に「レプリケーションメトリクス」とあるので、確認したいレプリケーションルールを選択し、「グラフを表示」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/0312704c-8643-8241-b9cf-80c0af0b5514.png)

- 以下のメトリクスを確認することが可能
    - レプリケーション保留中のオペレーション
    - レプリケーションのレイテンシー
    - レプリケーションを保留中のバイト数
    - オペレーションが失敗したレプリケーション

#### 4.2 ログを出力させる方法

レプリケーションに関するログ出力は、S3のイベント通知を使用するため、SNS,SQS,Lambdaを使用して、確認する必要があります。
なおバッチレプリケーションを使用した場合は、レポートで確認することができます。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/s3-batch-replication-batch.html#batch-replication-completion-report


本記事では、Lambdaを利用して、CloudWatchにエラー内容のログを出力させる方法を記載しています。

##### 4.2.1 Lambdaの作成

- 該当のリージョンのLambdaコンソール画面を開き、左サイドバーの「関数」をクリック
- 右上の「関数を作成」をクリック
- 本記事では、Pythonを選択
- 画面右下の「関数を作成」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/185306f5-f1d1-a9d6-c333-90233af26435.png)

- 以下のコードをコピーし、「デプロイ」をクリック
- 本記事では、詳細なエラーハンドリングは行っておりません
- 必要に応じて、修正してください

```python
import json

def lambda_handler(event, context):
    # TODO implement
    print("----event----")
    print(event)
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
```

##### 4.2.2 S3のイベント通知設定

- コピー元AWSアカウントで作成したS3バケット名をクリック
- 「プロパティ」タブをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/c516d551-1695-0561-f877-c5eca022ae66.png)

- 「イベント通知」のセクションで「イベント通知を作成」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/e77f9f48-14f2-da35-910d-f8f2508bdafc.png)

- イベント名は任意のものを入力
- 必要に応じて、プレフィックスやサフィックスを入力ください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/a0bf89ff-f2e1-c551-23ef-fb6fadeccc9c.png)

- 「イベントタイプ」のセクションで、「レプリケーション」があるので、「すべてのレプリケーションイベント」にチェック
    - 個別に有効化することも可能なので、要件に応じて変更ください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/1c86fba9-dcf9-a819-22b1-ffbca51c5f9b.png)

- 「送信先」セクションでLambda関数を選択し、先ほど作成したLambda関数を設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/a2cca2d4-8a4e-338c-928a-86f3ec8db37f.png)

- 画面右下の「保存」をクリック

- 失敗時は、CloudWatchのロググループでLambdaのログを確認してください
- 例えば、以下のような失敗理由が表示されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3717693/92d99e9b-3010-4e2b-4905-fb23580a79b2.png)


- レプリケーションの失敗理由については、以下の公式ドキュメントを参考にし、権限などを見直してください

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/replication-metrics-events.html#replication-failure-codes


## まとめ
本記事では、クロスアカウントでのS3レプリケーション時に、それぞれのAWSアカウントでKMSを利用する際の手順について記載しました。
KMSはカスタマー管理型を使用し、S3バケットはバージョニングを有効が必須です。
加えて、**レプリケーションが失敗した場合のログがレプリケーションルール自体では確認ができない**ため、別途用意する必要があります。
レプリケーションが標準機能としてあるのはとても便利ですが、いくつかポイントを知らないと、なぜかできないということになるので、実施前に要件や現状の設定を確認しましょう。