Using AWS4 Signature via Postman for CRUD Elastic operations Using AWS4 Signature via Postman for CRUD Elastic operations elasticsearch elasticsearch

Using AWS4 Signature via Postman for CRUD Elastic operations


The code from the OP is almost accurate just has a few bugs

1) getPath should return "/" when path=''
2) check if request.data is empty object if so requestBody = ''
3) no need to do JSON.stringify(request.data) since request.data returns a json string

The fixed snippet is below:

var date = new Date().toISOString();var amzdate = date.replace(/[:\-]|\.\d{3}/g, "");var dateStamp = amzdate.slice(0, -8);pm.environment.set('authorization', getAuthHeader(request.method, request.url, request.data));pm.environment.set('xAmzDate', amzdate);function getPath(url) {    var pathRegex = /.+?\:\/\/.+?(\/.+?)(?:#|\?|$)/;    var result = url.match(pathRegex);    return result && result.length > 1 ? result[1] : '/';}function getQueryString(url) {    var arrSplit = url.split('?');    return arrSplit.length > 1 ? url.substring(url.indexOf('?') + 1) : '';}function getSignatureKey(secretKey, dateStamp, regionName, serviceName) {    var kDate = sign("AWS4" + secretKey, dateStamp);    var kRegion = sign(kDate, regionName);    var kService = sign(kRegion, serviceName);    var kSigning = sign(kService, "aws4_request");    return kSigning;}function sign(key, message) {    return CryptoJS.HmacSHA256(message, key);}function getAuthHeader(httpMethod, requestUrl, requestBody) {    var ACCESS_KEY = pm.globals.get("access_key");    var SECRET_KEY = pm.globals.get("secret_key");    var REGION = 'us-east-1';    var SERVICE = 'es';    var ALGORITHM = 'AWS4-HMAC-SHA256';    var canonicalUri = getPath(requestUrl);    var canonicalQueryString = getQueryString(requestUrl);    if (httpMethod == 'GET' || !requestBody || Object.keys(requestBody).length === 0) {        requestBody = '';    }     var hashedPayload = CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(requestBody));    var canonicalHeaders = 'host:' + pm.environment.get("ESHost") + '\n' + 'x-amz-date:' + amzdate + '\n';    var signedHeaders = 'host;x-amz-date';    var canonicalRequestData = [httpMethod, canonicalUri, canonicalQueryString, canonicalHeaders, signedHeaders, hashedPayload].join("\n");    var hashedRequestData = CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(canonicalRequestData));    var credentialScope = dateStamp + '/' + REGION + '/' + SERVICE + '/' + 'aws4_request';    var stringToSign = ALGORITHM + '\n' + amzdate + '\n' + credentialScope + '\n' + hashedRequestData;    var signingKey = getSignatureKey(SECRET_KEY, dateStamp, REGION, SERVICE);    var signature = CryptoJS.HmacSHA256(stringToSign, signingKey).toString(CryptoJS.enc.Hex);    var authHeader = ALGORITHM + ' ' + 'Credential=' + ACCESS_KEY + '/' + credentialScope + ', ' + 'SignedHeaders=' + signedHeaders + ', ' + 'Signature=' + signature;    return authHeader;}


When setting up a CloudWatch Logs to Amazon Elasticsearch stream, AWS creates a Node.js Lambda function which does proper AWS SigV4 URL signing. Here's the relevant part from that script that you could reuse to properly generate your postman request:

function buildRequest(endpoint, body) {  var endpointParts = endpoint.match(/^([^\.]+)\.?([^\.]*)\.?([^\.]*)\.amazonaws\.com$/);  var region = endpointParts[2];  var service = endpointParts[3];  var datetime = (new Date()).toISOString().replace(/[:\-]|\.\d{3}/g, '');  var date = datetime.substr(0, 8);  var kDate = hmac('AWS4' + process.env.AWS_SECRET_ACCESS_KEY, date);  var kRegion = hmac(kDate, region);  var kService = hmac(kRegion, service);  var kSigning = hmac(kService, 'aws4_request');  var request = {    host: endpoint,    method: 'POST',    path: '/_bulk',    body: body,    headers: {       'Content-Type': 'application/json',      'Host': endpoint,      'Content-Length': Buffer.byteLength(body),      'X-Amz-Security-Token': process.env.AWS_SESSION_TOKEN,      'X-Amz-Date': datetime    }  };  var canonicalHeaders = Object.keys(request.headers)    .sort(function(a, b) { return a.toLowerCase() < b.toLowerCase() ? -1 : 1; })    .map(function(k) { return k.toLowerCase() + ':' + request.headers[k]; })    .join('\n');  var signedHeaders = Object.keys(request.headers)    .map(function(k) { return k.toLowerCase(); })    .sort()    .join(';');  var canonicalString = [    request.method,    request.path, '',    canonicalHeaders, '',    signedHeaders,    hash(request.body, 'hex'),  ].join('\n');  var credentialString = [ date, region, service, 'aws4_request' ].join('/');  var stringToSign = [    'AWS4-HMAC-SHA256',    datetime,    credentialString,    hash(canonicalString, 'hex')  ] .join('\n');  request.headers.Authorization = [    'AWS4-HMAC-SHA256 Credential=' + process.env.AWS_ACCESS_KEY_ID + '/' + credentialString,    'SignedHeaders=' + signedHeaders,    'Signature=' + hmac(kSigning, stringToSign, 'hex')  ].join(', ');  return request;}function hmac(key, str, encoding) {  return crypto.createHmac('sha256', key).update(str, 'utf8').digest(encoding);}function hash(str, encoding) {  return crypto.createHash('sha256').update(str, 'utf8').digest(encoding);}