クロスアカウントで容量の大きいオブジェクトのコピーを行った際に GetObjectTagging operation: Access Denied エラーが発生するので検証してみた

GetObjectTagging の権限を付与するか、オプション --copy-props を追加することで対応が可能です。
2023.09.30

バンクーバーで去り行く夏を惜しんでいる Funa です。
今回はクロスアカウントでs3 cpコマンドを実行する際にエラーが発生したので、それについてブログ化したいと思います。

エラー内容

クロスアカウントで容量の大きいオブジェクトのコピーを行った際に GetObjectTagging operation: Access Denied エラーが発生しました。

$ aws s3 cp s3://source-BUCKET/object s3://destination-BUCKET/
copy failed: s3://source-BUCKET/object to s3://destination-BUCKET/object
An error occurred (AccessDenied) when calling the GetObjectTagging operation: Access Denied

AWS CLI のバージョンは以下の通りです。

$ aws --version
aws-cli/2.9.17 Python/3.11.1 Darwin/22.6.0 source/x86_64 prompt/off

対応方法

これは AWS CLI バージョン 2 のコマンドではマルチパートコピーの際にデフォルトでタグを含めたプロパティをコピーする挙動となっているために発生します。

対応方法としては、以下のいずれかとなります。

GetObjectTagging の権限を IAM ポリシーに付与する

AWS CLI を使用して EC2 を介してクロスアカウントでのマルチパートコピーを行う場合は、以下のような IAM ポリシーを IAM ロールに付与して EC2 にアタッチします。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetObject",
                "s3:GetObjectTagging" //これを追加する
            ],
            "Resource": [
                "arn:aws:s3:::<送信元バケット名>",
                "arn:aws:s3:::<送信元バケット名>/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::<送信先バケット名>",
                "arn:aws:s3:::<送信先バケット名>/*"
            ]
        }
    ]
}

② オプション --copy-propsnone を指定する

aws s3 cpaws s3 sync コマンドを使用する際にオプション --copy-props にて none を指定してソースオブジェクトのプロパティを含まないようにします。

cp | AWS CLI Command Reference, v2

--copy-props (string) Determines which properties are copied from the source S3 object. This parameter only applies for S3 to S3 copies. Valid values are:

none - Do not copy any of the properties from the source S3 object.

①でご対応いただくことが簡単かと思いますが、要件によっては IAM ポリシーを変更できない場合もあるかと思いますので、②で対応を行う場合について検証してみたいと思います。

検証してみた

前提

以下の AWS CLI リファレンスにあるように、AWS CLI でのマルチパートコピーは 8MB 以上の場合に実施されます。

AWS CLI S3 Configuration

multipart_threshold

Default - 8MB

When uploading, downloading, or copying a file, the S3 commands will switch to multipart operations if the file reaches a given size threshold.

そのため、マルチパートコピーの対象外である 1 MB のファイルと、マルチパートコピーの対象である 20 MB のファイルを用意して検証を行います。

ファイルのアップロード

まずはファイル送信元であるアカウント A の S3 バケット(test-1218-cmca1) にファイルをアップロードしていきます。

1 MB のファイルを S3 バケットにアップロードします。

$ aws s3 cp dogo.png s3://test-1218-cmca1/

dd コマンドで 20 MB のファイルを作成し、S3 バケットにアップロードします。

$ dd if=/dev/zero of=test20M bs=1M count=20
$ aws s3 cp test20M s3://test-1218-cmca1/

IAM の設定

そしてファイル送信元のアカウント A に EC2 インスタンスを立ち上げ、以下の IAM ポリシー (S3-test-policy0929) を含んだ IAM ロール (testrole) を紐付けます。

  • 送信元バケット(test-1218-cmca1)
  • 送信先バケット(test-178-20230107)
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::test-1218-cmca1",
                "arn:aws:s3:::test-1218-cmca1/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::test-178-20230107",
                "arn:aws:s3:::test-178-20230107/*"
            ]
        }
    ]
}

次に送信先であるアカウント B の送信先バケット(test-178-20230107) に以下のバケットポリシーを設定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<アカウントAのAWSアカウントID>:role/testrole"
            },
            "Action": [
                "s3:GetBucketLocation",
                "s3:ListBucket"
            ],
            "Resource": "arn:aws:s3:::test-178-20230107"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<アカウントAのAWSアカウントID>:role/testrole"
            },
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::test-178-20230107/*"
        }
    ]
}

クロスアカウントでの s3 cp コマンドの実行

アカウント A の EC2インスタンス に SSH 接続をして、クロスアカウントでのコピーを行います。

① 1 MB のファイルのクロスアカウントコピー

$ aws s3 cp s3://test-1218-cmca1/dogo.png s3://test-178-20230107/
copy: s3://test-1218-cmca1/dogo.png to s3://test-178-20230107/dogo.png

1 MB のファイルのクロスアカウントコピーは、オプションの指定なしでも成功しました。

② 20 MB のファイルのクロスアカウントコピー

$ aws s3 cp s3://test-1218-cmca1/test20M s3://test-178-20230107/
copy failed: s3://test-1218-cmca1/test20M to s3://test-178-20230107/test20M An error occurred (AccessDenied) when calling the GetObjectTagging operation: Access Denied

オプションの指定なしでの 20 MB のファイルのクロスアカウントコピーは、GetObjectTagging operation の Access Denied エラーによって失敗しました。

$ aws s3 cp s3://test-1218-cmca1/test20M s3://test-178-20230107/ --copy-props none
copy: s3://test-1218-cmca1/test20M to s3://test-178-20230107/test20M

そこで --copy-props オプションで none を指定すると、20 MB のファイルでも問題なくクロスアカウントコピーが成功しました。

参照情報