AWS S3 NodeJS Forbidden or Connection Rest

642 views Asked by At

I have a NodeJS application on my local machine. I am trying to set it up with Amazon S3 services, but unfortunately, it doesn't work. I am able to get signed URL, but when uploading a file AWS returns Forbidden 403 (several times it dropped connection, but stopped after I removed timeout option from CORS)

What I have done so far:

  1. Created new user with fallowing policy:

    {
    "Statement": [
       {
        "Action": "s3:*",
        "Effect": "Allow",
        "Resource": [
            "arn:aws:s3:::my-bucket",
            "arn:aws:s3:::my-bucket/*"
        ]
      }
     ]
    }
    
  2. Created new access key for this user

  3. Updated CORS for bucket to

    <?xml version="1.0" encoding="UTF-8"?>
    <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
        <CORSRule>
            <AllowedOrigin>*</AllowedOrigin>
            <AllowedMethod>GET</AllowedMethod>
            <AllowedMethod>PUT</AllowedMethod>
            <AllowedMethod>POST</AllowedMethod>
            <AllowedHeader>*</AllowedHeader>
        </CORSRule>
    </CORSConfiguration>
    
  4. Updated bucket policy

     {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "111",
                "Effect": "Allow",
                "Principal": {
                        "AWS": "my-user-id-number"
                },
                "Action": "s3:PutObject",
                "Resource": "arn:aws:s3:::my-bucket/*"
            }
        ]
    }
    
  5. Created call to sign url in NodeJS (with Express)

    aws.config.accessKeyId = process.env.AWS_ACCESS_KEY_ID;
    aws.config.secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
    
    router.get('/sign-s3', function (req, res) {
    
            var s3 = new aws.S3();
            var fileName = req.query.fileName;
            var fileType = req.query.fileType;
    
            var s3Params = {
                Key: fileName,
                Bucket: process.env.S3_BUCKET_NAME,
                Expires: 600,
                ContentType: fileType,
                ACL: 'public-read'
            };
            s3.getSignedUrl('putObject', s3Params, function (err, data) {
                if (err) {
                    console.log(err);
                    return res.end();
                }
                var returnData = {
                    signedRequest: data,
                    url: 'https://${S3_BUCKET_NAME}.s3.amazonaws.com/${fileName}'
                };
                res.write(JSON.stringify(returnData));
                res.end();
            });
        });
    
  6. Upload file

    $http({
        method: 'GET',
        url: '/aws/sign-s3',
        params: data
    }).then(function (response) {
        var fd = new FormData();
        fd.append("file", file);
        $http({
            method: 'PUT',
            url: response.data.signedRequest,
            data: fd
        }).then(function (response) {
            defer.resolve(response);
        }, function (err) {
            defer.reject(err);
        });
    }, function (err) {
        defer.reject(err);
    });
    

There is one more thing I don't understand: i created a user and gave it access to s3, but I can't assign user to bucket in bucket permission. Is it missing something in access policy?

Thanks in advance for any hints!

1

There are 1 answers

0
Kamila On

I have figured out.

First of all, I generated new access keys to make sure these are correct. Second, I updated my upload request, to set content-type and to serialise only file, instead of FormData with file.

So the upload request looks

$http({
   method: 'PUT',
   url: response.data.signedRequest,
   data: file,
   headers: {'Content-type': file.type}
}).then(function (response) {
    defer.resolve(response);
  }, function (err) {
    defer.reject(err);
});