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,将Sids 拉出并在循环中调用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 触发器

AWS Lambda使用S3

使用 cloudformation 为 S3 存储桶启用 Lambda 函数

我如何通过AWS SNS设置有关上传事件的AWS S3?