web-dev-qa-db-ja.com

S3バケットLambdaイベント:次の宛先構成を検証できません

S3バケットを作成し、すぐにラムダ通知イベントを割り当てようとしています。

これが、私が書いたノードテストスクリプトです。

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を呼び出すとスローされます。

{ 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>

私はラムダに割り当てられたロールでそれを実行しました。ラムダに必要なすべてのポリシーがあると思います。私は何かが欠けている可能性があります。ルートアクセスキーを使用してこのスクリプトを実行しています。

Role

S3がイベントを追加する前にバケットを作成する時間が必要なタイミングエラーかもしれないと思っていましたが、しばらく待ってバケット名をハードコーディングし、同じエラーをスローするスクリプトを再度実行しました。

奇妙なことに、S3 UIでイベントフックを作成してすぐに削除すると、そのバケット名をハードコーディングするとスクリプトが機能します。 UIでイベントを作成すると、必要なアクセス許可がいくつか追加されるようですが、SDKまたはコンソールUIに何が含まれるかはわかりません。

S3 Event Config

何か考えやことを試してみてください?ご協力いただきありがとうございます

13
Scotty Waggoner

S3バケットにラムダ関数を呼び出すための権限がないため、このメッセージが表示されます。

AWSドキュメント !必要な許可には2つのタイプがあります。

  1. サービスを呼び出すLambda関数のアクセス許可
  2. Lambda関数を呼び出すAmazon S3のアクセス許可

「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>"
        }
      }
    }
  ]
}
21

1年後にようやくこれをもう一度見ました。これは昨年改訂したハッカソンプロジェクトでした。 @ davor.obilinovicの答えは、追加する必要があるLambdaの許可を示すのに非常に役立ちました。それでも私はそれがどのように見えるのに必要なのかを正確に理解するために少しかかりました。

AWS JavaScript SDKとLambda APIのドキュメントはこちら https://docs.aws.Amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#addPermission-propertyhttps:// 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).がスローされ始めました。各バケットに新しい個別のパーミッションを追加すると、明らかにそのポリシーには最大サイズがあります。

ポリシーはAWSマネジメントコンソールで編集できないように見えるため、SDKを使用して各エントリを削除するのが楽しかったです。ポリシーJSONをコピーし、Sidsを取り出し、ループ内で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);
    }
  });
}
_
4
Scotty Waggoner

コンソールは、s3がラムダを呼び出すことを許可する別の方法です。

注意

Lambdaコンソールを使用して関数にトリガーを追加すると、コンソールは関数のリソースベースのポリシーを更新して、サービスがそれを呼び出せるようにします。 Lambdaコンソールで使用できない他のアカウントまたはサービスにアクセス許可を付与するには、AWS CLIを使用します。

したがって、AWSコンソールからラムダにs3トリガーを追加して設定するだけです

https://docs.aws.Amazon.com/lambda/latest/dg/access-control-resource-based.html

0
Spiff

私にとっては、Lambdaはバケット全体に対する許可を期待していましたnotバケットとキー

0
supa_command

それでも誰かにとって有用な場合、これはJavaを使用してラムダ関数に許可を追加する方法です:

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-

0
James130490