As a good starting point we will use the first GET example on this page as a working base and modify it to retrieve the instance role credentials and add the session token to the request as follows.
Step 1: Retrieve the instance role credentials
As per the AWS documentation, instance credentials can be retrieved from the instance metadata by performing a GET against the following URL, where <role-name> is the name of the instance role containing the relevant permissions:http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>
In our example with the role named ec2-ro the result of the request will be similar to the result below where the body of the token has been replaced with [...] for brevity:
$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-ro
{
"Code" : "Success",
"LastUpdated" : "2014-10-05T07:25:22Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "ASIXXXXXXXXXXXX",
"SecretAccessKey" : "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234",
"Token" : "AXXXXXX//////////[...]==",
"Expiration" : "2014-10-05T13:30:35Z"
}
Achieving the same in Python is pretty simple:
creds = requests.get('http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-ro')
access_key = creds.json()['AccessKeyId']
secret_key = creds.json()['SecretAccessKey']
token = creds.json()['Token']
access_key = os.environ.get('AWS_ACCESS_KEY_ID')
secret_key = os.environ.get('AWS_SECRET_ACCESS_KEY')
Unfortunately we are not finished yet as running the new code now results in a 401 response with the following message:
"AWS was not able to validate the provided access credentials"
The reason for the error above is that the instance credentials require a session token to be considered valid, moving on to the next step.
Step 2: Add the session token to the request headers
Fixing the invalid credential error above is relatively trivial and simply involves adding the session token to the request headers with a header name of x-amz-security-token. So replacing this line:headers = {'x-amz-date':amzdate, 'Authorization':authorization_header}
With the following line:
headers = {'x-amz-date':amzdate, 'Authorization':authorization_header, 'x-amz-security-token':token}
Allows the code to execute successfully. One thing to be aware of is that the instance credentials are rotated fairly frequently and the credentials will need to be refreshed after the date and time in the instance metadata Expiration field.