バンクーバーで去り行く夏を惜しんでいる 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-props
で none
を指定する
aws s3 cp
やaws 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 以上の場合に実施されます。
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 のファイルでも問題なくクロスアカウントコピーが成功しました。