2
votes

I'm using a lambda function to create a presigned url to upload to S3:

var crypto = require('crypto');
var AWS = require('aws-sdk');

AWS.config.region = 'eu-west-1';

function randomValueHex (len) {
    return crypto.randomBytes(Math.ceil(len/2))
        .toString('hex') // convert to hexadecimal format
        .slice(0,len);   // return required number of characters
}

var value1 = randomValueHex(12)

exports.handler = function(event, context) {
    var key = randomValueHex(16);
    // Url is
    var s3 = new AWS.S3();
    var params = {Bucket: 'somebucket', Key: key };
    var url = s3.getSignedUrl('putObject', params);
    context.succeed({ key: key, url: url });
}

then with that url I try to make a PUT call with httpie:

echo "something" | http -v PUT https://...presigned url

however I get:

<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>

lambda runs with a full s3 access execution role but permissions shouldn't be the problem here

Update: trying to upload a file without a content-type header works fine:

http -v PUT https://...url

so seems the issue is with the content type, but since I don't specify it I thought AWS doesn't bother if I upload a json or anything else

1

1 Answers

0
votes

In Signature Version 2, at least, the value from the Content-Type header is an integral part of the signature algorithm... so if getSignedUrl doesn't know what you're going to put there, it will generate a signature that will be invalid.

You should be able to add this to the key/value pairs in params:

ContentType, 'text/plain' // using the appropriate mine type string