Sign In Register

How can we help you today?

Start a new topic

HowTo: AWS REST API from Cloud Code using Signature Version 2

Here is a small howto on how to call AWS REST API from Cloud Code, since AWS is using a signing method, you would need to implement that to use and here is how.


Step 1 - Create event with following Attributes:

  • region (string)
  • service (string)
  • querydata (json)

Step 2 - Add this code to the Event:

// ACC DATA
var access_key = "SET_YOUR_AWS_ACCESS_KEY";
var secret_key = "SET_YOUR_AWS_SEC_KEY";

// REQ DATA
var Params  = Spark.getData();

var service = Params.service;
var region  = Params.region;

// CONST PARAMS
var method          = "GET";
var host_endpoint   = 'amazonaws.com';
var host_url        = service + "." + (region ? region + "." : "" ) + host_endpoint;
var http_endpoint   = 'https://' + host_url;
var canonical_uri   = '/'; 

// get request params and sort them canonical
var canonical_querystring = getCanonicalQueryString(Params.querydata.params, access_key);

var canonical_request = 
    method + '\n' +                 // GET\n
    host_url + '\n' +               // ec2.amazonaws.com\n
    canonical_uri + '\n' +          // /\n
    canonical_querystring; //+'\n'  // Action=...&...

var ready_signature = Spark.getDigester().hmacSha256Base64(secret_key, canonical_request);

var ready_request = http_endpoint 
    + "?" + canonical_querystring 
    + "&Signature=" + amzUriEncode(ready_signature);

var response        = Spark.getHttp(ready_request).get();
var response_string = response.getResponseJson();
var response_code   = response.getResponseCode();

Spark.setScriptData("response_json", response_string);
Spark.setScriptData("response_code", response_code);

// HELPERS
function getCanonicalQueryString(params, AWSAccessKeyId)
{
    // add AWSAccessKeyId
    params.push({"k" : "AWSAccessKeyId", "v": AWSAccessKeyId});
    // add SignatureMethod 
    params.push({"k" : "SignatureMethod", "v": "HmacSHA256"});
    // add SignatureVersion 
    params.push({"k" : "SignatureVersion", "v": "2"});
    // add Timestamp 
    params.push({"k" : "Timestamp", "v": getAmzDateTimeString()});
    // add Version 
    params.push({"k" : "Version", "v": "2016-11-15"});

    // Sort the query string components by byte order
    params.sort(function(a, b) {
        return (a.k > b.k) - (a.k < b.k);
    });
    
    // Create the query string format "qk=qv&.."
    var i = 0; 
    var retQStr = "";
    var len = params.length;
    for (i = 0; i < len; ++i) {
        retQStr += qKv(params[i].k, params[i].v) + "&"; 
    }
    return retQStr.slice(0, -1); // remove last &
}

function getAmzDateTimeString()
{
    return (new Date()).toISOString().slice(0, -5); 
}

function amzUriEncode(input) {
    var result = "";
    var len = input.length;
    for (var i = 0; i < len ; i++) {
        var ch = input.charAt(i);
        if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '-' || ch == '~' || ch == '.') {
            result += ch;
        } else if (ch == '/') {
            result += "%2F";
        } else {
            result += encodeURIComponent(ch);
        }
    }
    return result;
}

function qKv(k, v) {
    return amzUriEncode(k) + "=" + amzUriEncode(v);
}


Now you can call your Cloud Code with given parameters, this example demonstrates how to use aws ec2 to start some given instance:


{
  "@class": ".LogEventRequest",
  "eventKey": "YOUR_AWS_EVENT_NAME",
  "region": "us-west-2",
  "service": "ec2",
  "querydata": {"params": [
        {"k": "Action", "v": "StartInstances"}, 
        {"k": "InstanceId.1", "v": "i-0797eaeea32a3236i"}]}
}

  

Enjoy your AWS API Requests! :)



Hi Pr0eX,


Thanks for sharing. I'm sure some of our users will find this useful.


Regards,

Liam


2 people like this

Thank you for posting this!
I am trying to make some requests to the AWS sqs using your code. 
I am however getting errors about the signature being incorrect. I know this posted a couple years ago so I was wondering if this was still working for you. Or maybe there was an updated version?


Thank You!

Haven't been here for two years, thought they would have a complete AWS integration by now. :)


So to the problem at hand, this post describes Version2 of AWS signing ( https://docs.aws.amazon.com/general/latest/gr/signature-version-2.html ) by the look of it, with SQS you still should be able to use it ( this site recommends using Version4: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-api-request-authentication.html ).

Shortly after I implemented Version2 I also implemented Version4, so maybe I could find it lin one of my archived backups. Once I get to access them I will try to find it.


In the meantime you could implement it yourself :) it's described by AWS API page in detail somewhere (like: https://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html ). For gamesparks you would need to use a function they introduced after I found a bug, it's called: hmacSha256HexWithHexKey


example usage:

var sD = Spark.getDigester();
var firstHash = sD.hmacSha256Hex("somekey", "sometext");
var secondHash = sD.hmacSha256HexWithHexKey(firstHash, "sometext2");
Spark.setScriptData("hash", secondHash);

  -Best

Login to post a comment