背景
マネコンを経由してクロスアカウントのS3アップロードをやりたいです。
バケットのオブジェクト所有者を「ACL無効」→バケット所有者強制(BucketOwnerEnforced)に設定します。
設定
・アカウントAのS3バケットポリシーでアカウントBに対するアップロード権限を付与する
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::<アカウントBのID>:role/<ロール名>"
]
},
"Action": [
"s3:ListBucket",
"s3:GetBucketVersioning",
"s3:DeleteObject",
"s3:PutObject",
"s3:PutObjectTagging"
],
"Resource": [
"arn:aws:s3:::<S3バケット名>",
"arn:aws:s3:::<S3バケット名>/*",
]
}
]
}
・アカウントBのロールポリシーでアカウンAのS3バケットに対するアップロード権限を付与する
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::<アカウントAのS3バケット>"
]
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::<アカウントAのS3バケット>/*"
]
}
]
}
エラー
アカウントBの該当ロールを使ってマネコンからファイルをアカウントAのS3バケットへアップロードする時に「AccessControlListNotSupported」エラーが出ました。
ブラウザーでネットワークの状況をデバッグすると「x-amz-acl」が「private」に設定しているので、間違えています。
※正しいのは「bucket-owner-full-control」です
解決方法
アカウントAのバケットポリシーとアカウントBのロールポリシーのAction
に下記「GetBucketOwnershipControls」権限を追加します。
"s3:GetBucketOwnershipControls"
原因分析
バケット所有者強制(BucketOwnerEnforced)を設定する場合(他のアカウント所有も同じ)、既定ACLをアップロード元で設定する仕組みとなります。加えて、既定ACLをbucket-owner-full-control
に設定しないとアップロードが失敗するわけです。
しかし、s3:GetBucketOwnershipControls
が許可しない場合、マネコンからアップロードする時、デフォルトACL許可: privateしかを利用できないから、AccessControlListNotSupported
エラーになります。
エラーを防ぐため、s3:GetBucketOwnershipControls
APIのコールでObjectOwnership設定を事前に確認して、正しいACL設定を実施します。
さらに深掘りすると、ACLの設定の「❗️重要」による、下記の記載があります。
ACL の設定または ACL の更新の要求に失敗すると、AccessControlListNotSupported エラーコードを返します。ACL の読み取り要求は引き続きサポートされています。
自分の考えだと、ACLでS3権限を制御することは最初からの仕組み、最近はACL無効化という機能がリリースしたばかりなので、バケットをACL無効(バケット所有者強制)に設定しても、互換性を持つためにACLの読み取りが続いてサポートしています。というのはACLという機能が実際に裏で動いています、なのでせめてACL参照権限をアップロード元に付与しないとアップロード元はバケット所有者設定はどうなっているのが知らないです。この場合既定ACLはデフォルトでprivate
を設しかできないです。