Search code examples
python-3.xamazon-web-servicesboto3

Verify AWS Credentials with boto3


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

Solution

  • 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.")