如何使用 Amazon Lambda 对在 S3 中创建的文件设置 Open/Download 权限?

How to set Open/Download permissions on a file created in S3 with Amazon Lambda?

我有一个 Amazon Lambda 函数可以成功地将文件写入 Amazon S3 存储桶。但是,默认情况下这些文件不可公开访问。如何让它们在写入时自动访问?

有没有办法更改存储桶本身,以便所有项目都可公开阅读 (open/download)?

或者,我发现这可以通过 IAM 角色策略来完成。这是我的:

{
"Version": "2012-10-17",
"Statement": [
{
  "Effect": "Allow",
  "Action": [
    "logs:CreateLogGroup",
    "logs:CreateLogStream",
    "logs:PutLogEvents"
  ],
  "Resource": "arn:aws:logs:*:*:*"
},
{
  "Effect": "Allow",
  "Action": [
    "s3:GetObject",
    "s3:PutObject"
  ],
  "Resource": [
    "arn:aws:s3:::*"
  ]
}
]
}

我认为需要更改的是 "Resource",但我不确定如何更改。

为了完整性(以防其他人需要做类似的事情并且正在涉足 Lambda 文档的泥潭),这是我在客户端的 ajax 调用(我正在将图像写入 S3并需要返回文件名):

$.ajax({
url: 'https://mylambdafunctionurl/',
type: 'POST',
crossDomain: true,
contentType: 'application/json',
data: JSON.stringify(data),
dataType: 'json',
success: function(data) {
    var path = "https://myregion.amazonaws.com/mybucket/";
    var filename = JSON.parse(data).filename;
    document.getElementById('finalimage').innerHTML = "<a href='"+path+filename+"'>Your image</a>";
},
error: function(xhr, ajaxOptions, thrownError) {
    if (xhr.status == 200) {
        console.log(ajaxOptions);
    } else {
        console.log("Error: ");
        console.log(xhr.status);
        console.log(thrownError);
    }
}
});

这是 Lambda POST 函数 (nodejs):

var AWS = require('aws-sdk');
var s3 = new AWS.S3();

exports.handler = function(event,context) {
    var s3 = new AWS.S3();
    var nowtime = new Date();
    var bodycontent = event.image;

    mykey = nowtime.getTime() + '.png';
    var param = {Bucket: 'mybucket', Key: mykey, Body: bodycontent};
    var successdata = {filename:mykey};
    s3.upload(param, function(e,data) {
        if (e) {
            console.log(e,e.stack);
        } else {
            console.log(event);
        }
        context.done(null,JSON.stringify(successdata));
    });
}

警告:使用当前时间作为文件名尚未准备好生产。这只是一种生成相当独特的文件名的快速方法。

根据此页面示例:http://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_examples.html 您可以像这样设置 IAM 角色策略

...
 {
  "Effect": "Allow",
  "Action": [
    "s3:PutObject",
    "s3:GetObject",
    "s3:DeleteObject"
  ],
  "Resource": "arn:aws:s3:::EXAMPLE-BUCKET-NAME/*"
}
...

所以你可以将它与像 arn:aws:s3:::EXAMPLE-BUCKET-NAME/public/* 这样的文件夹结合起来,我认为

或者您可以创建一个完整的存储桶,public 可以访问所有仅用于上传的文件。

或者您可以使用 getSignedUrl 从 sdk 到刚刚上传的文件,然后 return url 到客户端,这将使文件可以通过 url 给定的时间(现在不记得它们的有效期有多长),像这样:

s3.putObject({
  Bucket: bucket,  
  Key: key,
  Body: fs.createReadStream(path),
  ContentType: contentType,
}, function(err, data) {  
  if (err)
    return callback(err, null);  

  s3.getSignedUrl('getObject', {
    Bucket: 'mybucket',    
    Key: 'mypublicfiles/myfile.txt'
  }, function(err, url) {    
    if (err)
      return callback(err, null)
    else
      return callback(null, url)
  });
});

除了@mithril_knight的回答,我还需要一个桶策略(在S3控制台中设置):

{
"Id": "Policyxxxxxxxxxx",
"Version": "2012-10-17",
"Statement": [
{
  "Sid": "Stmtxxxxxxxxxx",
  "Action": [
    "s3:GetObject"
  ],
  "Effect": "Allow",
  "Resource": "arn:aws:s3:::mybucket/*",
  "Principal": {
    "AWS": [
      "*"
    ]
  }
}
]
}

我需要的魔力是“*”的"Principal",意思是"Everyone"。