【问题标题】:aws lambda function getting access denied when getObject from s3当从 s3 获取对象时,aws lambda 函数被拒绝访问
【发布时间】:2023-03-25 13:47:02
【问题描述】:

我在我的 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 事件属性上,委托人是正确的并且具有管理权限。

【问题讨论】:

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


【解决方案1】:

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

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

【讨论】:

  • 该函数稍后会尝试 DeleteObject 和 PutObject,因此这些操作也必须在策略中授予。
  • 那么最好的办法就是允许S3FullAccess,看看能不能用。如果是这样,则一次从策略中删除一组访问权限,并找到您的 Lambda 工作所需的最低权限。如果即使在提供 S3FullAccess 后仍无法正常工作,则问题出在其他地方。
  • 如果您在调用 putObject 期间尝试显式设置 ACL,您还需要在策略中明确允许 s3:PutObjectACL 操作。
  • @cyberdantes 你解决了这个问题吗?我用来执行 lambda 的角色具有完整的 S3 访问权限,即 {S3:*}。但我得到 getObject 函数拒绝访问。
  • 我已通过将“/*”附加到资源属性来解决问题,例如arn:aws:s3:::some-bucket-name/*
【解决方案2】:

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

【讨论】:

  • FWIW,在我的情况下,丢失的文件是由 S3 事件中键的 URL 编码引起的。
  • 这个。我花了一个小时试图找出“拒绝访问”错误的原因。然后检查了我的 S3 存储桶,你瞧,object_key 不存在。
  • 这是一个有用的答案,因为我认为它与权限有关,实际上它“仅”是德语变音符号的 url 编码问题。看在上帝的份上,为什么不暴露为404?
  • @Marc object not found 结果为 403(拒绝访问)而不是 404(未找到),因为不同的返回码会为攻击者提供有用的信息 - 它会泄露给定名称的对象的信息存在。然后,一个简单的字典式攻击可以枚举某人存储桶中的所有对象。出于类似的原因,登录页面不应该针对两种身份验证失败场景发出“无效用户”和“无效密码”;它应该始终发出“无效凭据”。
  • 这实际上取决于您拥有的权限(请参阅the doc) - 如果您对存储桶拥有s3:ListBucket 权限,Amazon S3 将返回 HTTP 状态代码 404(“没有这样的密钥” ) 错误。 - 如果您没有s3:ListBucket 权限,Amazon S3 将返回 HTTP 状态代码 403(“拒绝访问”)错误。
【解决方案3】:

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

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

【讨论】:

  • 说真的......我刚刚尝试将一些东西从 lambda 写入存储桶。已经制定了所有政策并且第一个资源在(没有.../*的那个)没有任何效果。你能解释一下为什么我强制需要 /* 吗?如果我为整个存储桶添加规则似乎有点奇怪,不是吗?
  • 天哪 3 小时浪费在一个失踪的 asterix 上
  • @Tim.G.它无法为整个存储桶添加 GetObject 规则。您必须在对象路径上添加 GetObject 规则。 /* 是一个对象路径。对于 GetObject,“整个桶”资源完全没有任何作用。与 GetBucket 之类的东西相比,它需要一个桶。
【解决方案4】:

我遇到了这个问题,经过数小时的 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"
        }
    ]
}

为我工作,不需要您与所有经过身份验证的 AWS 用户共享(这在大多数情况下并不理想)。

【讨论】:

  • 好!我之前不知道我们需要存储桶策略来访问 S3 对象——尽管 Lambda 的 IAM 角色具有 S3FullAccess。谢谢@adam-owczarczyk。添加存储桶策略有帮助。
【解决方案5】:

如果您在 S3 存储桶上设置了加密(例如 AWS KMS),您可能需要确保将应用于您的 Lambda 函数的 IAM 角色添加到 IAM 列表中> 加密密钥 > region > key > Key Users 用于您用于加密静态 S3 存储桶的相应密钥。

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

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

查找用于向 S3 存储桶添加加密的密钥:

在 IAM > 加密密钥中,选择您的区域并单击密钥名称:

在 S3 中指定的密钥的 IAM 加密密钥中将角色添加为密钥用户:

【讨论】:

    【解决方案6】:

    如果所有其他策略鸭子都在一行中,如果对象不存在并且请求者没有存储桶的 ListBucket 权限,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(“拒绝访问”)错误。

    【讨论】:

      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

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

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

        因为我是初学者,所以我使用了亚马逊提供的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"
                        ]
                    }
                }
            ]
        

        然后代码执行得很好:

        【讨论】:

          【解决方案9】:

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

          我尝试了上面列出的所有方法,但无法摆脱“拒绝访问”。最后,我能够通过向我的存储桶中的每个人授予“列表对象”权限来使其工作。

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

          【讨论】:

          • 在相应的策略中明确定义"Action": "s3:ListBucket" 以避免这种情况。
          【解决方案10】:

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

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

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

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

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

          【讨论】:

          • 4.这不是必须的,只要你给出了允许IAM用户或角色访问bucket的Allow语句,操作就会成功
          【解决方案11】:

          我为这个问题苦苦挣扎了好几个小时。我正在使用 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 在旧模型中注入凭据时遇到问题,但在新模型中运行良好。

          【讨论】:

            【解决方案12】:

            我在使用 lambda 函数裁剪 s3 图像时遇到了同样的错误“AccessDenied: Access Denied”。我根据下面给出的文档链接更新了 s3 存储桶策略和 IAM 角色内联策略。

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

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

            【讨论】:

              【解决方案13】:

              在将 boto3 与 python 结合使用时,我在 aws lambda 环境中收到此错误消息:

              botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the GetObject operation: Access Denied

              原来我需要额外的权限,因为我使用的是对象标签。如果您的对象有标签,您将需要 s3:GetObject AND s3:GetObjectTagging 用于获取对象。

              【讨论】:

                猜你喜欢
                • 2020-09-30
                • 2021-05-19
                • 2016-09-29
                • 1970-01-01
                • 2021-02-21
                • 1970-01-01
                • 2020-03-06
                • 2017-07-28
                • 2019-07-08
                相关资源
                最近更新 更多