如何使用 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"。
我有一个 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"。