I want to write a python program that make some API calls using user A's credential and then create an access key for user B. Then I want to use user B's newly created access key to make get caller identity API call. Here are the challenges:
when I directly use the keys returned by the createAccessKey api call, I am constantly getting this error
Traceback (most recent call last):
File "mock.py", line 142, in <module>
main()
File "mock.py", line 130, in main
print(client1.get_caller_identity())
File "/home/joe/.local/lib/python3.8/site-packages/botocore/client.py", line 535, in _api_call
return self._make_api_call(operation_name, kwargs)
File "/home/joe/.local/lib/python3.8/site-packages/botocore/client.py", line 980, 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.
However, if I type in the hard coded credentials generated from the create access key call, then the program will finish without any problems. I.e., uncomment out the second line below in the program and put in the access keys created:
# NOTE: manually put in the key id and access key created by the createAccessKey call above
#cred_new = credential('', '', None)
Here is the full program
import boto3
import time
class credential:
aws_access_key_id = ''
aws_secret_access_key = ''
aws_session_token = ''
def __init__(self, aws_access_key_id, aws_secret_access_key, aws_session_token=None) -> None:
self.aws_access_key_id = aws_access_key_id
self.aws_secret_access_key = aws_secret_access_key
self.aws_session_token = aws_session_token
def initialize_each_service(cred, service_name):
client = boto3.client(
service_name = service_name,
aws_access_key_id=cred.aws_access_key_id,
aws_secret_access_key=cred.aws_secret_access_key,
aws_session_token=cred.aws_session_token
)
return client
def initialize_clients(client_map, cred):
# TODO: read keys from a file
# Initialize the AWS STS (Security Token Service) client
service_list = ['sts', 'iam', 'guardduty']
for service_name in service_list:
client_map[service_name] = initialize_each_service(cred, service_name)
return client_map
def get_caller_identity(client_map):
response = client_map['sts'].get_caller_identity()
# Get the caller identity
# Extract and print the caller identity information
account_id = response['Account']
arn = response['Arn']
print(f"AWS Account ID: {account_id}")
print(f"Caller ARN: {arn}")
def create_access_key(client_map, target_user_name):
# Create an access key for the IAM user
response = client_map['iam'].create_access_key(UserName=target_user_name)
print(response)
# Extract and print the access key information
access_key_id = response['AccessKey']['AccessKeyId']
secret_access_key = response['AccessKey']['SecretAccessKey']
cred = credential(access_key_id, secret_access_key)
print(f"Access Key ID: {access_key_id}")
print(f"Secret Access Key: {secret_access_key}")
return cred
def main():
client_map = dict()
client_map_new = dict()
# Replace 'your_aws_access_key' and 'your_aws_secret_key' with your AWS IAM user's access key and secret key.
aws_access_key_id = '<key_id>'
aws_secret_access_key = '<access_key>'
cred = credential(aws_access_key_id, aws_secret_access_key)
print(f'aws_access_key_id = ', cred.aws_access_key_id)
print(f'aws_secret_access_key = ', cred.aws_secret_access_key)
print(f'aws_session_token = ', cred.aws_session_token)
client_map = initialize_clients(client_map, cred)
get_caller_identity(client_map)
target_user_name = 'devOps'
cred_new = create_access_key(client_map, target_user_name)
# NOTE: manually put in the key id and access key created by the createAccessKey call above
#cred_new = credential('', '', None)
print(f'aws_access_key_id = ', cred_new.aws_access_key_id)
print(f'aws_secret_access_key = ', cred_new.aws_secret_access_key)
print(f'aws_session_token = ', cred_new.aws_session_token)
time.sleep(5)
client1 = boto3.client(
service_name = 'sts',
aws_access_key_id=cred_new.aws_access_key_id,
aws_secret_access_key=cred_new.aws_secret_access_key,
aws_session_token=cred.aws_session_token
)
print(client1.get_caller_identity())
if __name__ == "__main__":
main()
User access keys are not immediately active after their creation.
You do have a 5-second delay in your code, but it might not be enough.
What probably happens when you are testing manually, is that you create the access key, dump it to stdout, copy it from your terminal, paste into your code then run it again, which takes enough time for the key to become active. So, it looks like you just need a larger delay.
I'm not sure what your use case is, but you almost never need to create user tokens programmatically for anything else other than giving them to users.
If you want to do stuff with permissions other than your user's, create an IAM role and assume it. Tokens created by AssumeRole
become active instantly.