古いS3バケットでの連携に注意
先日、 数年前からAWSで稼働している 自システム(A)が、別のAWSシステム(B)のデータをS3経由で受け取れるように、 アカウントA側を設定しました。
{ "Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "AWS" : "アカウントBのID" },
"Action": ["s3:ListBucket", "s3:PutObject", "s3:GetObject"],
"Resource": ["arn:aws:s3:::バケット名", "arn:aws:s3:::バケット名/*"]}]}
上記の設定後、アカウントB側で連携ファイル書き込みを行う主体のIAMロールに対して、アカウントA側のS3への書き込みを許可するポリシーを設定を行い、無事バケット上に連携ファイルの保存ができるようになりました。(やったね!)
……と、ここまでは良かったのですが、その連携ファイルを アカウントA側で読み取ろうとすると Access Denied
となってしましました。
「え? 自分のバケット上のファイルなのに何で自分で読み込めないの? 」
自アカウントのバケットなのにファイルを読み込めなかった原因
原因は保存された連携ファイルの所有者に置いた人(アカウントB)が設定されていたためです。
下記ドキュメントを見ればわかりますが、S3はオブジェクト単位でACLを持つことが可能です。
S3 オブジェクト所有権は、Amazon S3 バケットレベルの設定で、バケットにアップロードされたオブジェクトの所有権を制御し、アクセスコントロールリスト (ACL) を有効または無効にするのに使用できます。デフォルトでは、オブジェクト所有権は[バケット所有者の強制] 設定に設定され、すべての ACL は無効になっています。ACL が無効になっている場合、バケット所有者はバケット内のすべてのオブジェクトを所有し、アクセス管理ポリシーのみを使用してデータへのアクセスを管理します。
Amazon S3 の最新のユースケースの大部分では ACL を使用する必要がなくなっています。そのため、オブジェクトごとに個別にアクセスを制御する必要がある異常な状況を除き、ACL を無効にしておくことをお勧めします。 ACL を無効にすると、バケット内のオブジェクトをアップロードしたユーザーに関係なく、ポリシーを使用してバケット内のすべてのオブジェクトへのアクセスをより簡単に制御できます。
現時点で普通にS3バケットを作成した場合、バケットのオブジェクトはバケットのオーナーの持ち主になるようにデフォルトで設定されますが、古いバケットはそうなっていない可能性があります。 そういった場合、今回の私のケースのように他アカウントから書き込まれたファイルを読み込めなくなります。
バケットはTerraformで管理していたため、下記のようなリソースを追加してバケットのACLの挙動を無効にしました。
resource "aws_s3_bucket_ownership_controls" "data_sync" {
bucket = aws_s3_bucket.data_sync.id
rule {
object_ownership = "BucketOwnerEnforced"
}
}
(AWSマネージメントコンソールからは、 該当のS3バケット → Permissions → Object Ownership のセクションを確認)
まとめ
自バケットのオブジェクトをなぜか読み込めない場合は所有者やバケットのデフォルトオブジェクト所有権の設定をチェックしましょう。