04 Aug 2023 03:46 PM - edited 20 Oct 2025 03:40 PM
There are currently no out-of-the-box templates for AWS Signature Authorization in Dynatrace Synthetic monitoring. This article provides a snippet and instructions for modifying it to generate a signed Authorization header for an HTTP request for AWS.
You can find more information on how to create a signed AWS API request, using AWS Signature Version 4, here.
/*
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);
If none of the previous steps resolved the issue, you can
You can find further troubleshooting tips for Synthetic in the Synthetic Troubleshooting Map
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