I have serverless aws lambda that will get/put object onto encrypted S3 buckets via presigned urls. getObject works perfectly. putObject generates SignatureDoesNotMatch
error once I encrypt the bucket and I cannot understand why. I have played with headers and such, but still cannot get it to work. Code / policies below:
lambda
const generatepresignedurl = (req, res, callback) => {
var fileurls = [];
const body = JSON.parse(req.body);
const theBucket = body['theBucket'];
const theKey = body['theKey'];
const theContentType = body['theContentType'];
const theOperation = body['theOperation'];
/*setting the presigned url expiry time in seconds, also check if user making the request is an authorized user
for your app (this will be specific to your app’s auth mechanism so i am skipping it)*/
const signedUrlExpireSeconds = 60 * 60;
if (theOperation == 'getObject') {
var params = {
Bucket: theBucket,
Key: theKey,
Expires: signedUrlExpireSeconds
};
} else {
var params = {
Bucket: theBucket,
Key: theKey,
Expires: signedUrlExpireSeconds,
ACL: 'bucket-owner-full-control',
ContentType: theContentType,
ServerSideEncryption: 'AES256'
};
}
s3.getSignedUrl(theOperation, params, function (err, url) {
if (err) {
console.log('Error Getting Presigned URL from AWS S3');
// callback(null, ({ success: false, message: 'Pre-Signed URL error', urls: fileurls }));
callback(null, {error: err});
}
else {
fileurls[0] = url;
console.log('Presigned URL: ', fileurls[0]);
callback(null, { success: true, message: 'AWS SDK S3 Pre-signed urls generated successfully.', urls: fileurls });
}
});
}
Calling code is here:
Generate PreSigned Url
Function callStandAloneAWSService(lambda As String, request As String, contentType As String) As String
Dim httpserver As New MSXML2.XMLHTTP
With httpserver
Dim theURL As String
theURL = AWS_WEBSERVICE_URL_DEV
.Open "POST", theURL & lambda 'variable that contains generatepresignedurl
.setRequestHeader "Content-type", contentType
.send request
Do: DoEvents: Loop Until .readyState = 4 'make sure we are ready to recieve response
callStandAloneAWSService = .responseText
End With
End Function
Upload to PreSigned URL (original question did not have serversidencryption header)
Function uploadToPreSignedURL(url As String, whichFile As String, contentType) As Boolean
'code to create binaryFile
Dim httpserver As New MSXML2.XMLHTTP
With httpserver
.Open "POST", url
.setRequestHeader "Content-type", "text/plain" 'contentType
.send binaryFile
Do: DoEvents: Loop Until .readyState = 4 'make sure we are ready to recieve response
If Len(.responseText) = 0 Then
uploadToPreSignedURL = True
Else
'extract error message from xml and write to report mail
End If
End With
End Function
bucket policy
{
"Version": "2012-10-17",
"Id": "S3PolicyId1",
"Statement": [
{
"Sid": "DenyIncorrectEncryptionHeader",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::mybiggetybucket/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "AES256"
}
}
},
{
"Sid": "DenyUnEncryptedObjectUploads",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::mybiggetybucket/*",
"Condition": {
"Null": {
"s3:x-amz-server-side-encryption": "true"
}
}
}
]
}
FWIW, I can run this via aws cli and get it to work:
aws s3api put-object --bucket mybiggetybucket --key test.json --body package-lock.json --server-side-encryption "AES256"