Je reçois une erreur d'accès refusé du service S3 AWS sur ma fonction Lambda.
C'est le code:
// 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);
}
};
C'est l'erreur sur Cloudwatch:
AccessDenied: Access Denied
C'est l'erreur de pile:
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)
Sans aucune autre description ni information Sur S3, les autorisations de compartiment permettent à tout le monde de mettre en liste et de supprimer.
Que puis-je faire pour accéder au compartiment S3?
PS: sur les propriétés d’événement Lambda, le principal est correct et dispose de privilèges d’administration.
Votre Lambda n'a pas de privilèges (S3:GetObject)
.
Accédez au tableau de bord IAM, vérifiez le rôle associé à votre exécution Lambda. Si vous utilisez l'assistant AWS, il crée automatiquement un rôle appelé oneClick_lambda_s3_exec_role
. Cliquez sur Show Policy
. Il devrait montrer quelque chose de similaire à l'image ci-jointe. Assurez-vous que S3:GetObject
est répertorié.
J'ai rencontré ce problème et après des heures de folie politique IAM, la solution consistait à:
Fait ... Les stratégies de rôle IAM soigneusement rédigées importent peu, pas plus que les stratégies de compartiment spécifiques (je les ai écrites aussi pour que cela fonctionne). Ou ils ne travaillent tout simplement pas sur mon compte, qui sait.
[MODIFIER]
Après beaucoup de bricolage, l'approche ci-dessus n'est pas la meilleure. Essaye ça:
{ "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" } ] }
Travaillé pour moi et n'exige pas que vous partagiez avec tous les utilisateurs AWS authentifiés (ce qui n'est généralement pas idéal).
Fait intéressant, AWS renvoie 403 (accès refusé) lorsque le fichier n'existe pas. Assurez-vous que le fichier cible se trouve dans le compartiment S3.
Si vous spécifiez Ressource , n'oubliez pas d'ajouter également la spécification de sous-dossier. Comme ça:
"Resource": [
"arn:aws:s3:::BUCKET-NAME",
"arn:aws:s3:::BUCKET-NAME/*"
]
J'ai moi aussi rencontré ce problème. J'ai résolu le problème en fournissant s3:GetObject*
dans la liste de contrôle d'accès car il tente d'obtenir une version de cet objet.
J'ai essayé d'exécuter un schéma de base de la fonction lambda Python [exemple de code] et j'ai eu le même problème. Mon rôle d'exécution était lambda_basic_execution
Je suis allé à S3> (mon nom de seau ici)> autorisations.
Comme je suis débutant, j’ai utilisé le Policy Generator fourni par Amazon plutôt que d’écrire moi-même JSON: http://awspolicygen.s3.amazonaws.com/policygen.html ce:
{
"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"
]
}
}
]
Et puis le code s’exécute bien:
Si tous les autres canards de stratégie sont alignés, S3 renverra toujours un message Accès refusé si l'objet n'existe pas ET si le demandeur n'a pas le droit ListObjects sur le compartiment.
De https://docs.aws.Amazon.com/AmazonS3/latest/API/RESTObjectGET.html :
... Si l'objet que vous demandez n'existe pas, l'erreur Amazon S3 les retours dépendent de si vous avez également l'autorisation s3: ListBucket.
Si vous disposez de l'autorisation s3: ListBucket sur le compartiment, Amazon S3 utilisera renvoie une erreur du code d'état HTTP 404 ("pas de clé de ce type"). si vous ne le faites pas Avec l'autorisation s3: ListBucket, Amazon S3 renverra un HTTP code d'état 403 ("accès refusé") erreur.
Si le chiffrement est défini sur votre compartiment S3 (comme AWS KMS), vous devrez peut-être vous assurer que le rôle IAM appliqué à votre fonction Lambda est ajouté à la liste IAM> Clés de chiffrement> region> clé> Utilisateurs de clé pour la clé correspondante que vous avez utilisée pour chiffrer votre compartiment S3 au repos.
Dans ma capture d'écran, par exemple, j'ai ajouté le rôle CyclopsApplicationLambdaRole que j'ai appliqué à ma fonction Lambda en tant qu'utilisateur Key dans IAM pour la même clé AWS KMS que celle que j'avais utilisée pour chiffrer mon compartiment S3. N'oubliez pas de sélectionner la région correcte pour votre clé lorsque vous ouvrez l'interface utilisateur Encryption keys.
Recherchez le rôle d'exécution que vous avez appliqué à votre fonction Lambda:
Recherchez la clé que vous avez utilisée pour ajouter le cryptage à votre compartiment S3:
Dans IAM> Clés de cryptage, choisissez votre région et cliquez sur le nom de la clé:
Ajoutez le rôle en tant qu'utilisateur clé dans Clés de cryptage IAM pour la clé spécifiée dans S3:
Je me débattais avec ce problème pendant des heures. J'utilisais AmazonS3EncryptionClient et rien de ce que j'ai fait ne m'a aidé. Ensuite, j'ai remarqué que le client est en réalité obsolète, alors j'ai décidé d'essayer de passer au modèle de constructeur proposé:
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()
Et… ça l'a résolu. On dirait que Lambda a du mal à injecter les informations d'identification dans l'ancien modèle, mais fonctionne bien dans le nouveau.
J'essayais de lire un fichier à partir de s3 et de créer un nouveau fichier en modifiant le contenu du fichier lu (Lambda + Node). La lecture du fichier depuis S3 n’a rencontré aucun problème. Dès que j'ai essayé d'écrire dans le compartiment S3, l'erreur «Accès refusé» s'affiche.
J'ai essayé toutes les choses énumérées ci-dessus mais je ne pouvais pas me débarrasser de 'Accès refusé'. Finalement, j'ai pu le faire fonctionner en donnant la permission 'List Object' à tout le monde sur mon seau .
De toute évidence, ce n’est pas la meilleure approche mais rien d’autre n’a fonctionné.