Skip to content

Instantly share code, notes, and snippets.

@salrashid123
Last active September 10, 2024 12:21
Show Gist options
  • Save salrashid123/796faa071ce38ccf74041f3581848139 to your computer and use it in GitHub Desktop.
Save salrashid123/796faa071ce38ccf74041f3581848139 to your computer and use it in GitHub Desktop.
AWS SigV4 Signing without SDK

Variant of AWS v4 signing without SDK

but the varaint below invokes sts.GetCallerIdentity

To use, simply export env vars and run the python script below.

The script will manually sign and invoke the api using the AWS_SECRET_ACCESS_KEY as the secret

export AWS_ACCESS_KEY_ID=redacted
export AWS_SECRET_ACCESS_KEY=redacted

aws sts get-caller-identity --debug
import datetime
import hashlib
import hmac
import requests
import os


import http.client as http_client
http_client.HTTPConnection.debuglevel = 1
import logging

logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True


# AWS access keys
access_key = os.environ['AWS_ACCESS_KEY_ID']  
secret_key = os.environ['AWS_SECRET_ACCESS_KEY']

# Request parameters
method = 'POST'
service = 'sts'
host = "sts.amazonaws.com"
region = 'us-east-1'
endpoint = '/'

# Create a datetime object for signing
t = datetime.datetime.utcnow()
amzdate = t.strftime('%Y%m%dT%H%M%SZ')
datestamp = t.strftime('%Y%m%d') 

# Create the canonical request
canonical_uri = endpoint

canonical_querystring = ''
canonical_headers = 'content-type:application/x-www-form-urlencoded' + '\n' +'host:' + host + '\n' + 'x-amz-date:'  + amzdate + '\n'

signed_headers = 'content-type;host;x-amz-date'

# https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html
payload = 'Action=GetCallerIdentity&Version=2011-06-15'
#payload = 'Action=GetSessionToken&DurationSeconds=3600&Version=2011-06-15'
#payload = 'Action=AssumeRole&&RoleSessionName=testAR&RoleArn=arn:aws:iam::291738886548:role/gcpsts&Version=2011-06-15'

payload_hash = hashlib.sha256(payload.encode('utf-8')).hexdigest()
canonical_request = (method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n'
                     + canonical_headers + '\n' + signed_headers + '\n' + payload_hash)

# 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())

def sign(key, msg):
    return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest()

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

# Sign the string    
signing_key = getSignatureKey(secret_key, datestamp, region, service)
signature = hmac.new(signing_key, (string_to_sign).encode('utf-8'), hashlib.sha256).hexdigest()

# Add signing information to the request
authorization_header = (algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' +  
                        'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature)

print(authorization_header)
# Make the request
headers = {'content-type': 'application/x-www-form-urlencoded',  
           'host': host,
           'x-amz-date': amzdate,
           'Authorization': authorization_header}
request_url = 'https://' + host + canonical_uri


response = requests.post(request_url, headers=headers, data=payload,allow_redirects=False, timeout=5)
response.raise_for_status()

print(response.text)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment