【问题标题】:AWS S3 Bucket Policy not working when manually testing Lambda Function手动测试 Lambda 函数时 AWS S3 存储桶策略不起作用
【发布时间】:2017-12-31 14:42:32
【问题描述】:

我有一个 AWS Lambda 函数,它通过其 URL(即 https://s3-eu-west-1.amazonaws.com/bucketname/key)访问 S3 资源。

我在 S3 存储桶上添加了一个存储桶策略,允许我的 Lambda 函数访问 S3 存储桶(通过 Lambda 函数 IAM 角色)。此存储桶策略如下所示:

{
    "Version": "2012-10-17",
    "Id": "Access control to S3 bucket",
    "Statement": [
        {
            "Sid": "Allow Get and List Requests from IAM Role",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123412341234:role/role-name“
            },
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": [
                "arn:aws:s3:::bucket-name”,
                "arn:aws:s3:::bucket-name/*"
            ]
        }
    ]
}

当 Lambda 函数由触发器“自动”激活时,这一切正常。但是当我手动(通过 AWS 控制台)测试 Lambda 函数时,我收到 403 错误。

如果我随后将 S3 存储桶策略中的 Principal 更改为“*”,则 403 异常得到解决。

我的猜测是手动触发 Lambda 函数时使用了不同的 Principal,但我不知道这可能是什么。我尝试添加一个新策略,授予我的规范用户访问权限,但这不起作用。

有什么建议吗?

【问题讨论】:

  • 您为什么要通过其 URL 访问 Amazon S3 对象?像 s3-eu-west-1.amazonaws.com/bucketname/key 这样的 URL 不发送任何标识,因此它是一个匿名请求。如果对象不是公开的,它应该总是收到 403 错误。最好通过经过身份验证的 API 调用或使用 S3 预签名 URL 来访问对象。
  • 我没有意识到我需要使用 AWS S3 控制台中的“下载”或“下载为”按钮,而不是使用属性页面底部的 URL。一直在追403错误鬼。
  • @JohnRotenstein 我的用例是我使用 Nodemailer + SES 发送带有 S3 对象作为附件的电子邮件。也许 S3 预签名 URL 可能适合这里?
  • 因此,您需要授予 Lambda 函数对 S3 对象的访问权限,以便它可以将其附加到电子邮件中。是的,您可以将签名 URL 传递给特定 S3 对象的 Lambda 函数,或者您可以授予 Lambda 函数对 S3 的访问权限,以便始终能够访问该对象。除非您对安全性特别敏感,否则第二个更合乎逻辑。您能否显示生成 403 错误的代码——它是对 S3 进行 API 调用,还是尝试通过公共 URL 检索对象?
  • @MattD -- 这完全取决于如何获取对象。如果访问是通过使用 AWS JavaScript 开发工具包的 API 调用,则将使用角色的凭证。但是,如果对象是通过一个没有传递凭据的 URL 获取的,那么访问将被拒绝。

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


【解决方案1】:

我遇到了类似的问题,问题是我的策略没有考虑到 Lambda 在执行时承担角色的事实。我将假定的角色添加到 Principal 部分,一切都开始工作了:

        "Principal": {
            "AWS": [
                "arn:aws:sts::123412341234:assumed-role/role-name/function-name"
            ]
        },

【讨论】:

    【解决方案2】:

    如果您希望向特定 IAM 用户/组/角色授予权限,那么您应该直接在该用户/组/角色上添加权限,而不是将其作为特殊情况添加到存储桶策略。

    这可以让您的存储桶策略保持整洁,减少特殊情况。

    我会推荐:

    • 移除已显示的存储桶策略
    • 向您的 Lambda 函数使用的 IAM 角色添加内联策略(针对一次性情况)

    这是一个示例策略:

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "BucketAccess",
                "Effect": "Allow",
                "Action": [
                    "s3:*"
                ],
                "Resource": [
                    "arn:aws:s3:::my-bucket",
                    "arn:aws:s3:::my-bucket/*"
                ]
            }
        ]
    }
    

    实际上,这过于宽松,因为它会允许 Lambda 函数对存储桶执行任何操作(例如删除存储桶),因此您应该只授予您知道 Lambda 函数所需的权限。

    【讨论】:

    • 感谢您的建议。这确实是一种更好的表达方式。但是,在实施此解决方案后,我仍然遇到相同的基本问题。手动运行 Lambda 函数时,我得到 403,而当 AWS 基础设施触发 Lambda 函数时一切正常。
    【解决方案3】:

    按照@JohnRotenstein 的建议,我删除了存储桶策略,而是实施了一个预签名的 URL。现在一切正常。

    Node.js 中预签名 URL 生成示例(URL 有效期为 360 秒):

    s3.getSignedUrl('getObject', {Bucket: bucket, Key: filename, Expires: 360})
    

    在 Java 中(有效期为 1 小时):

    private URL createSignedURL(String s3Bucket, String s3Key){
    
        AmazonS3 s3client = AmazonS3ClientBuilder.defaultClient();
    
        // Set expiration to 1 hour
        java.util.Date expiration = new java.util.Date();
        long msec = expiration.getTime();
        msec += 1000 * 60 * 60; 
        expiration.setTime(msec);
    
        // Generate signed key
        GeneratePresignedUrlRequest generatePresignedUrlRequest = 
                      new GeneratePresignedUrlRequest(s3Bucket, s3Key);
    
        generatePresignedUrlRequest.setMethod(HttpMethod.GET); 
        generatePresignedUrlRequest.setExpiration(expiration);
    
        // Return key
        return s3client.generatePresignedUrl(generatePresignedUrlRequest); 
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-24
      • 2012-11-23
      • 2017-10-14
      • 2017-05-28
      • 2020-04-10
      相关资源
      最近更新 更多