Использование подписи AWS4 через почтальона для операций CRUD Elastic - PullRequest
0 голосов
/ 03 февраля 2019

Я пытаюсь опубликовать данные в Elasticsearch, управляемом AWS, используя метод подписи AWS4.Я хотел бы добиться этого с помощью предварительного сценария почтальона.Я попытался использовать приведенный ниже скрипт, который отлично работал для операции GET поиска Elastic, но не работал для операций POST или PUT или DELETE, и продолжал выдавать мне сообщение об ошибке, что подпись не соответствует операции POST.Может кто-нибудь помочь мне в исправлении ниже pre-script в почтальоне?

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) {
        requestBody = '';
    } else {
        requestBody = JSON.stringify(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;
}

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

Код из OP является почти точным, просто есть несколько ошибок

1) getPath должен возвращать "/", когда path=''
2) проверить, является ли request.data пустым объектом, если так requestBody = ''
3) не нужно делать JSON.stringify(request.data), поскольку request.data возвращает строку json

Фиксированный фрагмент приведен ниже:

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;
}

0 голосов
/ 04 февраля 2019

При настройке CloudWatch Logs в потоке Amazon Elasticsearch AWS создает функцию Node.js Lambda, которая выполняет надлежащую подпись URL-адреса AWS SigV4.Вот соответствующая часть этого скрипта, которую вы можете использовать для правильной генерации вашего запроса почтальона:

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);
}
...