web-dev-qa-db-fra.com

aws fonction lambda obtenir un accès refusé lorsque getObject de s3

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.

30
cyberdantes

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é.

 enter image description here

29
helloV

J'ai rencontré ce problème et après des heures de folie politique IAM, la solution consistait à:

  1. Aller à la console S3
  2. Cliquez sur le seau qui vous intéresse.
  3. Cliquez sur 'Propriétés'
  4. Déplier 'Autorisations'
  5. Cliquez sur 'Ajouter plus de permissions'
  6. Choisissez "Tout utilisateur AWS authentifié" dans la liste déroulante. Sélectionnez 'Upload/Delete' et 'List' (ou tout ce dont vous avez besoin pour votre lambda).
  7. Cliquez sur "Enregistrer"

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:

  1. Conservez la politique de votre rôle comme dans le message helloV.
  2. Allez à S3. Sélectionnez votre seau. Cliquez sur les autorisations. Cliquez sur Stratégie de compartiment.
  3. Essayez quelque chose comme ç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).

17
Adam Owczarczyk

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.

14
vedat

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/*"
]
10
TheVTM

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.

2
Steven Lu

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.

 S3:BucketPolicyView

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:

 foo

1
O95

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.

1
Jeremiah

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:  screenshot of Lambda execution role

Recherchez la clé que vous avez utilisée pour ajouter le cryptage à votre compartiment S3:  screenshot of the key selected for the S3 bucket

Dans IAM> Clés de cryptage, choisissez votre région et cliquez sur le nom de la clé:  screenshot of region dropdown in IAM

Ajoutez le rôle en tant qu'utilisateur clé dans Clés de cryptage IAM pour la clé spécifiée dans S3:  screenshot of IAM key users selection

0
Danny Bullis

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.

0
yi1

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 .  S3 Bucket Access Control List

De toute évidence, ce n’est pas la meilleure approche mais rien d’autre n’a fonctionné.

0
imTheManager