Skip to content

Instantly share code, notes, and snippets.

@hugotkk
Created April 13, 2023 12:30
Show Gist options
  • Save hugotkk/a5897367c5e1667ee138acbe4be07b43 to your computer and use it in GitHub Desktop.
Save hugotkk/a5897367c5e1667ee138acbe4be07b43 to your computer and use it in GitHub Desktop.
Example of aws ec2 describe-instances with curl and aws signature V4
import datetime
import hashlib
import hmac
import urllib.parse
def sign_request(method, url, region, service, access_key, secret_key, data='', headers=None):
if headers is None:
headers = {}
# Create a new datetime object and convert it to ISO format
now = datetime.datetime.utcnow()
amzdate = now.strftime('%Y%m%dT%H%M%SZ')
datestamp = now.strftime('%Y%m%d')
# Set the AWS request headers
headers['x-amz-date'] = amzdate
headers['Host'] = urllib.parse.urlparse(url).hostname
# Create a canonical request
canonical_uri = urllib.parse.urlparse(url).path or '/'
canonical_querystring = urllib.parse.urlparse(url).query
canonical_headers = '\n'.join([f"{key.lower()}:{value.strip()}" for key, value in sorted(headers.items())])
payload_hash = hashlib.sha256(data.encode('utf-8')).hexdigest()
canonical_request = '\n'.join([
method,
canonical_uri,
canonical_querystring,
canonical_headers,
'',
'content-type;host;x-amz-date',
payload_hash
])
# Create a string to sign
algorithm = 'AWS4-HMAC-SHA256'
credential_scope = f"{datestamp}/{region}/{service}/aws4_request"
string_to_sign = '\n'.join([
algorithm,
amzdate,
credential_scope,
hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()
])
# Generate the signing key
kdate = hmac.new(('AWS4' + secret_key).encode('utf-8'), datestamp.encode('utf-8'), hashlib.sha256).digest()
kregion = hmac.new(kdate, region.encode('utf-8'), hashlib.sha256).digest()
kservice = hmac.new(kregion, service.encode('utf-8'), hashlib.sha256).digest()
ksigning = hmac.new(kservice, b'aws4_request', hashlib.sha256).digest()
# Generate the signature
signature = hmac.new(ksigning, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()
# Add the authorization header to the request headers
headers['Authorization'] = f"{algorithm} Credential={access_key}/{credential_scope}, SignedHeaders=content-type;host;x-amz-date, Signature={signature}"
return headers
api_action = 'DescribeInstances'
api_version = '2016-11-15'
endpoint_url = f'https://ec2.amazonaws.com?Action={api_action}&Version={api_version}'
data = f''
region = 'us-east-1'
access_key = '<ACCESS_KEY>'
secret_key = '<SECRET_KEY>'
service = 'ec2'
method = 'GET'
headers = sign_request(method, endpoint_url, region, service, access_key, secret_key, headers={'Content-Type': 'application/x-www-form-urlencoded'}, data=data)
curl_command = f"curl -X {method} --location '{endpoint_url}' \\\n"
if data:
curl_command += f"--data '{data}' \\\n"
curl_command += f"--header 'Content-Type: {headers['Content-Type']}' \\\n"
curl_command += f"--header 'x-amz-date: {headers['x-amz-date']}' \\\n"
curl_command += f"--header 'Authorization: {headers['Authorization']}' \n"
print(curl_command)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment