Reputation: 413
I'm trying to write Python code that uses a number of different AWS keys, some of which may have expired. I need, given an AWS key pair as strings, to check whether the given key pair is valid using boto3. I would prefer not to have to do anything like using os.system to run
echo "$aws_key_id
$aws_secret_key\n\n" | aws configure
and then reading the response of aws list-buckets.
The answer should look something like
def check_aws_validity(key_id, secret):
pass
where key_id
and secret
are strings.
Note that this is not a repeat of Verifying S3 credentials w/o GET or PUT using boto3, as I do not have the keys in boto3.profile.
Thanks in advance!
EDIT From John Rotenstein's answer, I got the following function to work.
def check_aws_validity(key_id, secret):
try:
client = boto3.client('s3', aws_access_key_id=key_id, aws_secret_access_key=secret)
response = client.list_buckets()
return true
except Exception as e:
if str(e)!="An error occurred (InvalidAccessKeyId) when calling the ListBuckets operation: The AWS Access Key Id you provided does not exist in our records.":
return true
return false
Upvotes: 29
Views: 32002
Reputation: 46
Here is how I solved that:
import boto3
import botocore
def check_login():
sts = boto3.client('sts')
try:
sts.get_caller_identity()
return True
except botocore.exceptions.UnauthorizedSSOTokenError:
return False
if check_login():
print("Credentials are valid.")
else:
# do something to log in
The difference to the answer before is the import of botocore and the catch of the correct error (UnauthorizedSSOTokenError). Also it works with Python3 (e. g. new boolean types to return).
Upvotes: 3
Reputation: 2838
Such a credential-validating method does exist; it's the STS GetCallerIdentity API call (boto3 method docs).
With expired temporary credentials:
>>> import boto3
>>> sts = boto3.client('sts')
>>> sts.get_caller_identity()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/jantman/venv/lib/python3.8/site-packages/botocore/client.py", line 276, in _api_call
return self._make_api_call(operation_name, kwargs)
File "/home/jantman/venv/lib/python3.8/site-packages/botocore/client.py", line 586, in _make_api_call
raise error_class(parsed_response, operation_name)
botocore.exceptions.ClientError: An error occurred (ExpiredToken) when calling the GetCallerIdentity operation: The security token included in the request is expired
With invalid credentials:
>>> import boto3
>>> sts = boto3.client('sts')
>>> sts.get_caller_identity()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/jantman/venvs/current/lib/python3.8/site-packages/botocore/client.py", line 316, in _api_call
return self._make_api_call(operation_name, kwargs)
File "/home/jantman/venvs/current/lib/python3.8/site-packages/botocore/client.py", line 626, in _make_api_call
raise error_class(parsed_response, operation_name)
botocore.exceptions.ClientError: An error occurred (InvalidClientTokenId) when calling the GetCallerIdentity operation: The security token included in the request is invalid
With valid credentials (IDs replaced with X's):
>>> import boto3
>>> sts = boto3.client('sts')
>>> sts.get_caller_identity()
{'UserId': 'AROAXXXXXXXXXXXXX:XXXXXXX', 'Account': 'XXXXXXXXXXXX', 'Arn': 'arn:aws:sts::XXXXXXXXXXXX:assumed-role/Admin/JANTMAN', 'ResponseMetadata': {'RequestId': 'f44ec1d9-XXXX-XXXX-XXXX-a26c85be1c60', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amzn-requestid': 'f44ec1d9-XXXX-XXXX-XXXX-a26c85be1c60', 'content-type': 'text/xml', 'content-length': '426', 'date': 'Thu, 28 May 2020 10:45:36 GMT'}, 'RetryAttempts': 0}}
Invalid credentials will raise an exception and valid credentials won't, so you can do something such as:
import boto3
sts = boto3.client('sts')
try:
sts.get_caller_identity()
print("Credentials are valid.")
except boto3.exceptions.ClientError:
print("Credentials are NOT valid.")
Upvotes: 40
Reputation: 270104
You can make a call by directly specifying credentials:
import boto3
client = boto3.client('s3', aws_access_key_id='xxx', aws_secret_access_key='xxx')
response = client.list_buckets()
You can then use the response to determine whether the credentials are valid.
However, it is possible that a user has valid credentials, but does not have permission to call list_buckets()
. This might make it harder to determine whether they have valid credentials. You'll need to try various combinations to see what response is sent back to your code.
Upvotes: 8