cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
HannahM
Dynatrace Leader
Dynatrace Leader

Self Service Summary

 

There are currently no OOTB templates for AWS Signature Authorization. This guide provides a snippet and instructions to modify it to generate a signed Authorization header for an HTTP request for AWS
See the following for how to sign a request for AWS Signature Version 4:
https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html

 

Issue Solution Tasks Alternative(s)
Need to authenticate using AWS Signature in an HTTP Monitor Use snippet Update snippet with required different headers and definitely different AWS-specific fields Contact support

 

How to add a pre-execution script to add an AWS signature to a request

  1. Create an HTTP Monitor and add the HTTP Request you would like to sign
  2. Enable the pre-execution script and paste in the pre-execution snippet
  3. Update the AccessKey, SecretKey &  IdentityId. These can be taken from a previous request or the Credential Vault. 
  4. Enter the host name
  5. Confirm all the headers required for you request are included in the headers section and add any extras needed. 
  6. Save the Monitor and test it. 

Pre-execution snippet

/*
This code generates a signed Authorization header for an HTTP request for AWS
See the following for how to sign a request for AWS Signature Version 4:
https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
 */

// CryptoJS rollup code for HMACSha256 and Sha256
var CryptoJS=CryptoJS||function(h,s){var f={},g=f.lib={},q=function(){},m=g.Base={extend:function(a){q.prototype=this;var c=new q;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},r=g.WordArray=m.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=s?c:4*a.length},toString:function(a){return(a||k).stringify(this)},concat:function(a){var c=this.words,d=a.words,b=this.sigBytes;a=a.sigBytes;this.clamp();if(b%4)for(var e=0;e<a;e++)c[b+e>>>2]|=(d[e>>>2]>>>24-8*(e%4)&255)<<24-8*((b+e)%4);else if(65535<d.length)for(e=0;e<a;e+=4)c[b+e>>>2]=d[e>>>2];else c.push.apply(c,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<32-8*(c%4);a.length=h.ceil(c/4)},clone:function(){var a=m.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],d=0;d<a;d+=4)c.push(4294967296*h.random()|0);return new r.init(c,a)}}),l=f.enc={},k=l.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++){var e=c[b>>>2]>>>24-8*(b%4)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b+=2)d[b>>>3]|=parseInt(a.substr(b,2),16)<<24-4*(b%8);return new r.init(d,c/2)}},n=l.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++)d.push(String.fromCharCode(c[b>>>2]>>>24-8*(b%4)&255));return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b++)d[b>>>2]|=(a.charCodeAt(b)&255)<<24-8*(b%4);return new r.init(d,c)}},j=l.Utf8={stringify:function(a){try{return decodeURIComponent(escape(n.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return n.parse(unescape(encodeURIComponent(a)))}},u=g.BufferedBlockAlgorithm=m.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=j.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,d=c.words,b=c.sigBytes,e=this.blockSize,f=b/(4*e),f=a?h.ceil(f):h.max((f|0)-this._minBufferSize,0);a=f*e;b=h.min(4*a,b);if(a){for(var g=0;g<a;g+=e)this._doProcessBlock(d,g);g=d.splice(0,a);c.sigBytes-=b}return new r.init(g,b)},clone:function(){var a=m.clone.call(this);a._data=this._data.clone();return a},_minBufferSize:0});g.Hasher=u.extend({cfg:m.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){u.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(c,d){return(new a.init(d)).finalize(c)}},_createHmacHelper:function(a){return function(c,d){return(new t.HMAC.init(a,d)).finalize(c)}}});var t=f.algo={};return f}(Math);(function(h){for(var s=CryptoJS,f=s.lib,g=f.WordArray,q=f.Hasher,f=s.algo,m=[],r=[],l=function(a){return 4294967296*(a-(a|0))|0},k=2,n=0;64>n;){var j;a:{j=k;for(var u=h.sqrt(j),t=2;t<=u;t++)if(!(j%t)){j=!1;break a}j=!0}j&&(8>n&&(m[n]=l(h.pow(k,0.5))),r[n]=l(h.pow(k,1/3)),n++);k++}var a=[],f=f.SHA256=q.extend({_doReset:function(){this._hash=new g.init(m.slice(0))},_doProcessBlock:function(c,d){for(var b=this._hash.words,e=b[0],f=b[1],g=b[2],j=b[3],h=b[4],m=b[5],n=b[6],q=b[7],p=0;64>p;p++){if(16>p)a[p]=c[d+p]|0;else{var k=a[p-15],l=a[p-2];a[p]=((k<<25|k>>>7)^(k<<14|k>>>18)^k>>>3)+a[p-7]+((l<<15|l>>>17)^(l<<13|l>>>19)^l>>>10)+a[p-16]}k=q+((h<<26|h>>>6)^(h<<21|h>>>11)^(h<<7|h>>>25))+(h&m^~h&n)+r[p]+a[p];l=((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+(e&f^e&g^f&g);q=n;n=m;m=h;h=j+k|0;j=g;g=f;f=e;e=k+l|0}b[0]=b[0]+e|0;b[1]=b[1]+f|0;b[2]=b[2]+g|0;b[3]=b[3]+j|0;b[4]=b[4]+h|0;b[5]=b[5]+m|0;b[6]=b[6]+n|0;b[7]=b[7]+q|0},_doFinalize:function(){var a=this._data,d=a.words,b=8*this._nDataBytes,e=8*a.sigBytes;d[e>>>5]|=128<<24-e%32;d[(e+64>>>9<<4)+14]=h.floor(b/4294967296);d[(e+64>>>9<<4)+15]=b;a.sigBytes=4*d.length;this._process();return this._hash},clone:function(){var a=q.clone.call(this);a._hash=this._hash.clone();return a}});s.SHA256=q._createHelper(f);s.HmacSHA256=q._createHmacHelper(f)})(Math);(function(){var h=CryptoJS,s=h.enc.Utf8;h.algo.HMAC=h.lib.Base.extend({init:function(f,g){f=this._hasher=new f.init;"string"==typeof g&&(g=s.parse(g));var h=f.blockSize,m=4*h;g.sigBytes>m&&(g=f.finalize(g));g.clamp();for(var r=this._oKey=g.clone(),l=this._iKey=g.clone(),k=r.words,n=l.words,j=0;j<h;j++)k[j]^=1549556828,n[j]^=909522486;r.sigBytes=l.sigBytes=m;this.reset()},reset:function(){var f=this._hasher;f.reset();f.update(this._iKey)},update:function(f){this._hasher.update(f);return this},finalize:function(f){var g=this._hasher;f=g.finalize(f);g.reset();return g.finalize(this._oKey.clone().concat(f))}})})();

/*
Build a signature key that is used to sign data
https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
 */
function getSignatureKey(key, dateStamp, regionName, serviceName) {
    var kDate = CryptoJS.HmacSHA256(dateStamp, "AWS4" + key);
    var kRegion = CryptoJS.HmacSHA256(regionName, kDate);
    var kService = CryptoJS.HmacSHA256(serviceName, kRegion);
    var kSigning = CryptoJS.HmacSHA256("aws4_request", kService);
    return kSigning;
}

AccessKey = api.getValue("AccessKey");
SecretKey = api.getValue("SecretKey");
awsService = "execute-api";
awsRegion = api.getValue("IdentityId").split(':')[0];
now = new Date();
dateStamp = now.getUTCFullYear() + (now.getUTCMonth() < 9 ? '0' : '') + (now.getUTCMonth() + 1);
dateStamp += (now.getUTCDate() < 10 ? '0' : '') + now.getUTCDate();
signKey = getSignatureKey(SecretKey, dateStamp, awsRegion, awsService);
api.info('Signing key: ' + signKey);

/*
All the headers that need to be signed (non-default headers) and in
alphabetical order by name.  I manually sorted the header order, but
this code should have a function to sort them by name in lowercase.
 */

host = '<some hostname: e.g. - www.d5.google.com>';

amzDate = dateStamp + 'T' + now.toUTCString().split(/ /)[4].replace(/\:/g, '') + 'Z';
SessionToken = api.getValue("SessionToken");

// this section must list all the headers that will be added to the request
headers = [{
        "clientrequestid": "P123456789"
    }, {
        "content-type": "application/json"
    }, {
        "deviceid": "5555555"
    }, {
        "Host": host
    }, {
        "X-Amz-Date": amzDate
    }, {
        "X-Amz-Security-Token": SessionToken
    }, {
        "x-api-key": "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd123"
    }, {
        "x-clientapp-version": "1.2"
    }, {
        "x-device-id": "89406"
    }, {
        "x-originator-type": "app"
    }
];

/*
Building the canonical request and adding the headers to the HTTP request
https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
 */

// HTTP Request parameters
method = "GET";
path = '/v1/accounts/vehicles';
queryStr = '';
payload = '';
payloadHash = CryptoJS.SHA256(payload).toString();

signedHeads = "";
canonReq = method + "\
    " + path + "\
    " + queryStr + "\
    ";
for (i = 0; i < headers.length; i++) {
    name = Object.keys(headers[i])[0];
    value = headers[i][name];
    signedHeads += name.toLowerCase() + ";";
    canonReq += name.toLowerCase() + ':' + value + '\
    ';
    request.addHeader(name, value);
}
signedHeads = signedHeads.substr(0, signedHeads.length - 1); // remove last semi-colon
canonReq += "\
" + signedHeads + "\
" + payloadHash;

// Hash of the canonical request
canonHash = CryptoJS.SHA256(canonReq).toString();
api.info('Hash of Canonical request: ' + canonHash);

/*
Building the string to sign
https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
 */
signStr = "AWS4-HMAC-SHA256\
    " + amzDate + "\
    " + dateStamp + "/";
signStr += awsRegion + "/" + awsService + "/aws4_request\
" + canonHash;
api.info('String to sign: ' + signStr);

/*
Signing the string
https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
 */
sig = CryptoJS.HmacSHA256(signStr, signKey).toString();

authString = 'AWS4-HMAC-SHA256 Credential=' + AccessKey + '/' + dateStamp + '/' + awsRegion + '/' + awsService + '/aws4_request, SignedHeaders=' + signedHeads + ', Signature=' + sig;
api.info('authString: ' + authString);

request.addHeader("Authorization", authString);

 

Version history
Last update:
‎04 Aug 2023 03:46 PM
Updated by:
Comments
AntonPineiro
DynaMight Guru
DynaMight Guru

Hi,

I have just tried ant returns a 403:

"healthStatusCode": 6,
"healthStatus": "INVALID_CODE",
"responseBody": "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details"

I have just tried it using Postman and no problem. AWS keys are correct.

Best regards

HannahM
Dynatrace Leader
Dynatrace Leader

Thanks Anton. Can you create a ticket? I think we would need to check the exact code being used in each case.