0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

S3 クロスアカウントレプリケーション ・ 異常時の動作を試してみた

Posted at

はじめに

異なるアカウント間で、ファイル転送によるデータ連携ではなく、S3バケット間のレプリケーションを考える機会がありました。
単純にレプリケーションするだけなら問題なくできることを経験していたのですが、レプリケーションの失敗など異常時の動作がどうなるのだろうと思い、試してみることにしました。

S3クロスアカウントレプリケーションとは

アカウントAのバケットに保存したファイルがアカウントBのバケットにレプリケーションできる機能です。
以下のようなイメージです。
S3_001.png

どれくらいの遅延でレプリケーションできるのか?という点についてもマニュアルに記載がありました。

S3 Replication Time Control (S3 RTC) では、データレプリケーションに関するコンプライアンス要件 (またはビジネス要件) への対応をサポートします。また、Amazon S3 レプリケーション時間を可視化します。S3 RTC は、Amazon S3 にアップロードしたほとんどのオブジェクトを数秒でレプリケートし、これらのオブジェクトの 99.99% を 15 分以内にレプリケートします。

十分に実用的ですね。

使ってみた

レプリケーション元のアカウントA バケットを作成

まずはレプリケーション元のアカウントAでバケットを作成します。
S3のレプリケーションを行うために、バケットのバージョニングを有効にする必要があるので、ご注意ください。
※デフォルトでは無効です。
S3_01.png
S3_02.png

その他の設定はデフォルトで「バケットを作成」をクリックします。

レプリケーション先のアカウントB バケットを作成

続いてレプリケーション先のアカウントBでバケットを作成します。
レプリケーション元と同様にバケットのバージョニングを有効にすることを忘れないでください。
※以降の画面でもアカウントBの画面はダークモードでキャプチャしています

S3_03.png
S3_04.png

レプリケーション元のアカウントA レプリケーション設定

次にレプリケーション元のアカウントAでレプリケーションの設定を行います。
「管理」タブにて「レプリケーションルールを作成」をクリック。
S3_05.png

以下の設定を行います。
 ・レプリケーションルールの設定
  レプリケーションルール名:replication-test
・ソースバケット
  ルールスコープを選択:バケット内のすべてのオブジェクトに適用
S3_06.png

 ・送信先
  送信先:別のアカウントのバケットを指定する
  アカウントID:レプリケーション先のアカウントBのアカウントIDを設定
  バケット名:destination-bucket-202411
 ・オブジェクト所有者を送信先バケット所有者に変更:チェックを入れる
 ・IAMロール:新しいロールの作成 を選択
S3_07.png

・追加のレプリケーションオプション
 レプリケーション時間のコントロール(RTC):チェックをいれる
 その他はデフォルト設定で、最後に「保存」をクリック。
S3_08.png

ルールを保存する際に、既存オブジェクトをレプリケートするか確認がありました。
今回は、作ったばかりのバケットで空になっていますので、「いいえ、既存オブジェクトをレプリケートしません。」を選択しました。
S3_09.png

レプリケーションルールが作成されました。
レプリケーションルールの構成設定欄に作成されたIAMロールのリンクがありますので、開いて確認します。
S3_10.png

次のステップで使用しますので、IAMロールのARNをコピーしておきます。
S3_12.png

ちなみに、自動で作成されたIAMロールの中身は以下となっていました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:ListBucket",
                "s3:GetReplicationConfiguration",
                "s3:GetObjectVersionForReplication",
                "s3:GetObjectVersionAcl",
                "s3:GetObjectVersionTagging",
                "s3:GetObjectRetention",
                "s3:GetObjectLegalHold"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::source-bucket-202411",
                "arn:aws:s3:::source-bucket-202411/*",
                "arn:aws:s3:::destination-bucket-202411",
                "arn:aws:s3:::destination-bucket-202411/*"
            ]
        },
        {
            "Action": [
                "s3:ReplicateObject",
                "s3:ReplicateDelete",
                "s3:ReplicateTags",
                "s3:ObjectOwnerOverrideToBucketOwner"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::source-bucket-202411/*",
                "arn:aws:s3:::destination-bucket-202411/*"
            ]
        }
    ]
}

レプリケーション先のアカウントB バケットポリシーを設定

アカウントAからレプリケーション先のアカウントBのバケットにアクセスできるように、アカウントB側でバケットポリシー(先ほど作られたIAMロールによるアクセスを許可)を設定していきます。
バケットポリシーの「編集」をクリックします。
S3_13.png

ポリシーに設定を入れて、「変更の保存」をクリックして保存します。
S3_14.png

設定したポリシーは以下の通りです。

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "1",
			"Effect": "Allow",
			"Principal": {
				"AWS": "arn:aws:iam::<アカウントAのアカウントID>:role/service-role/s3crr_role_for_source-bucket-202411"
			},
			"Action": [
				"s3:ReplicateDelete",
				"s3:ReplicateObject",
				"s3:ReplicateTags",
				"s3:ObjectOwnerOverrideToBucketOwner"
			],
			"Resource": "arn:aws:s3:::destination-bucket-202411/*"
		}
	]
}

試しにアカウントAのバケットにファイルを配置してみます。
S3_15.png

しっかりアカウントBのバケットにファイルがレプリケーションされました。
S3_16.png

レプリケーション先のアカウントBでレプリケーションを検知する

異常系の動作の確認の前に少し寄り道をします。
レプリケーション先のアカウントではレプリケーションでファイルが作成されたことを契機として、後続の処理を動かすといったことがあると思います。
そこで、レプリケーション先のアカウントBでS3のイベント検知を実施し、一番簡単な後続処理であるSNSでメール通知が行えるか確認しておきます。

イメージとしては以下のような形です。
S3_002.png

アカウントBのSNSでトピックを作成します。
S3_18.png

S3_17.png

トピックのアクセスポリシーを開いて、メソッドの選択で「アドバンスト」を選択します。
S3_19.png

以下の内容に修正して、S3からのPublishを許可しておきます。
「トピックの作成」をクリックして、トピックを作成します。

{
  "Version": "2008-10-17",
  "Id": "__default_policy_ID",
  "Statement": [
    {
      "Sid": "__default_statement_ID",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": [
        "SNS:GetTopicAttributes",
        "SNS:SetTopicAttributes",
        "SNS:AddPermission",
        "SNS:RemovePermission",
        "SNS:DeleteTopic",
        "SNS:Subscribe",
        "SNS:ListSubscriptionsByTopic",
        "SNS:Publish"
      ],
      "Resource": "arn:aws:sns:ap-northeast-1:<アカウントBのアカウントID>:test-topic2",
      "Condition": {
        "StringEquals": {
          "AWS:SourceOwner": "<アカウントBのアカウントID>"
        }
      }
    },
    {
      "Sid": "additional_statement_ID",
      "Effect": "Allow",
      "Principal": {
        "Service": "s3.amazonaws.com"  
      },
      "Action": [
        "SNS:Publish"
      ],
      "Resource": "arn:aws:sns:ap-northeast-1:<アカウントBのアカウントID>:test-topic2",
      "Condition": {
        "ArnLike": { 
          "aws:SourceArn": "arn:aws:s3:::destination-bucket-202411"
        }
      }
    }
  ]
}

サブスクリプションも作成していきます。
「サブスクリプションの作成」をクリックします。
S3_20.png

プロトコルは「Eメール」を選択し、エンドポイントに通知したいメールアドレスを設定します。
「サブスクリプションの作成」をクリックして、サブスクリプションを保存します。
S3_21.png

エンドポイントに入力したメールアドレスへメールが届きます。
届いたメールで「Confirm subscription」をクリックしておきます。

続いて、レプリケーション先のアカウントBのS3バケットでイベント通知の設定を行います。
レプリケーション先バケットの「プロパティ」タブを選択します。
S3_22.png

「イベント通知を作成」をクリックします。
S3_23.png

イベント名を入力します。
S3_24.png

イベント通知のタイプについては、今回はシンプルに「すべてのオブジェクト作成イベント」を選択しました。
S3_25.png

送信先は「SNSトピック」を選択します。
SNSトピックを特定の項目については「SNSトピックから選択する」を選択します。
最後に先ほど作成したトピックを選択して、「変更の保存」をクリックします。
S3_26.png

こうして、ファイルがアップロードされた時に起動するイベント通知ができました。
S3_27.png

早速、レプリケーション元のアカウントAのS3バケットにファイルを配置してみます。
S3_28.png
S3_29.png

レプリケーション先のアカウントBのバケットにもファイルがレプリケーションされており、無事にレプリケーション結果の通知も受けることができました。
S3_30.png

異常時の動作について

正常系の稼働が確認できましたので、いよいよ異常系の動作確認に入っていきます。

異常系の動作として気になったのは以下の3点です。
1.レプリケーション元のアカウントAでレプリケーションが失敗したことを検知できるか
2.レプリケーションが失敗した後に、次の別ファイルがアップロードされたらどうなるか
3.レプリケーションの自動リトライが行われるか
オンプレ環境のファイル転送だと自動リトライ処理や手動再送を実装しているかと思います。AWS環境だとそのあたりが楽になっているといいなと思い、試してみることにしました。

1.レプリケーション元のアカウントAでレプリケーションが失敗したことを検知できるか

検知を簡単に行うため、SNSで通知を受けられるようにします。
以下のようなイメージです。
S3_003.png

レプリケーション元のアカウントAのSNS通知を受け取るため、先ほどのアカウントBと同様にアカウントAでもSNSトピック、サブスクリプションを作成しておきます。

続いてアカウントAのS3バケットでイベント通知の設定を行います。
レプリケーション元バケットのプロパティタブを選択し、「イベント通知を作成」をクリックします。
S3_32.png

イベント名を設定します。
S3_31.png

今回は、イベントタイプで「オブジェクトのレプリケートに失敗しました」にチェックを入れます。
S3_33.png

送信先は「SNSトピック」を選択します。
SNSトピックを特定の項目については「SNSトピックから選択する」を選択します。
最後にアカウントBで作成したトピックを選択して、「変更の保存」をクリックします。
S3_34.png

イベント通知ができました。
S3_35.png

準備が整ったので、いよいよレプリケーションを失敗させます。
レプリケーション先のアカウントBのS3バケットでバケットポリシーを一時的に削除します。
S3_36.png

S3_37.png
S3_38.png

バケットポリシーが削除されたことで、アカウントAからアカウントBへのレプリケーションはできなくなりました。
この状態で、アカウントAのバケットにファイルをアップします。
S3_39.png

アカウントBのバケットにはファイルがレプリケーションされません。
S3_41.png

また、アカウントA側でレプリケーション失敗について、以下のような内容のSNS通知を受けることができました。

{"Records":[{"eventVersion":"2.2","eventSource":"aws:s3","awsRegion":"ap-northeast-1","eventTime":"2024-11-16T12:56:16.172Z","eventName":"Replication:OperationFailedReplication","userIdentity":{"principalId":"s3.amazonaws.com"},"requestParameters":{"sourceIPAddress":"s3.amazonaws.com"},"responseElements":{〜},"s3":{"s3SchemaVersion":"1.0","configurationId":"S3-error-event","bucket":{"name":"source-bucket-202411","ownerIdentity":{"principalId":"※***********"},"arn":"arn:aws:s3:::source-bucket-202411"},"object":{"key":"replication-error.pdf","size":12179011,〜}},"replicationEventData":{"replicationRuleId":"replication-test","destinationBucket":"arn:aws:s3:::destination-bucket-202411","s3Operation":"OBJECT_PUT","requestTime":"2024-11-16T12:55:17.749Z","failureReason":"DstPutObjectNotPermitted"}}]}

結論、レプリケーションの失敗を検知して次のアクションを起こすことはできることを確認しました。

2.レプリケーションが失敗した後に、次の別ファイルがアップロードされたらどうなる?

続いて、レプリケーションが失敗した上記の状態からレプリケーション先のバケットのアクセスポリシーを再度付与して復旧させます。
S3_40.png
失敗したファイルreplication-error.pdfがある状態で、同じバケットに新しいファイルreplication-error2.pdfがアップロードされたらどうなるでしょうか。

レプリケーションに失敗したファイルがある状態で、アカウントAのバケットに、新しいファイルreplication-error2.pdfをアップロードしてみます。
S3_46.png

結果、追加でアップロードされたreplication-error2.pdfだけがレプリケーションされました。
権限不足でレプリケーションに失敗したreplication-error.pdfはレプリケーションされないままでした。
ファイルごとのステータスをちゃんと見て、レプリケーションの判断をしているということですね。
S3_47.png

3.レプリケーションの自動リトライが行われるか

さて、レプリケーションが失敗したファイルreplication-error.pdfは、バケットポリシーで権限が付与された後、どうなったでしょうか。

15分以上待ちましたが、アカウントBのバケットにreplication-error.pdfはレプリケーションされませんでした。
S3_48.png

マニュアルを読み進めてみたところ、以下の記載がありました。

オブジェクトをアップロードした後で、オブジェクトのレプリケーションに失敗した場合、レプリケーションを再試行できません。オブジェクトを再度アップロードするか、S3 バッチレプリケーションを使用して失敗したオブジェクトをレプリケートする必要があります。

さらに、以下の記載もありました。

レプリケーションロールの許可、AWS Key Management Service (AWS KMS) 許可、またはバケットの許可がないなどの問題がある場合、オブジェクトは FAILED ステータスに移行します。バケットやリージョンが使用できないなどの一時的な障害が発生した場合、レプリケーションのステータスは FAILED にはならず、PENDING のままになります。リソースがオンラインに戻ると、Amazon S3 はこれらのオブジェクトのレプリケーションを再開します。

何らかの障害で失敗した場合はPENDINGステータスになって、自動でレプリケーションが再開されるようですので、再レプリケーションは基本的に実行されそうですね。
一方で、ステータスを意識してリトライやアラートをあげる等、もう少し考えるところはありそうです。

ちなみに、レプリケーションに失敗したファイルreplication-error.pdfのステータスを確認してみました。
権限不足でレプリケーションに失敗したreplication-error.pdfは、たしかにレプリケーションステータスが、FAILEDになっていました。
S3_42.png

マニュアル通りですね。(最初から読めばよかった。。)

再度手動でファイルをアップロードしました。
S3_43.png
S3_44.png

最終的に、アカウントBへファイルがレプリケーションされました。
S3_45.png

まとめ

S3のクロスアカウントレプリケーションは、アカウント間において非同期でファイルを連携する処理に十分使えることが分かりました。
レプリケーション後の処理も非同期で実装でき、レプリケーション先のアカウントでイベント検知もできますので、SQSやEventBridge等を連携して後続処理が実装できますので、非常に便利だと思います。
レプリケーション失敗時の動作などを意識しながら活用していきたいと思います。

以上、今回はS3 クロスアカウントレプリケーション をお試ししてみました。
どなたかの参考になれば幸いです。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?