AWS SigV4 signature does not match AWS's calculated

259 Views Asked by At

I am trying to follow the code in the documentation of AWS SigV4 signing process but it seems something is off, as I keep on getting error 403 - signature does not match.

All I did was changing the parameters for my needs. I have been using the same parameters in Postman and they work flawlessly.

Here's my Python code, straight outta the doc:

import sys, datetime, hashlib, hmac
import requests
import const

# ************* REQUEST VALUES *************
method = 'GET'
service = 'sts'
host = 'sts.eu-west-1.amazonaws.com'
region = 'eu-west-1'
endpoint = 'https://sts.eu-west-1.amazonaws.com'
request_parameters = 'Action=AssumeRole&Version=2011-06-15&RoleArn=arn:aws:iam::mySessionName:role/SellingPartnerAPIRole&DurationSeconds=3600&RoleSessionName=mySessionName'

# Key derivation functions. See:
# http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-python
def sign(key, msg):
    return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()

def getSignatureKey(key, dateStamp, regionName, serviceName):
    kSecret = ('AWS4' + key).encode('utf-8')
    kDate = sign(kSecret, dateStamp)
    kRegion = sign(kDate, regionName)
    kService = sign(kRegion, serviceName)
    kSigning = sign(kService, 'aws4_request')
    return kSigning

access_key = const.AWS_ACCESS_KEY_ID
secret_key = const.AWS_SECRET_ACCESS_KEY
if access_key is None or secret_key is None:
    print('No access key is available.')
    sys.exit()

# Create a date for headers and the credential string
t = datetime.datetime.utcnow()
amzdate = t.strftime('%Y%m%dT%H%M%SZ')
datestamp = t.strftime('%Y%m%d')  # Date w/o time, used in credential scope

# ************* TASK 1: CREATE A CANONICAL REQUEST *************
canonical_uri = '/'
canonical_querystring = request_parameters
canonical_headers = 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n'
signed_headers = 'host;x-amz-date'
payload_hash = hashlib.sha256(('').encode('utf-8')).hexdigest()
canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash

# ************* TASK 2: CREATE THE STRING TO SIGN*************
algorithm = 'AWS4-HMAC-SHA256'
credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'
string_to_sign = algorithm + '\n' + amzdate + '\n' + credential_scope + '\n' + hashlib.sha256(
    canonical_request.encode('utf-8')).hexdigest()

# ************* TASK 3: CALCULATE THE SIGNATURE *************
signing_key = getSignatureKey(secret_key, datestamp, region, service)
signature = hmac.new(signing_key, (string_to_sign).encode('utf-8'), hashlib.sha256).hexdigest()

# ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
authorization_header = algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature
headers = {'x-amz-date': amzdate, 'Authorization': authorization_header}

# ************* SEND THE REQUEST *************
request_url = endpoint + '?' + canonical_querystring

print('\nBEGIN REQUEST++++++++++++++++++++++++++++++++++++')
print('Request URL = ' + request_url)
r = requests.get(request_url, headers=headers)

print('\nRESPONSE++++++++++++++++++++++++++++++++++++')
print('Response code: %d\n' % r.status_code)
print(r.text)

I have tried putting in amzdate, datetime, and signature from Postman into this code, and they worked. So I believe there is something wrong with the signature caculation process, but I really can't tell.

I appreciate all the help I can get. Thanks in advance.

1

There are 1 best solutions below

0
On

You could check with this simple library - aws-sigv4-request-generator==0.0.1