amazon web services – “The request signature we calculated does not match the signature you provided.” even though I successfully PUT to an AWS resource

I am following this guide for signing HTTP requests to an Amazon OpenSearch Service using Node.

When I copy the exact sample code and export my AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY of my authorised user, the PUT is successful:

201 Created
Response body: {"_index":"products","_type":"_doc","_id":"2","_version":1,"result":"created","_shards":{"total":2,"successful":2,"failed":0},"_seq_no":0,"_primary_term":1}

However, when I change the request to instead hit /_search endpoint with a GET request, I get:

403 Forbidden
Response body: {"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."}

The authorised user is fully authorised against the index:

    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::**:user/aws-elasticbeanstalk-ec2-user"
      },
      "Action": "es:*",
      "Resource": "arn:aws:es:ap-southeast-2:**:domain/mydomain/*"
    },

How do I rectify my signature?

Here is my modified code from the above link:

const { HttpRequest } = require('@aws-sdk/protocol-http')
const { defaultProvider } = require('@aws-sdk/credential-provider-node')
const { SignatureV4 } = require('@aws-sdk/signature-v4')
const { NodeHttpHandler } = require('@aws-sdk/node-http-handler')
const { Sha256 } = require('@aws-crypto/sha256-browser')

const region = ''
const domain = ''
const index = 'products'
const type="_search"
const createBody = (query) => ({
  query: {
    multi_match: {
      query,
      type: 'phrase',
      fields: [
        'tags',
        'name',
        'category',
        'maker'
      ]
    }
  },
  highlight: {
    pre_tags: [''],
    post_tags: [''],
    fields: {
      tags: {},
      name: {},
      category: {},
      maker: {}
    }
  }
})

searchIndex('sh').then(() => process.exit())

async function searchIndex (query) {
  const request = new HttpRequest({
    body: JSON.stringify(createBody(query)),
    headers: {
      'Content-Type': 'application/json',
      host: domain
    },
    hostname: domain,
    method: 'GET',
    path: index + "https://stackoverflow.com/" + type
  })

  const signer = new SignatureV4({
    credentials: defaultProvider(),
    region: region,
    service: 'es',
    sha256: Sha256
  })

  const signedRequest = await signer.sign(request)

  const client = new NodeHttpHandler()
  const { response } = await client.handle(signedRequest)
  console.log(response.statusCode + ' ' + response.body.statusMessage)

  let responseBody = ''
  return new Promise((resolve) => {
    response.body.on('data', (chunk) => {
      responseBody += chunk
    })
    response.body.on('end', () => {
      console.log('Response body: ' + responseBody)
      resolve(responseBody)
    })
  }, (error) => {
    console.log('Error: ' + error)
  })
}

Read more here: Source link