`SignatureV4` is calculating a different signature to AWS, and I don't understand why
See original GitHub issueI am following this guide for signing HTTP requests using @aws-sdk/signature-v4@3.39.0
to an Amazon OpenSearch Service.
When I copy the exact sample code and export the AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
variables of my authorised user, the PUT index/type/id
request to add a document 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 the GET index/_search
endpoint, 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 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/*"
},
I was wondering how I can rectify my signature, as I have followed Create a canonical request for Signature Version 4 and can’t see why the SignatureV4
builder would produce any errors for the GET
request vs the PUT
request.
Here is my modified code from the guide:
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 + '/' + 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)
})
}
SDK version number
@aws-crypto/sha256-browser@^2.0.0
@aws-sdk/credential-provider-node@^3.39.0
@aws-sdk/node-http-handler@^3.38.0
@aws-sdk/protocol-http@^3.38.0
@aws-sdk/signature-v4@^3.39.0
Is the issue in the browser/Node.js/ReactNative?
Node.js
Details of the browser/Node.js/ReactNative version
node -v: v14.18.1
Issue Analytics
- State:
- Created 2 years ago
- Reactions:4
- Comments:5
I am experiencing the same behavior running in AWS Lambda on Node.js 14 with all
@aws-sdk/*
dependencies atv3.40.0
. APUT
request to add the items works successfully; however, a GET (specifically, a_search
) with a body returns the “different signature” error message. Credentials are being retrieved using thefromEnv()
function in@aws-sdk/credential-providers@3.40.0
for both GET and PUT.Performing a GET request without a body, such as
{index}/_doc/{id}
does worksuccessfully. Having no real knowledge of the inner workings of theSignatureV4
class, this seems to be a bug in the way that GET requests that contain a body are handled.GET
with body (broken): https://github.com/dod-ccpo/atat-web-api/blob/feature/AT-6804/packages/api/portfolioDrafts/getPortfolioDrafts.ts#L92PUT
(working): https://github.com/dod-ccpo/atat-web-api/blob/feature/AT-6804/packages/opensearch/dataCopy/index.ts#L71To transform the
GET
into a working test, the body was omitted and thepath
was changed to a specific document’s ID.Ran into a similar
403
error but withPOST
request. For us, we had URL query parameters that weren’t being passed into the signed request correctly, they were only being appended to thepath
. For some reason, the HTTP request signing guide for OpenSearch doesn’t tell you to set thequery
parameter innew HttpRequest()
which surprisingly solved our issue!