手动测试Lambda函数时,AWS S3 Bucket Policy无法正常工作

时间:2017-07-25 15:10:35

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

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

我在S3 Bucket上添加了一个Bucket Policy,允许我的Lambda Function访问S3 Bucket(通过Lambda Functions IAM Role)。此Bucket Policy如下所示:

{
    "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函数被触发器“自动”激活时,一切正常。但是当我手动测试Lambda函数时(通过AWS控制台),我收到403错误。

如果我然后将S3 Bucket Policy中的Principal更改为“*”,则会解决403异常。

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

有什么建议吗?

3 个答案:

答案 0 :(得分:0)

如果您希望授予特定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函数需要的权限。

答案 1 :(得分:0)

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

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

答案 2 :(得分:-1)

正如@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); 
}