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>
私はラムダに割り当てられたロールでそれを実行しました。ラムダに必要なすべてのポリシーがあると思います。私は何かが欠けている可能性があります。ルートアクセスキーを使用してこのスクリプトを実行しています。
S3がイベントを追加する前にバケットを作成する時間が必要なタイミングエラーかもしれないと思っていましたが、しばらく待ってバケット名をハードコーディングし、同じエラーをスローするスクリプトを再度実行しました。
奇妙なことに、S3 UIでイベントフックを作成してすぐに削除すると、そのバケット名をハードコーディングするとスクリプトが機能します。 UIでイベントを作成すると、必要なアクセス許可がいくつか追加されるようですが、SDKまたはコンソールUIに何が含まれるかはわかりません。
何か考えやことを試してみてください?ご協力いただきありがとうございます
S3バケットにラムダ関数を呼び出すための権限がないため、このメッセージが表示されます。
AWSドキュメント !必要な許可には2つのタイプがあります。
「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>"
}
}
}
]
}
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をコピーし、Sid
sを取り出し、ループ内で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);
}
});
}
_
コンソールは、s3がラムダを呼び出すことを許可する別の方法です。
注意
Lambdaコンソールを使用して関数にトリガーを追加すると、コンソールは関数のリソースベースのポリシーを更新して、サービスがそれを呼び出せるようにします。 Lambdaコンソールで使用できない他のアカウントまたはサービスにアクセス許可を付与するには、AWS CLIを使用します。
したがって、AWSコンソールからラムダにs3トリガーを追加して設定するだけです
https://docs.aws.Amazon.com/lambda/latest/dg/access-control-resource-based.html
私にとっては、Lambdaはバケット全体に対する許可を期待していましたnotバケットとキー
それでも誰かにとって有用な場合、これは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);