S3 存储桶 Lambda 事件:无法验证以下目标配置
Posted
技术标签:
【中文标题】S3 存储桶 Lambda 事件:无法验证以下目标配置【英文标题】:S3 Bucket Lambda Event: Unable to validate the following destination configurations 【发布时间】:2018-04-23 06:08:02 【问题描述】:我正在尝试创建一个 S3 存储桶并立即为其分配一个 lambda 通知事件。
这是我写的节点测试脚本:
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);
);
);
创建工作正常,但从 aws-sdk
调用 s3.putBucketNotificationConfiguration
会抛出:
InvalidArgument: Unable to validate the following destination configurations
at Request.extractError ([...]/node_modules/aws-sdk/lib/services/s3.js:577:35)
at Request.callListeners ([...]/node_modules/aws-sdk/lib/sequential_executor.js:105:20)
at Request.emit ([...]/node_modules/aws-sdk/lib/sequential_executor.js:77:10)
at Request.emit ([...]/node_modules/aws-sdk/lib/request.js:683:14)
at Request.transition ([...]/node_modules/aws-sdk/lib/request.js:22:10)
at AcceptorStateMachine.runTo ([...]/node_modules/aws-sdk/lib/state_machine.js:14:12)
at [...]/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> ([...]/node_modules/aws-sdk/lib/request.js:38:9)
at Request.<anonymous> ([...]/node_modules/aws-sdk/lib/request.js:685:12)
at Request.callListeners ([...]/node_modules/aws-sdk/lib/sequential_executor.js:115:18)
message: 'Unable to validate the following destination configurations',
code: 'InvalidArgument',
region: null,
time: 2017-11-10T02:55:43.004Z,
requestId: '9E1CB35811ED5828',
extendedRequestId: 'tWcmPfrAu3As74M/0sJL5uv+pLmaD4oBJXwjzlcoOBsTBh99iRAtzAloSY/LzinSQYmj46cwyfQ=',
cfId: undefined,
statusCode: 400,
retryable: false,
retryDelay: 4.3270874729153475
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InvalidArgument</Code>
<Message>Unable to validate the following destination configurations</Message>
<ArgumentName1>arn:aws:lambda:us-west-1:xxxxxxxxxx:function:respondS3Upload, null</ArgumentName1>
<ArgumentValue1>Not authorized to invoke function [arn:aws:lambda:us-west-1:xxxxxxxxxx:function:respondS3Upload]</ArgumentValue1>
<RequestId>9E1CB35811ED5828</RequestId>
<HostId>tWcmPfrAu3As74M/0sJL5uv+pLmaD4oBJXwjzlcoOBsTBh99iRAtzAloSY/LzinSQYmj46cwyfQ=</HostId>
</Error>
我使用分配给 lambda 的角色运行它,我认为这是它需要的所有策略。我可能会遗漏一些东西。我正在使用我的根访问密钥来运行此脚本。
我认为这可能是时间错误,S3 在添加事件之前需要时间来创建存储桶,但我等了一段时间,硬编码存储桶名称,然后再次运行我的脚本,这会引发相同的错误。
奇怪的是,如果我在 S3 UI 中创建事件挂钩并立即删除它,如果我将存储桶名称硬编码到其中,我的脚本就可以工作。似乎在 UI 中创建事件会添加一些所需的权限,但我不确定 SDK 或控制台 UI 中会是什么。
有什么想法或尝试吗?感谢您的帮助
【问题讨论】:
【参考方案1】:您收到此消息是因为您的 s3 存储桶缺少调用 lambda 函数的权限。
根据AWS documentation!需要两种类型的权限:
-
您的 Lambda 函数调用服务的权限
Amazon S3 调用您的 Lambda 函数的权限
您应该创建一个类型为“AWS::Lambda::Permission”的对象,它应该类似于:
"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>"
]
【讨论】:
我应该将上述政策文件添加到哪里? 根据 S3 文档,对象AWS::Lambda::Permission
具有 SourceArn
等属性。我在那里没有看到政策文件道具。另见docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/…
他更有可能从aws.amazon.com/premiumsupport/knowledge-center/…中描述的隐式循环依赖中得到这个错误
我们也面临同样的问题。我们需要在哪里添加此政策?
对于仍然想知道在哪里添加的任何人:使用 AWS CLI 来执行此操作。示例在这里:docs.aws.amazon.com/lambda/latest/dg/…【参考方案2】:
一年后终于又看了一遍。这是我们重新审视的去年的黑客马拉松项目。 @davor.obilinovic 的回答非常有助于向我指出我需要添加的 Lambda 权限。我仍然花了一点时间来弄清楚我需要它的样子。
这里是 AWS javascript 开发工具包和 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
s 拉出并在循环中调用removePermission
(这引发了速率限制错误,我不得不多次运行它)。
最后我发现省略 SourceArn
键会给所有 S3 存储桶授予 Lambda 权限。
这是我使用 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);
);
【讨论】:
天啊!!!它对我有用!文档示例完全错误,浪费了我的半天时间! boto3.amazonaws.com/v1/documentation/api/latest/reference/… 非常感谢!我确定它使用 '/*' 工作了一段时间,但更新后我得到了错误。改了之后又能用了!【参考方案3】:如果它仍然对某人有用,这就是我使用 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);
请检查 https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/lambda/AWSLambda.html#addPermission-com.amazonaws.services.lambda.model.AddPermissionRequest-
【讨论】:
【参考方案4】:控制台是允许 s3 调用 lambda 的另一种方式:
注意
当您使用 Lambda 控制台向函数添加触发器时, 控制台更新函数的基于资源的策略以允许 服务来调用它。授予其他帐户权限或 Lambda 控制台中不可用的服务,请使用 AWS CLI。
所以您只需要从 aws 控制台向您的 lambda 添加和配置一个 s3 触发器
https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html
【讨论】:
是的。最初我以为我必须为每个存储桶添加一个新的权限条目。我的存储桶是动态创建的。省略SourceArn
并只为所有存储桶添加一个权限是解决方案,因此通过 Web 控制台创建一个权限也应该同样有效。【参考方案5】:
对我来说,是 Lambda 期望获得整个存储桶的权限,而不是存储桶和密钥
【讨论】:
【参考方案6】:看看这里可能会有所帮助:AWS Lambda : creating the trigger
当您在存储桶中有冲突的事件时,会出现一种不清楚的错误。您需要清除其他事件以创建新事件。
【讨论】:
以上是关于S3 存储桶 Lambda 事件:无法验证以下目标配置的主要内容,如果未能解决你的问题,请参考以下文章
如果通过验证,AWS lambda 读取 zip 文件执行验证并解压缩到 s3 存储桶
无法在 cloudformation 中创建带有事件的 s3 存储桶,以连接到它
无服务器框架:使用来自资源的存储桶的 S3 Lambda 触发器