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

Summary

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.

 

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, and IdentityId. These can be taken from a previous request or the Credential Vault. 
  4. Enter the hostname
  5. Confirm all the headers required for your 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);

 

What's Next

If none of the previous steps resolved the issue, you can

  • open a chat, or support ticket, and provide a link to the affected monitor and the troubleshooting steps you have already completed. Support can help spot errors in applying this snippet or give you pointers.
    or
  • talk to your Customer Success Manager, or account team, and discuss getting some scripting assistance. 

You can find further troubleshooting tips for Synthetic in the Synthetic Troubleshooting Map

Version history
Last update:
‎20 Oct 2025 03:40 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 Guru
Dynatrace Guru

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