从s3获取getObject时,aws lambda函数获取访问权限

cyb*_*tes 31 amazon-s3 amazon-web-services amazon-iam aws-lambda

我在Lambda函数上从S3 AWS服务获得了acccess denied错误.

这是代码:

// 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);
        }
};
Run Code Online (Sandbox Code Playgroud)

这是Cloudwatch上的错误:

AccessDenied: Access Denied
Run Code Online (Sandbox Code Playgroud)

这是堆栈错误:

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)
Run Code Online (Sandbox Code Playgroud)

没有任何其他描述或信息S3存储桶权限允许每个人放置列表和删除.

如何访问S3存储桶?

PS:在Lambda事件属性上,主体是正确的并具有管理权限.

hel*_*loV 35

您的Lambda没有特权(S3:GetObject).

转到IAM仪表板,检查与Lambda执行相关联的角色.如果您使用AWS向导,它会自动创建一个名为的角色oneClick_lambda_s3_exec_role.点击Show Policy.它应该显示类似于附加图像的东西.确保S3:GetObject列出.

在此输入图像描述

  • 我通过将"/*"附加到Resource属性来解决了这个问题,例如arn:aws:s3 ::: some-bucket-name/* (4认同)
  • 然后最好的解决方案是允许S3FullAccess,看它是否有效.如果是,则从策略中一次删除一组访问权限,并找到Lambda工作所需的最小权限.如果在给出S3FullAccess之后它仍然不起作用,那么问题出在其他地方. (2认同)
  • 如果您尝试在调用 putObject 期间显式设置 ACL,您还需要在策略中专门允许 s3:PutObjectACL 操作。 (2认同)
  • @cyberdantes 你解决了吗?我用来执行 lambda 的角色具有完整的 S3 访问权限,即 {S3:*}。但是我正在从 getObject 函数拒绝访问。 (2认同)

Ada*_*zyk 18

我遇到了这个问题,经过数小时的IAM政策疯狂,解决方案是:

  1. 转到S3控制台
  2. 点击您感兴趣的存储桶.
  3. 点击"属性"
  4. 展开'权限'
  5. 点击"添加更多权限"
  6. 从下拉列表中选择"任何经过身份验证的AWS用户".选择"上传/删除"和"列表"(或您的lambda所需的任何内容).
  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"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

为我工作,并不要求您与所有经过身份验证的AWS用户共享(大部分时间都不理想).


ved*_*dat 17

有趣的是,当文件不存在时,AWS返回403(拒绝访问).确保目标文件位于S3存储桶中.

  • 这实际上取决于您拥有的权限(请参阅 [文档](https://docs.aws.amazon.com/fr_fr/AmazonS3/latest/API/RESTObjectGET.html)) - 如果您拥有 `s3:ListBucket`存储桶上的权限,Amazon S3 将返回 HTTP 状态代码 404(“无此类密钥”)错误。- 如果您没有 `s3:ListBucket` 权限,Amazon S3 将返回 HTTP 状态代码 403(“访问被拒绝”)错误。 (10认同)
  • @Marc 对象未找到会导致 403(拒绝访问)而不是 404(未找到),因为不同的返回码会为攻击者提供有用的信息——它会泄露给定名称的对象实际存在的信息。然后,一个简单的字典式攻击就可以枚举某人存储桶中的所有对象。出于类似的原因,登录页面不应该针对两种身份验证失败情况发出“无效用户”和“无效密码”;它应该始终发出“无效凭据”。 (6认同)
  • FWIW,在我的情况下,丢失的文件是由 S3 事件中密钥的 URL 编码引起的。 (2认同)
  • 这个.我花了一个小时试图弄清楚我的"拒绝访问"错误的原因.然后检查了我的S3存储桶,并且看,object_key不存在. (2认同)
  • 这是一个有用的答案,因为我认为它与权限有关,实际上它“只是”带有德语变音符号的 url 编码问题。天哪,为什么这没有暴露为 404 ? (2认同)

The*_*VTM 15

如果您要指定资源,请不要忘记添加子文件夹规范.像这样:

"Resource": [
  "arn:aws:s3:::BUCKET-NAME",
  "arn:aws:s3:::BUCKET-NAME/*"
]
Run Code Online (Sandbox Code Playgroud)

  • 我的上帝在一个失踪的星号上浪费了3个小时 (5认同)
  • 说真的,我只是试着写从lambda到bucket的东西。如果所有政策都已到位,并且第一个资源已存在(没有... / *的资源),则无济于事。您能解释一下为什么我必须强制使用/ *吗?如果我为整个存储桶添加一条规则,似乎有点不可思议,不是吗? (2认同)

Dan*_*lis 8

如果您对您的S3存储加密设置(如AWS KMS),您可能需要确保角色应用到您的lambda函数的IAM被添加到列表中IAM>加密密钥>区域>>关键用户进行相应的您用来加密静态 S3 存储桶的密钥。

例如,在我的屏幕截图中,我添加了CyclopsApplicationLambdaRole角色,该角色已作为IAM 中的关键用户应用于我的 Lambda 函数,用于加密 S3 存储桶的同一 AWS KMS 密钥。当您打开加密密钥UI时,不要忘记为您的密钥选择正确的区域。

找到您已应用于 Lambda 函数的执行角色: Lambda 执行角色截图

找到用于向 S3 存储桶添加加密的密钥: 为 S3 存储桶选择的密钥的屏幕截图

在 IAM > Encryption keys 中,选择您的区域并单击密钥名称: IAM 中区域下拉菜单的屏幕截图

在 S3 中指定的密钥的 IAM 加密密钥中添加作为密钥用户的角色: IAM 关键用户选择截图


小智 6

如果所有其他策略鸭子都在一行中,并且该对象不存在并且请求者对该存储桶没有 ListBucket 权限,S3 仍将返回“拒绝访问”消息。

\n\n

来自https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGET.html

\n\n
\n

...如果您请求的对象不存在,Amazon S3\n 返回的错误取决于您是否也具有 s3:ListBucket 权限。

\n\n

如果您拥有存储桶的 s3:ListBucket 权限,Amazon S3 将返回 HTTP 状态代码 404(“无此类密钥”)错误。如果您\xe2\x80\x99t\n 没有 s3:ListBucket 权限,Amazon S3 将返回 HTTP\n 状态代码 403(“访问被拒绝”)错误。

\n
\n


Ste*_* Lu 5

我也遇到了这个问题,我通过s3:GetObject*在 ACL 中提供来解决这个问题,因为它试图获取该对象的一个​​版本。