はじめに
こんにちは!BFT名古屋支店のマッチです。今回はAWS S3に異なるアカウントから連携されたファイルをLambdaで読み込もうとしたところ、権限エラーで失敗したため、解決までに試したことを備忘も兼ねてご紹介します。手っ取り早く解決方法だけ知りたい方は解決手順からご覧ください。
目次
事象
以下の図のようにアカウントBからアカウントAのS3バケットにアップロードされたファイルをLambdaで読み込もうとしたところ、Permission deniedエラーにより失敗しました。
試したこと
Lambdaの割り当てポリシーの確認
まず最初に疑ったのはLambdaに割り当てられたポリシーが不足していることです。以前に似たような事象に遭遇した際はLambdaにS3へのアクセス権がなかったことが原因だったためです。
そこで、Lambdaに割り当てられたロールのポリシーを確認したところ、「AmazonS3FullAccess」が割り当てられていたため、ポリシーは問題ありませんでした。
また、AWSのコンソール画面から直接S3のファイルをダウンロードしようとした際もLambdaと同様に失敗したため、Lambdaのポリシーは原因ではなさそうです。
S3バケットのアクセス許可確認
次にS3バケットのアクセス許可設定の不足の可能性を考えました。バケットポリシーを確認したところ、アカウントBに対しての「s3:PutObject」は許可されていました。
しかし、調べてみるとそれだけでは不足しているらしく、バケットオーナー(アカウントA)にオブジェクトの所有権を移すために以下2つの設定が必要であることが分かりました。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::[アカウントBのID]:user/[ユーザーB]" }, "Action": "s3:PutObject", "Resource": "arn:aws:s3:::[バケット名]/*", "Condition": { "StringEquals": { "s3:x-amz-acl": "bucket-owner-full-control" } } } ] }
- オブジェクト所有者を「希望するバケット所有者」に変更する。
この状態で再度アカウントBからのファイルアップロードを試みましたが、今度はアップロード自体が失敗するようになってしまいました。
ファイルアップロード時のオプション追加
さらに調査したところ、S3へのアップロード時にバケットオーナーへ所有権を移すオプションである「--acl bucket-owner-full-control」を指定する必要があることが分かりました。以下はコマンドの例です。
$ aws s3 cp [ファイルパス] s3://[配置先S3 URI] --acl bucket-owner-full-control
上記オプションを追加することで無事アップロード成功し、Lambdaからの読み込みもできるようになりました。
原因
今回のエラーはアップロードされたファイルのオブジェクト所有者がアカウントBのままであったため、アカウントAからは操作できないことが原因でした。以下に解決に必要な手順を簡単にまとめます。
解決手順
バケットポリシーに「bucket-owner-full-control」オプションを追加する。
⇒ファイルアップロード時に「--acl bucket-owner-full-control」オプションの指定を必須とするため。オブジェクト所有者を「希望するバケット所有者」に変更する。
⇒「--acl bucket-owner-full-control」オプション指定でアップロードされたファイルの所有権をバケット所有者とするため。S3へのアップロード時に「--acl bucket-owner-full-control」を指定する。
⇒バケット所有者がアップロードされたファイルに対してフルアクセスできるようにするため。
おわりに
今回はS3のオブジェクト所有権についての理解が甘かったため、解決に時間がかかってしまいました。AWSで権限系のエラーが発生した際はIAMポリシーが原因だと思い込んでしまいがちですが、バケットポリシーやオブジェクトのアクセス権にも目を向ける必要があると改めて学びました。
参考
オブジェクトの所有権の制御とバケットの ACL の無効化。 - Amazon Simple Storage Service
[アップデート] オブジェクト所有権でもう悩まない!S3 バケット所有者がアップロード時に自動的にオブジェクト所有権を引き継げるようになりました。 | DevelopersIO