Skip to content
Advertisement

S3 Object upload to a private bucket using a pre-signed URL result in Access denied

I’m learning AWS and with my limited knowledge of AWS, am I right in saying that If I make pre-signed URLS to Upload and Download from a bucket – which is set to block all public access it should work? I take all my authentication and checks through API gateway, so if a user is able to hit the endpoint that returns a pre-signed URL to upload/download, then they are allowed to do so.

If I’m correct then I am confused to why I’m getting an Access denied error when I try to upload an image to my bucket (which blocks public access) via a pre-signed URL – it works perfectly when the bucket is set to public?

My Lambda function that creates a pre-signed URL:

const AWS = require('aws-sdk');
AWS.config.update({region: process.env.AWS_REGION});
const s3 = new AWS.S3()

// Main entry point
exports.handler = async (event) => {
    const result = await getUploadURL()
   // console.log('Result: ' result)
    return result;
}

const getUploadURL = async function(){
    const randomID = parseInt(Math.random()*10000000000)

    const s3Params = {
        Bucket: process.env.UploadBucket,
        Key: `${randomID}.jpg`,
        ContentType: 'image/jpeg',
        ACL: 'public-read'
    }

    console.log('getUploadURL: ', s3Params)
    return new Promise((resolve, reject) => {
        // Get signed URL
        resolve({
            "statusCode": 200,
            "isBase64Encoded": false
            "body": JSON.stringify({
                "uploadURL": s3.getSignedUrl('putObject', s3Params),
                "photoFilename": `${randomID}.jpg`
            })
        })
    });
}

My python code that get’s pre-signed URL and uses it to upload objects:

def upload_file_new(fileDir):
    presignedURL = requests.get('<URL>').json()['uploadURL']
    data = open(fileDir, 'rb').read()
    result = requests.put(presignedURL, data=data, headers={'Content-type': 'image/jpeg'})

My policy for my lambda function:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "arn:aws:s3:::contentsync/*"
        }
    ]
}

Advertisement

Answer

It’s likely that your bucket has Block all public access turned on. Therefore, you cannot set the ACL of the object to public-read. The solution is that you can either turn off the Block all public access or change public-read to private.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement