Функция aws lambda, получившая доступ, запрещена, когда getObject из s3
Я получаю сообщение об отказе в доступе от службы S3 AWS на своей функции Lambda.
Это код:
// dependencies
var async = require('async');
var AWS = require('aws-sdk');
var gm = require('gm').subClass({ imageMagick: true }); // Enable ImageMagick integration.
exports.handler = function(event, context) {
var srcBucket = event.Records[0].s3.bucket.name;
// Object key may have spaces or unicode non-ASCII characters.
var key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));
/*
{
originalFilename: <string>,
versions: [
{
size: <number>,
crop: [x,y],
max: [x, y],
rotate: <number>
}
]
}*/
var fileInfo;
var dstBucket = "xmovo.transformedimages.develop";
try {
//TODO: Decompress and decode the returned value
fileInfo = JSON.parse(key);
//download s3File
// get reference to S3 client
var s3 = new AWS.S3();
// Download the image from S3 into a buffer.
s3.getObject({
Bucket: srcBucket,
Key: key
},
function (err, response) {
if (err) {
console.log("Error getting from s3: >>> " + err + "::: Bucket-Key >>>" + srcBucket + "-" + key + ":::Principal>>>" + event.Records[0].userIdentity.principalId, err.stack);
return;
}
// Infer the image type.
var img = gm(response.Body);
var imageType = null;
img.identify(function (err, data) {
if (err) {
console.log("Error image type: >>> " + err);
deleteFromS3(srcBucket, key);
return;
}
imageType = data.format;
//foreach of the versions requested
async.each(fileInfo.versions, function (currentVersion, callback) {
//apply transform
async.waterfall([async.apply(transform, response, currentVersion), uploadToS3, callback]);
}, function (err) {
if (err) console.log("Error on excecution of watefall: >>> " + err);
else {
//when all done then delete the original image from srcBucket
deleteFromS3(srcBucket, key);
}
});
});
});
}
catch (ex){
context.fail("exception through: " + ex);
deleteFromS3(srcBucket, key);
return;
}
function transform(response, version, callback){
var imageProcess = gm(response.Body);
if (version.rotate!=0) imageProcess = imageProcess.rotate("black",version.rotate);
if(version.size!=null) {
if (version.crop != null) {
//crop the image from the coordinates
imageProcess=imageProcess.crop(version.size[0], version.size[1], version.crop[0], version.crop[1]);
}
else {
//find the bigger and resize proportioned the other dimension
var widthIsMax = version.size[0]>version.size[1];
var maxValue = Math.max(version.size[0],version.size[1]);
imageProcess=(widthIsMax)?imageProcess.resize(maxValue):imageProcess.resize(null, maxValue);
}
}
//finally convert the image to jpg 90%
imageProcess.toBuffer("jpg",{quality:90}, function(err, buffer){
if (err) callback(err);
callback(null, version, "image/jpeg", buffer);
});
}
function deleteFromS3(bucket, filename){
s3.deleteObject({
Bucket: bucket,
Key: filename
});
}
function uploadToS3(version, contentType, data, callback) {
// Stream the transformed image to a different S3 bucket.
var dstKey = fileInfo.originalFilename + "_" + version.size + ".jpg";
s3.putObject({
Bucket: dstBucket,
Key: dstKey,
Body: data,
ContentType: contentType
}, callback);
}
};
Это ошибка в Cloudwatch:
AccessDenied: Access Denied
Это ошибка стека:
at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/services/s3.js:329:35)
at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)
at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)
at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:596:14)
at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:21:10)
at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:37:9)
at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:598:12)
at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:115:18)
Без какого-либо другого описания или информации о разрешениях S3 Bucket разрешить каждому ставить список и удалять.
Что я могу сделать, чтобы получить доступ к корзине S3?
PS: в свойствах события Lambda принципал правильный и имеет права администратора.
Ответы
Ответ 1
Ваша лямбда не имеет привилегий (S3:GetObject)
.
Перейдите на панель инструментов IAM и проверьте роль, связанную с выполнением Lambda. Если вы используете мастер AWS, он автоматически создает роль oneClick_lambda_s3_exec_role
. Нажмите на Show Policy
. На нем должно быть что-то похожее на прикрепленное изображение. Убедитесь, что S3:GetObject
указан в списке.
![enter image description here]()
Ответ 2
Я столкнулся с этой проблемой, и после нескольких часов безумства политики IAM решение было следующим:
- Перейдите на консоль S3
- Выберите интересующее вас ведро.
- Нажмите "Свойства"
- Unfold 'Permissions'
- Нажмите "Добавить дополнительные разрешения"
- Выберите "Any Authenticated AWS User" из раскрывающегося списка. Выберите "Upload/Delete" и "List" (или все, что вам нужно для вашей лямбда).
- Нажмите "Сохранить"
Готово.
Ваши тщательно написанные политики роли IAM не имеют значения, также не имеют конкретных политик ведра (я написал их тоже, чтобы они работали). Или они просто не работают на моем счете, кто знает.
[EDIT]
После многократного перебора вышеупомянутый подход не самый лучший. Попробуйте следующее:
- Сохраняйте свою политику роли как в сообщении helloV.
- Перейдите к S3. Выберите свое ведро. Нажмите "Разрешения". Выберите "Политика Bucket".
- Попробуйте что-то вроде этого:
{
"Version": "2012-10-17",
"Id": "Lambda access bucket policy",
"Statement": [
{
"Sid": "All on objects in bucket lambda",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AWSACCOUNTID:root"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::BUCKET-NAME/*"
},
{
"Sid": "All on bucket by lambda",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AWSACCOUNTID:root"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::BUCKET-NAME"
}
]
}
Работал для меня и не требует, чтобы вы делились со всеми аутентифицированными пользователями AWS (которые большую часть времени не идеальны).
Ответ 3
Интересно, что AWS возвращает 403 (доступ запрещен), когда файл не существует. Убедитесь, что целевой файл находится в корзине S3.
Ответ 4
Если вы указываете Ресурс, не забудьте также добавить спецификацию подпапки. Вот так:
"Resource": [
"arn:aws:s3:::BUCKET-NAME",
"arn:aws:s3:::BUCKET-NAME/*"
]
Ответ 5
Я тоже столкнулся с этой проблемой, я исправил это, предоставив s3:GetObject*
в ACL, когда он пытается получить версию этого объекта.
Ответ 6
Это может быть полезно некоторым людям.
Если вы все еще получаете ошибку Access Denied даже после настройки правильной роли IAM с политиками разрешений s3, убедитесь, что ваш код верен. У меня была ошибка в моем коде, и она появлялась в журналах, поскольку Access denied.
Ответ 7
Если все другие политики утки находятся в ряду, S3 по-прежнему будет возвращать сообщение "Отказано в доступе", если объект не существует И запрашивающая сторона не имеет разрешения ListObjects на ведро.
С https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGET.html:
... Если запрашиваемый вами объект не существует, ошибка, которую возвращает Amazon S3, зависит от того, есть ли у вас разрешение s3: ListBucket.
Если у вас есть разрешение s3: ListBucket для корзины, Amazon S3 вернет ошибку HTTP с кодом состояния 404 ("нет такого ключа"). Если у вас нет разрешения s3: ListBucket, Amazon S3 вернет ошибку HTTP с кодом состояния 403 ("доступ запрещен").
Ответ 8
Я боролся с этой проблемой часами. Я использовал AmazonS3EncryptionClient и ничего не помог. Затем я заметил, что клиент фактически устарел, поэтому я решил попробовать переключиться на модель строителя, которую они имеют:
var builder = AmazonS3EncryptionClientBuilder.standard()
.withEncryptionMaterials(new StaticEncryptionMaterialsProvider(encryptionMaterials))
if (accessKey.nonEmpty && secretKey.nonEmpty) builder = builder.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey.get, secretKey.get)))
builder.build()
И... это решило. Похоже, у Lambda есть проблемы с вводом учетных данных в старую модель, но хорошо работает в новой.
Ответ 9
Я попытался выполнить простую лямбда-функцию Python [пример кода], и у меня возникла та же проблема. Моя исполнительная роль была lambda_basic_execution
Я пошел к S3> (мое имя ведра здесь)> разрешения.
![S3:BucketPolicyView]()
Поскольку я новичок, я использовал Генератор политик, предоставленный Amazon, а не сам писал JSON: http://awspolicygen.s3.amazonaws.com/policygen.html мой JSON выглядит следующим образом:
{
"Id": "Policy153536723xxxx",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt153536722xxxx",
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::tokabucket/*",
"Principal": {
"AWS": [
"arn:aws:iam::82557712xxxx:role/lambda_basic_execution"
]
}
}
]
И тогда код выполняется красиво:
![foo]()
Ответ 10
Я пытался прочитать файл из s3 и создать новый файл, изменив содержимое файла чтения (Lambda + Node). Чтение файла с S3 не было проблем. Как только я попытался записать в корзину S3, я получаю сообщение об ошибке "Отказано в доступе".
Я перепробовал все перечисленные выше вещи, но не смог избавиться от "Отказано в доступе". Наконец я смог заставить его работать, дав разрешение "Список объектов" всем в моем ведре. ![S3 Bucket Access Control List]()
Очевидно, что это не лучший подход, но больше ничего не сработало.
Ответ 11
Если в вашем сегменте S3 установлено шифрование (например, AWS KMS), возможно, вам необходимо убедиться, что роль IAM, примененная к вашей функции Lambda, добавлена в список IAM> Ключи шифрования> регион> ключ> Ключевые пользователи для соответствующего ключ, который вы использовали для шифрования вашего S3 ведро в покое.
Например, на своем снимке экрана я добавил роль CyclopsApplicationLambdaRole, которую я применил к своей функции Lambda в качестве ключевого пользователя в IAM для того же ключа KMS AWS, который я использовал для шифрования своей корзины S3. Не забудьте выбрать правильный регион для вашего ключа при открытии интерфейса ключей шифрования.
Найдите роль исполнения, которую вы применили к своей лямбда-функции: ![screenshot of Lambda execution role]()
Найдите ключ, который вы использовали для добавления шифрования в корзину S3: ![screenshot of the key selected for the S3 bucket]()
В IAM> Ключи шифрования выберите свой регион и нажмите на имя ключа: ![screenshot of region dropdown in IAM]()
Добавьте роль в качестве ключевого пользователя в ключах шифрования IAM для ключа, указанного в S3: ![screenshot of IAM key users selection]()