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

时间:2016-02-23 22:36:26

标签: amazon-web-services amazon-s3 aws-lambda amazon-iam

我的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);
        }
};

这是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事件属性上,主体是正确的并具有管理权限。

11 个答案:

答案 0 :(得分:30)

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

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

enter image description here

答案 1 :(得分:17)

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

  1. 转到S3控制台
  2. 点击您感兴趣的存储桶。
  3. 点击“属性”
  4. 展开'权限'
  5. 点击“添加更多权限”
  6. 从下拉列表中选择“任何经过身份验证的AWS用户”。选择“上传/删除”和“列表”(或lambda所需的任何内容)。
  7. 点击“保存”
  8. 完成。 您精心编写的IAM角色策略无关紧要,特定的存储桶策略也没有关系(我也写过这些策略以使其工作)。或者他们只是不在我的帐户上工作,谁知道。

    [编辑]

    经过大量的修修补补,上述方法并不是最好的。试试这个:

    1. 将您的角色政策保留在helloV帖子中。
    2. 转到S3。选择你的水桶。单击“权限”。单击“存储桶策略”。
    3. 尝试这样的事情:
    4. {
          "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用户共享(大部分时间都不理想)。

答案 2 :(得分:15)

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

答案 3 :(得分:3)

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

答案 4 :(得分:1)

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

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

  

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

     

如果你对存储桶有s3:ListBucket权限,那么Amazon S3会   返回HTTP状态代码404(“无此键”)错误。如果你不这样做   拥有s3:ListBucket权限,Amazon S3将返回HTTP   状态代码403(“访问被拒绝”)错误。

答案 5 :(得分:1)

我尝试执行基本的蓝图Python lambda函数[示例代码],但遇到了同样的问题。我的执行职务是lambda_basic_execution

我去了S3>(这里是我的存储桶名称)>权限。

S3:BucketPolicyView

因为我是初学者,所以我使用了Amazon提供的 Policy Generator ,而不是自己编写JSON: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

答案 6 :(得分:1)

如果您在S3存储桶上设置了加密(例如AWS KMS),则可能需要确保将应用于Lambda函数的IAM角色添加到 IAM列表中>加密密钥> 区域> 密钥>密钥用户,用于您在静止时对S3存储桶进行加密的相应密钥。

例如,在我的屏幕截图中,我添加了 CyclopsApplicationLambdaRole 角色,该角色已作为IAM中的 Key User 应用于IAM的Lambda函数中,用于相同的AWS KMS密钥,我曾经对S3存储桶进行加密。打开加密密钥用户界面时,请不要忘记为密钥选择正确的区域。

找到已应用于Lambda函数的执行角色: screenshot of Lambda execution role

找到用于向S3存储桶添加加密的密钥: screenshot of the key selected for the S3 bucket

在IAM>加密密钥中,选择您的区域,然后单击密钥名称: screenshot of region dropdown in IAM

在IAM加密密钥中为S3中指定的密钥添加作为密钥用户的角色: screenshot of IAM key users selection

答案 7 :(得分:0)

我几个小时都在努力解决这个问题。我使用的是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无法在旧模型中注入凭据,但在新模型中运行良好。

答案 8 :(得分:0)

我试图从s3中读取文件,并通过更改读取的文件(Lambda + Node)的内容来创建新文件。从S3读取文件没有任何问题。尝试写入S3存储桶后,我立即收到“访问被拒绝”错误。

我尝试了上面列出的所有方法,但无法摆脱“访问被拒绝”的问题。最终,我可以通过向存储桶中的每个人授予“列表对象”权限来使其工作。 S3 Bucket Access Control List

显然,这不是最好的方法,但没有其他方法起作用。

答案 9 :(得分:0)

我按照AWS - How do I allow my Lambda execution role to access my Amazon S3 bucket?的所有说明解决了我的问题:

  1. 为Lambda函数创建一个AWS Identity and Access Management(IAM)角色,以授予对S3存储桶的访问权限。

  2. 修改IAM角色的信任策略。

  3. 将IAM角色设置为Lambda函数的执行角色。

  4. 验证存储桶策略是否授予对Lambda函数执行角色的访问权限。

答案 10 :(得分:0)

在使用Lambda函数裁剪s3图像时,出现了相同的错误“ AccessDenied:访问被拒绝”。我按照下面给出的文档链接更新了s3存储桶策略和IAM角色内联策略。

但是,我仍然遇到相同的错误。然后我意识到,我试图在私有存储桶中提供“公开读取”访问权限。删除ACL后:从S3.putObject问题'public-read'得到解决。

https://aws.amazon.com/premiumsupport/knowledge-center/access-denied-lambda-s3-bucket/