I have been trying to upload a file from my express backend application using Multer-S3 but I am getting an 'Access Denied' error. Printing out the error gives me this:
{
"success": false,
"errors": {
"title": "File Upload Error",
"detail": "Access Denied",
"error": {
"message": "Access Denied",
"code": "AccessDenied",
"region": null,
"time": "2021-06-26T16:40:47.074Z",
"requestId": "7W7EMNWNFWTPNHHG",
"extendedRequestId": "9tC2dSn8Zu6dplJxxUVIx3Zdr4mCk7ZVg0RcayXHHO86hTIZdO/9YZKsUKwn1ir0AeUg50Y/c94=",
"statusCode": 403,
"retryable": false,
"retryDelay": 76.37236671132325,
"storageErrors": []
}
}
}
My AWS set up:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::test-bucket/*"
}
]
}
where 'test-bucket' is the name of my bucket.
The user is also set with programmatic access and I have checked that the access keys are updated and active.
From what I understand, this policy will allow my IAM user to put, get and delete objects in my s3 bucket, even though it is not accessible by the public. I also should not need to carry out any further configurations like setting up CORS.
My code:
route.js
router.post('/upload', uploadController.uploadToS3);
uploadController.js
const upload = require("../util/s3");
const singleUpload = upload.single("myfile");
exports.uploadToS3 = (req, res, next) => {
singleUpload(req, res, function (err) {
if (err) {
return res.json({
success: false,
errors: {
title: "File Upload Error",
detail: err.message,
error: err
}
})
}
})
};
s3.js
const S3 = require('aws-sdk/clients/s3');
const multer = require("multer");
const multerS3 = require("multer-s3");
bucket_name = process.env.AWS_BUCKET_NAME;
bucket_region = process.env.AWS_BUCKET_REGION;
aws_access_key = process.env.AWS_ACCESS_KEY;
aws_secret_key = process.env.AWS_SECRET_KEY;
const s3 = new S3({
bucket_region,
aws_access_key,
aws_secret_key
})
const upload = multer({
storage: multerS3({
s3: s3,
bucket: bucket_name,
acl: 'private',
metadata: function (req, file, cb) {
cb(null, { fieldName: file.fieldname });
},
key: function (req, file, cb) {
cb(null, file.originalname);
}
})
});
I have tried some solutions that were suggested online, such as adding a policy for the bucket itself, or setting up CORS configuration.
I've even tried to change my IAM user's policy to S3FullAccess. Even then, I still get the access denied error.
I followed this Youtube video's tutorial for the AWS setup: https://www.youtube.com/watch?v=NZElg91l_ms&t=900s&ab_channel=SamMeech-Ward It doesn't seem as if anyone is facing the same issue...
Any help would be much appreciated, thanks!
I've managed to solve my issue. Turns out it was quite a silly mistake, nothing to do with my IAM policies at all. The issue lies in my s3.js code, when I create the s3 object:
const s3 = new S3({
bucket_region,
aws_access_key,
aws_secret_key
})
From the AWS S3 SDK documentation (https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html), the correct constructor parameters should be:
const s3 = new S3({
region,
accessKeyId,
secretAccessKey
})
With that, I was able to upload to my bucket using the AWS setup that I described.
The reason why I noticed this was because I realized that the 'Last Used' column in the 'Access Key' section for my IAM user was constantly displaying "N/A". This made me realize that my access key was not even being called in the first place.