My last post was about a simple script I wrote to start up an EC2 instance and verify the SSH fingerprint. It did the trick but left me itching for something that was a little easier to extend and generalize.
I've also been itching to learn some Python, so for my next experiment I wrote a Python script (my first) that generates the security signature for an EC2 API request. Google pointed me to several solutions, but they were all either outdated (version 1 of the signature specification), incomplete, inaccurate or all of the above.
The following script works for me. It is still hard coded to perform a single type of simple request, but it should be a useful example for anybody that just wants to sign an EC2 request in Python.
The boto project also provides what looks like a fairly complete Python interface to most of the Amazon web services.
#!/usr/bin/python3
import base64,hashlib,hmac,datetime,urllib.parse,urllib.request
endpoint = 'ec2.us-west-1.amazonaws.com'
aws_secret_access_key = b'YOUR_KEY_SECRET'
params = {}
params['Version'] = '2011-01-01'
params['AWSAccessKeyId'] = 'YOUR_ACCESS_KEY'
now = datetime.datetime.utcnow()
params['Timestamp'] = now.strftime("%Y-%m-%dT%H:%M:%S.000Z")
# this can be omitted
expires = now + datetime.timedelta(minutes=10)
params['Expires'] = expires.strftime("%Y-%m-%dT%H:%M:%SZ")
params['SignatureMethod'] = 'HmacSHA256'
params['SignatureVersion'] = '2'
params['Action'] = 'DescribeInstances'
keys = sorted(params.keys())
values = map(params.get, keys)
query_string = urllib.parse.urlencode( list(zip(keys,values)) )
# construct the string to sign
string_to_sign = '\n'.join(['GET', endpoint, '/', query_string])
# sign the request
signature = hmac.new(
key=aws_secret_access_key,
msg=bytes(string_to_sign, 'UTF-8'),
digestmod=hashlib.sha256).digest()
# base64 encode the signature. URL safe base64 encoding does NOT work
signature = base64.b64encode(signature)
signature = urllib.parse.quote(signature)
url = 'https://' + endpoint + '/?' + query_string + '&Signature=' + signature
response = urllib.request.urlopen(url)
xml = response.read()
# learning a little about xml parsing in Python is my next project
print(xml)
No comments:
Post a Comment