S3 Bucket Lambda Event: невозможно проверить следующие конфигурации назначения
Я пытаюсь создать корзину 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 и немедленно удаляю ее, мой сценарий работает, если я жестко закодирую это имя сегмента. Кажется, что создание события в пользовательском интерфейсе добавляет некоторые необходимые разрешения, но я не уверен, что это будет в SDK или в пользовательском интерфейсе консоли.
![S3 Event Config]()
Любые мысли или вещи, чтобы попробовать? Спасибо за вашу помощь
Ответы
Ответ 1
Вы получаете это сообщение, потому что в вашем ведомости s3 отсутствуют разрешения для вызова вашей лямбда-функции.
Согласно документации AWS ! требуется два типа разрешений:
- Разрешения для вашей функции 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>"
}
}
}
]
}
Ответ 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
ошибку 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
и вызвал removePermission
в цикле (который removePermission
ошибки ограничения скорости, и мне приходилось запускать его много раз).
Наконец, я обнаружил, что SourceArn
ключа 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);
}
});
}
Ответ 3
Консоль - это еще один способ разрешить s3 вызывать лямбду:
Заметка
Когда вы добавляете триггер к своей функции с помощью консоли Lambda, консоль обновляет политику функции на основе ресурсов, чтобы позволить службе вызывать ее. Чтобы предоставить разрешения другим учетным записям или службам, которые недоступны в консоли Lambda, используйте интерфейс командной строки AWS.
Так что вам просто нужно добавить и настроить триггер s3 для вашей лямбды из консоли aws
https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html
Ответ 4
Для меня это была лямбда, ожидающая разрешения на все ведро, а не ведро и ключи
Ответ 5
Если это все еще полезно для кого-то, вот как я добавляю разрешение к лямбда-функции, используя 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-