スイッチロールを使用している場合のクロスアカウントでS3バケット同期(aws s3 sync)


スイッチロールを使用している異なるアカウントのS3バケット間で同期する方法について調べました。
一先ず解決したのでメモします。

やりたい事

スイッチロールを使用しているアカウントA(同期元)のS3バケットから
スイッチロールを使用しているアカウントB(同期先)のS3バケットにaws s3 syncコマンドで同期する。

同期対象のS3バケットに設定するバケットポリシー

スイッチロールを使用している場合、一定時間経過するとセッションIDが変わってしまいます。
Principalは名前またはARNの一部に一致させる指定ができないため、Principalではすべてを対象にしてConditionで絞るようにしています。
※ワイルドカード(*)は、すべてのユーザーまたはパブリックアクセスを表すので使用の際は注意。

アカウントAのS3バケットポリシー
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "xxx",
      "Effect": "Allow",
      "Principal": "*",
      "Action": [
        "s3:ListBucket",
        "s3:GetObject"
      ],
      "Resource": [
        "arn:aws:s3:::<アカウントAの同期対象S3バケット名>",
        "arn:aws:s3:::<アカウントAの同期対象S3バケット名>/*"
      ],
      "Condition": {
        "StringLike": {
          "aws:userId": [
              "<アカウントBのRoleId>:*"
          ]
        }
      }
    }
  ]
}

RoleIdをコマンドを使って調べる

Conditionで指定しているRoleIdは以下のコマンドを使用して調べます。
RoleIdの文字列xxxxxxxxxxxxxxxxxxxxxを使用します。

RoleIdを調べる
// aws iam get-role --role-name <ロール名> --profile <プロファイル名>
$ aws iam get-role --role-name AdminRole --profile dev-b
{
    "Role": {
        "Path": "/",
        "RoleName": "AdminRole",
        "RoleId": "xxxxxxxxxxxxxxxxxxxxx",        ←これ
        "Arn": "arn:aws:iam::accountid:role/AdminRole",
        "CreateDate": "2020-00-00T00:00:00Z",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": "arn:aws:iam::accountid:root"
                    },
                    "Action": "sts:AssumeRole"
                }
            ]
        },
        "Description": "",
        "MaxSessionDuration": 3600,
        "RoleLastUsed": {
            "LastUsedDate": "2020-00-00T00:00:00Z",
            "Region": "ap-northeast-1"
        }
    }
}

以下のコマンドでも調べられます。
UserIdのxxxxxxxxxxxxxxxxxxxxxがRoleIdになります。

RoleIdを調べる
// aws sts get-caller-identity --profile <プロファイル名>
$ aws sts get-caller-identity --profile dev-b
{
    "UserId": "xxxxxxxxxxxxxxxxxxxxx:botocore-session-0000000000",
    "Account": "accountid",
    "Arn": "arn:aws:sts::accountid:assumed-role/AdminRole/botocore-session-0000000000"
}

同期に使用するコマンド

同期先のスイッチロールを使用して、同期コマンドを実行します。
スイッチロールは同期先S3バケットへの以下の権限を持っている必要があります。
必要な権限:s3:ListBucket、s3:PutObject、s3:PutObjectAcl

コマンド例:アカウントAからアカウントBへの同期
aws s3 sync \
 --exact-timestamps \
 --delete \
 s3://アカウントA(同期元)S3バケット \
 s3://アカウントB(同期先)S3バケット \
 --profile アカウントBのプロファイル

--exact-timestamps

デフォルトではサイズが変わらない場合は無視されます。
タイムスタンプに変更があった場合も同期されるように指定します。

--delete

デフォルトでは削除されたファイルは同期先で削除されません。
削除されたファイルも同期先で削除されるように指定します。

プロファイル

スイッチロールを使用している場合、プロファイルは以下のように設定し、
<スイッチ後プロファイル名>を--profileに指定します。

.aws/credentials
[<スイッチ前プロファイル名>]
aws_access_key_id = <アクセスキー>
aws_secret_access_key = <シークレットアクセスキー>
.aws/config
[<スイッチ前プロファイル名>]
output = json
region = ap-northeast-1

[profile <スイッチ後プロファイル名>]
role_arn = arn:aws:iam::<アカウントBのアカウントID>:role/<使用するロール名>
source_profile = <スイッチ前プロファイル名>
region = ap-northeast-1
output = json

権限について補足

上記設定では同期向きの可不可は以下になります。
(AdministratorAccess権限を持ったアカウントBのプロファイルで実行した場合)
可 :アカウントA -> アカウントB
不可:アカウントB -> アカウントA
不可:ローカル -> アカウントA
可 :ローカル -> アカウントB
可 :アカウントA -> ローカル
可 :アカウントB -> ローカル

参考

https://dev.classmethod.jp/articles/cross-account-s3-sync/
https://qiita.com/n-ishida/items/33cef1d67adc0961625a
https://dev.classmethod.jp/articles/s3-sync-exact-timestamps/
https://dev.classmethod.jp/articles/what-permissions-are-needed-for-s3-sync/
https://docs.aws.amazon.com/cli/latest/reference/s3/sync.html
https://aws.amazon.com/jp/premiumsupport/knowledge-center/copy-s3-objects-account/
https://dev.classmethod.jp/articles/test-s3-sync/
https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-require-object-ownership/