我试图创建一个S3存储桶并立即为其分配一个lambda通知事件。
这是我写的节点测试脚本:
first <= last
创建工作正常,但从const aws = require('aws-sdk');
const uuidv4 = require('uuid/v4');
aws.config.update({
accessKeyId: 'key',
secretAccessKey:'secret',
region: 'us-west-1'
});
const s3 = new aws.S3();
const params = {
Bucket: `bucket-${uuidv4()}`,
ACL: "private",
CreateBucketConfiguration: {
LocationConstraint: 'us-west-1'
}
};
s3.createBucket(params, function (err, data) {
if (err) {
throw err;
} else {
const bucketUrl = data.Location;
const bucketNameRegex = /bucket-[a-z0-9\-]+/;
const bucketName = bucketNameRegex.exec(bucketUrl)[0];
const params = {
Bucket: bucketName,
NotificationConfiguration: {
LambdaFunctionConfigurations: [
{
Id: `lambda-upload-notification-${bucketName}`,
LambdaFunctionArn: 'arn:aws:lambda:us-west-1:xxxxxxxxxx:function:respondS3Upload',
Events: ['s3:ObjectCreated:CompleteMultipartUpload']
},
]
}
};
// Throws "Unable to validate the following destination configurations" until an event is manually added and deleted from the bucket in the AWS UI Console
s3.putBucketNotificationConfiguration(params, function(err, data) {
if (err) {
console.error(err);
console.error(this.httpResponse.body.toString());
} else {
console.log(data);
}
});
}
});
投掷s3.putBucketNotificationConfiguration
调用:
aws-sdk
我使用分配给lambda的角色运行它,我认为它是所需的所有策略。我可能会遗漏一些东西。我使用root访问密钥来运行此脚本。
我认为这可能是一个时间错误,S3在添加事件之前需要时间来创建存储桶,但是我已经等了一段时间,硬编码了存储桶名称,并再次运行我的脚本同样的错误。
奇怪的是,如果我在S3 UI中创建事件挂钩并立即将其删除,那么如果我将该桶名称硬编码到其中,我的脚本就会起作用。似乎在UI中创建事件会添加一些所需的权限,但我不确定在SDK或控制台UI中会出现什么。
任何想法或事情要尝试?谢谢你的帮助
答案 0 :(得分:16)
您收到此消息是因为您的s3存储桶缺少调用lambda函数的权限。
根据AWS documentation!需要两种类型的权限:
您应该创建一个&#39; AWS :: Lambda :: Permission&#39;它看起来应该类似于:
{
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Sid": "<optional>",
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": "lambda:InvokeFunction",
"Resource": "<ArnToYourFunction>",
"Condition": {
"StringEquals": {
"AWS:SourceAccount": "<YourAccountId>"
},
"ArnLike": {
"AWS:SourceArn": "arn:aws:s3:::<YourBucketName>"
}
}
}
]
}
答案 1 :(得分:2)
一年后终于再次看了看。这是我们去年取消的黑客马拉松项目。 @ davor.obilinovic的回答非常有帮助,使我指向需要添加的Lambda权限。还是花了我一点时间才能弄清楚我需要它的外观。
以下是AWS JavaScript SDK和Lambda API文档 https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#addPermission-property https://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
JS SDK文档包含以下内容:
SourceArn: "arn:aws:s3:::examplebucket/*",
我无法使它工作最长时间,并且仍然出现Unable to validate the following destination configurations
错误。
更改为
SourceArn: "arn:aws:s3:::examplebucket",
解决了该问题。 /*
显然是错误的,我应该仔细看看我在这里得到的答案,但是正在尝试关注AWS文档。
在开发了一段时间并创建了很多存储桶,Lambda权限和S3 Lambda通知之后,调用addPermission开始抛出The final policy size (...) is bigger than the limit (20480).
。为每个存储桶添加新的,单独的权限会将它们添加到Lambda功能策略的底部而且显然该策略具有最大大小。
该策略在AWS管理控制台中似乎不可编辑,因此我很高兴使用SDK删除了每个条目。我复制了策略JSON,将Sid
抽出并在循环中调用了removePermission
(这抛出了速率限制错误,我不得不运行多次)。
最后,我发现省略SourceArn
键将向Lambda授予所有S3存储桶的权限。
这是我使用SDK添加所需权限的最终代码。我只为功能运行一次。
const aws = require('aws-sdk');
aws.config.update({
accessKeyId: process.env.AWS_ACCESS,
secretAccessKey: process.env.AWS_SECRET,
region: process.env.AWS_REGION,
});
// Creates Lambda Function Policy which must be created once for each Lambda function
// Must be done before calling s3.putBucketNotificationConfiguration(...)
function createLambdaPermission() {
const lambda = new aws.Lambda();
const params = {
Action: 'lambda:InvokeFunction',
FunctionName: process.env.AWS_LAMBDA_ARN,
Principal: 's3.amazonaws.com',
SourceAccount: process.env.AWS_ACCOUNT_ID,
StatementId: `example-S3-permission`,
};
lambda.addPermission(params, function (err, data) {
if (err) {
console.log(err);
} else {
console.log(data);
}
});
}
答案 2 :(得分:0)
控制台是允许s3调用lambda的另一种方式:
注意
当您使用Lambda控制台向函数添加触发器时, 控制台会更新功能的基于资源的策略,以允许 服务来调用它。授予其他帐户权限或 Lambda控制台中不可用的服务,请使用AWS CLI。
因此,您只需要从aws控制台向lambda添加并配置s3触发器
https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html
答案 3 :(得分:0)
对于我来说,Lambda希望整个存储桶都得到许可,而不存储桶和键则是
答案 4 :(得分:0)
如果它仍然对某人有用,这就是我使用java向lambda函数添加权限的方式:
AWSLambda client = AWSLambdaClientBuilder.standard().withRegion(clientRegion).build();
AddPermissionRequest requestLambda = new AddPermissionRequest()
.withFunctionName("XXXXX")
.withStatementId("XXXXX")
.withAction("lambda:InvokeFunction")
.withPrincipal("s3.amazonaws.com")
.withSourceArn("arn:aws:s3:::XXXXX" )
.withSourceAccount("XXXXXX");
client.addPermission(requestLambda);