Signature calculation to access Amazon Bedock

55 Views Asked by At

I am trying to make a POST request to Amazon Bedrock without using SDKs in Nodejs/JS. I managed to tweak the code given in here: (How to sign POST request with AWS Signature Version 4) to access S3. But generating the Signature the same way did not work with Bedock. It says

      message: '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.'
    

Appreciate if someone can show a code snippet to talk directly to Amazon bedrock in NodeJS / JS without using amazon sdk s

-RR-

I tried tweaking the code given in here: text }

Here is my NodeJS code

import axios from 'axios'
import crypto from 'crypto-js'
async function send() {
    //AWS credentials
    const access_key = "XXXXXXXXX"
    const secret_key = "XXXXXXXXX"
    const method = 'POST';
    const service = 'bedrock';
    const region = 'eu-central-1'; //'us-east-1' 
    const host = 'bedrock-runtime.' + region + '.amazonaws.com/model/anthropic.claude-v2:1/invoke';
    //const host = 'bedrock-runtime.' + region + '.amazonaws.com'
    const canonical_uri = '/'
    const base = "https://"
    const content_type = 'application/json';
    const amz_target = '';
    var request_parameters =''
    // Create a date for headers and the credential string
    const amz_date = getAmzDate(new Date().toISOString());
    const date_stamp = amz_date.split("T")[0]; 
    //request parameters are passed in the body of the request and the query string is blank.
    const canonical_querystring = ''
    var payload = {
        "prompt": "\n\Utterance: Hello how are you\n\nAssistant:",
        "max_tokens_to_sample": 300,
        "temperature": 0.5,
        "top_k": 250,
        "top_p": 1,
        "anthropic_version": "bedrock-2023-05-31"
    };  
    //var payload = "{'prompt' : 'Hello how are you'}";
    var payload_hash = crypto.SHA256(payload)
    //Choose Signature headers. 
    const signed_headers = 'content-type;host;x-amz-content-sha256;x-amz-date'
    //const signed_headers = 'content-type;host;x-amz-date'
    //const signed_headers = 'host;x-amz-content-sha256;x-amz-date'
    //const signed_headers = 'host;x-amz-date'
    //Create cannonocal_headers according to the signed_headers used above
    var canonical_headers = createCanonicalHeaders(signed_headers, host, payload_hash,amz_date)
    console.log('\ncanonical_headers:\n' + canonical_headers)
    //create canonical request
    const canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash
    var canonical_request_hash = crypto.SHA256(canonical_request)
    const algorithm = 'AWS4-HMAC-SHA256'
    const credential_scope = date_stamp + '/' + region + '/' + service + '/' + 'aws4_request'
    const string_to_sign = algorithm + '\n' +  amz_date + '\n' +  credential_scope + '\n' +  canonical_request_hash  //.toString()
    console.log("\nstring_to_sign:\n",string_to_sign)
    // Create the signing key
    const signing_key = getSignatureKey(secret_key, date_stamp, region, service)
    // Sign the string_to_sign using the signing_key
    var signature = sign(string_to_sign, signing_key);
    // Put the signature information in a header named Authorization.
    const authorization_header = algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' +  'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature
    console.log("\nauthorization_header:\n" + authorization_header)
    //request headers
    const headers = {
        'Authorization':authorization_header,
        'Content-Type':content_type,        
        'X-Amz-Content-Sha256':payload_hash, 
        'X-Amz-Date':amz_date
    }
    // ************* SEND THE REQUEST *************
    var response = await axios({
        method: method,
        baseURL: base + host, 
        url: canonical_uri,
        data:JSON.stringify(payload), //request_parameters,
        headers: headers,
    });
    console.log(response)
}
//call the send() function
send()
//Function implementations
function sign(key, msg) {
    return crypto.HmacSHA256(msg,key)
    //return crypto.HmacSHA256(crypto.enc.Hex.parse(msg), key)
}
function getSignatureKey(key, date_stamp, regionName, serviceName) {
    var kDate = sign(('AWS4' + key), date_stamp)
    var kRegion = sign(kDate, regionName)
    var kService = sign(kRegion, serviceName)
    var kSigning = sign(kService, 'aws4_request')
    return kSigning
}
function createCanonicalHeaders(signed_headers, host, payload_hash,amz_date) {
    var canonical_headers =''
    if(signed_headers.includes('content-type')) {
        canonical_headers = canonical_headers  + 'content-type:application/json' + "\n"
    }   
    if(signed_headers.includes('host')) {
        canonical_headers = canonical_headers + 'host:' + host + "\n"
    }
    if(signed_headers.includes('x-amz-content-sha256')) {
        canonical_headers = canonical_headers +  'x-amz-content-sha256:' + payload_hash + "\n"
    }
    if(signed_headers.includes('x-amz-date')) {
        canonical_headers = canonical_headers + 'x-amz-date:' + amz_date + '\n' 
    }
    return canonical_headers
}       
// this function converts the generic JS ISO8601 date format to the specific format the AWS API wants
function getAmzDate(dateStr) {
    var chars = [":","-"];
    for (var i=0;i<chars.length;i++) {
        while (dateStr.indexOf(chars[i]) != -1) {
            dateStr = dateStr.replace(chars[i],"");
        }
    }
    dateStr = dateStr.split(".")[0] + "Z";
    return dateStr;
}

1

There are 1 best solutions below

0
JesusS On

You can use aws4 or aws4-axios. Back in the day i tried to sign manually and didnt managed to do it