web-dev-qa-db-ja.com

s3からgetObjectを取得するとアクセスが拒否されるAWSラムダ関数

Lambda関数でS3 AWSサービスからアクセス拒否エラーが発生しています。

これはコードです:

// dependencies
var async = require('async');
var AWS = require('aws-sdk');
var gm = require('gm').subClass({ imageMagick: true }); // Enable ImageMagick integration.

exports.handler = function(event, context) {
    var srcBucket = event.Records[0].s3.bucket.name;
    // Object key may have spaces or unicode non-ASCII characters.
    var key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));
/*
{
    originalFilename: <string>,
    versions: [
        {
            size: <number>,
            crop: [x,y],
            max: [x, y],
            rotate: <number>
        }
    ]
}*/
    var fileInfo;
    var dstBucket = "xmovo.transformedimages.develop";
    try {
        //TODO: Decompress and decode the returned value
        fileInfo = JSON.parse(key);
        //download s3File

        // get reference to S3 client
        var s3 = new AWS.S3();

        // Download the image from S3 into a buffer.
        s3.getObject({
                Bucket: srcBucket,
                Key: key
            },
            function (err, response) {
                if (err) {
                    console.log("Error getting from s3: >>> " + err + "::: Bucket-Key >>>" + srcBucket + "-" + key + ":::Principal>>>" + event.Records[0].userIdentity.principalId, err.stack);
                    return;
                }

                // Infer the image type.
                var img = gm(response.Body);
                var imageType = null;
                img.identify(function (err, data) {
                    if (err) {
                        console.log("Error image type: >>> " + err);
                        deleteFromS3(srcBucket, key);
                        return;
                    }
                    imageType = data.format;

                    //foreach of the versions requested
                    async.each(fileInfo.versions, function (currentVersion, callback) {
                        //apply transform
                        async.waterfall([async.apply(transform, response, currentVersion), uploadToS3, callback]);

                    }, function (err) {
                        if (err) console.log("Error on excecution of watefall: >>> " + err);
                        else {
                            //when all done then delete the original image from srcBucket
                            deleteFromS3(srcBucket, key);
                        }
                    });
                });
            });
    }
    catch (ex){
        context.fail("exception through: " + ex);
        deleteFromS3(srcBucket, key);
        return;
    }
        function transform(response, version, callback){
            var imageProcess = gm(response.Body);
            if (version.rotate!=0) imageProcess = imageProcess.rotate("black",version.rotate);
            if(version.size!=null) {
                if (version.crop != null) {
                    //crop the image from the coordinates
                    imageProcess=imageProcess.crop(version.size[0], version.size[1], version.crop[0], version.crop[1]);
                }
                else {
                    //find the bigger and resize proportioned the other dimension
                    var widthIsMax = version.size[0]>version.size[1];
                    var maxValue = Math.max(version.size[0],version.size[1]);
                    imageProcess=(widthIsMax)?imageProcess.resize(maxValue):imageProcess.resize(null, maxValue);
                }
            }


            //finally convert the image to jpg 90%
            imageProcess.toBuffer("jpg",{quality:90}, function(err, buffer){
                if (err) callback(err);
                callback(null, version, "image/jpeg", buffer);
            });

        }

        function deleteFromS3(bucket, filename){
            s3.deleteObject({
                Bucket: bucket,
                Key: filename
            });
        }

        function uploadToS3(version, contentType, data, callback) {
            // Stream the transformed image to a different S3 bucket.
            var dstKey = fileInfo.originalFilename + "_" + version.size + ".jpg";
            s3.putObject({
                Bucket: dstBucket,
                Key: dstKey,
                Body: data,
                ContentType: contentType
            }, callback);
        }
};

これはCloudwatchのエラーです。

AccessDenied: Access Denied

これはスタックエラーです。

at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/services/s3.js:329:35)

at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20) 

at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)

at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:596:14)

at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:21:10) 

at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12) 

at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10 

at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:37:9) 

at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:598:12) 

at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:115:18)

S3バケットに関する他の説明や情報がない場合、すべてのユーザーがリストを作成して削除できます。

S3バケットにアクセスするにはどうすればよいですか?

PS:Lambdaイベントプロパティでは、プリンシパルは正しく、管理者権限を持っています。

31
cyberdantes

Lambdaには(S3:GetObject)権限がありません。

IAMダッシュボードに移動し、Lambdaの実行に関連付けられているロールを確認します。 AWSウィザードを使用する場合、oneClick_lambda_s3_exec_roleというロールが自動的に作成されます。 Show Policyをクリックします。添付画像に似たものが表示されるはずです。 S3:GetObjectがリストされていることを確認してください。

enter image description here

34
helloV

私はこの問題に出くわし、IAMポリシーが何時間も狂った後、解決策は次のとおりでした。

  1. S3コンソールに移動
  2. 興味のあるバケットをクリックします。
  3. 「プロパティ」をクリックします
  4. 「許可」を展開する
  5. 「アクセス許可を追加する」をクリックします
  6. ドロップダウンから[認証されたAWSユーザー]を選択します。 [アップロード/削除]と[リスト](またはラムダに必要なもの)を選択します。
  7. 「保存」をクリックします

できた慎重に作成されたIAMロールポリシーは重要ではなく、特定のバケットポリシーも重要ではありません(機能させるためにそれらも作成しました)。または、私のアカウントでは機能しません。

[編集]

多くの調整を行った後、上記のアプローチは最適ではありません。これを試して:

  1. HelloV投稿のように役割ポリシーを保持します。
  2. S3に移動します。バケットを選択します。許可をクリックします。 [バケットポリシー]をクリックします。
  3. 次のようなものを試してください:
{
    "Version": "2012-10-17",
    "Id": "Lambda access bucket policy",
    "Statement": [
        {
            "Sid": "All on objects in bucket lambda",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::AWSACCOUNTID:root"
            },
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::BUCKET-NAME/*"
        },
        {
            "Sid": "All on bucket by lambda",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::AWSACCOUNTID:root"
            },
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::BUCKET-NAME"
        }
    ]
}

私のために働いたので、認証されたすべてのAWSユーザーと共有する必要はありません(ほとんどの場合、理想的ではありません)。

18
Adam Owczarczyk

興味深いことに、ファイルが存在しない場合、AWSは403(アクセス拒否)を返します。ターゲットファイルがS3バケットにあることを確認してください。

15
vedat

Resourceを指定する場合は、サブフォルダーの指定も忘れずに追加してください。このような:

"Resource": [
  "arn:aws:s3:::BUCKET-NAME",
  "arn:aws:s3:::BUCKET-NAME/*"
]
12
TheVTM

私もこの問題に遭遇しました。s3:GetObject*は、そのオブジェクトのバージョンを取得しようとしているACL内にあります。

3
Steven Lu

S3バケットに暗号化を設定している場合(AWS KMSなど)、Lambda関数に適用されたIAMロールがIAM>暗号化キー> region> key>キーユーザーS3バケットを保存中に暗号化するために使用した対応するキー。

たとえば、スクリーンショットでは、Lambda関数にIAMのKey Userとして適用したCyclopsApplicationLambdaRoleロールを追加しましたS3バケットの暗号化に使用したのと同じAWS KMSキーに対して。 Encryption keysUIを開くときに、キーの正しい領域を選択することを忘れないでください。

Lambda関数に適用した実行ロールを見つけます: screenshot of Lambda execution role

S3バケットに暗号化を追加するために使用したキーを見つけます: screenshot of the key selected for the S3 bucket

IAM>暗号化キーで、地域を選択し、キー名をクリックします: screenshot of region dropdown in IAM

S3で指定されたキーのIAM暗号化キーにキーユーザーとしてロールを追加します。 screenshot of IAM key users selection

1
Danny Bullis

S3からファイルを読み取って、ファイル読み取りの内容を変更して新しいファイルを作成しようとしました(Lambda + Node)。 S3からのファイルの読み取りに問題はありませんでした。 S3バケットに書き込もうとすると、「アクセスが拒否されました」というエラーが表示されます。

上記のすべてを試しましたが、「アクセス拒否」を取り除くことができませんでした。最後に、バケットのすべてのユーザーに「オブジェクトのリスト」権限を付与することで、機能させることができました。 S3 Bucket Access Control List

明らかにこれは最善のアプローチではありませんが、他に何も機能しませんでした。

1
imTheManager

基本的な設計図を実行しようとしましたPython lambda関数[コード例])同じ問題がありました。実行ロールはlambda_basic_execution

S3>(ここに自分のバケット名)> permissionsに行きました。

S3:BucketPolicyView

私は初心者なので、JSONを自分で記述するのではなく、Amazonが提供するPolicy Generatorを使用しました: http://awspolicygen.s3。 amazonaws.com/policygen.html 私のJSONは次のようになります。

{
    "Id": "Policy153536723xxxx",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt153536722xxxx",
            "Action": [
                "s3:GetObject"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:s3:::tokabucket/*",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::82557712xxxx:role/lambda_basic_execution"
                ]
            }
        }
    ]

そして、コードはうまく実行されました:

foo

1
O95

他のすべてのポリシーアヒルが並んでいる場合、オブジェクトが存在せず、要求者がバケットに対するListObjects権限を持っていない場合、S3は引き続きアクセス拒否メッセージを返します。

から https://docs.aws.Amazon.com/AmazonS3/latest/API/RESTObjectGET.html

...リクエストしたオブジェクトが存在しない場合、Amazon S3が返すエラーは、s3:ListBucketアクセス許可も持っているかどうかによって異なります。

バケットに対するs3:ListBucketアクセス許可がある場合、Amazon S3はHTTPステータスコード404( "no such key")エラーを返します。 s3:ListBucketアクセス許可がない場合、Amazon S3はHTTPステータスコード403(「アクセス拒否」)エラーを返します。

1
Jeremiah

私はこの問題に何時間も苦労していました。私はAmazonS3EncryptionClientを使用していましたが、何も助けませんでした。次に、クライアントが実際に非推奨になっていることに気付いたので、クライアントのビルダーモデルに切り替えてみようと思いました。

var builder = AmazonS3EncryptionClientBuilder.standard()
  .withEncryptionMaterials(new StaticEncryptionMaterialsProvider(encryptionMaterials))
if (accessKey.nonEmpty && secretKey.nonEmpty) builder = builder.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey.get, secretKey.get)))
builder.build()

そして...それはそれを解決しました。 Lambdaは古いモデルで認証情報を注入するのに問題があるように見えますが、新しいモデルではうまく機能します。

0
yi1