使用Boto3 createAccessKey生成的凭证调用API失败问题排查
问题描述
我要写一个Python程序,流程是:用用户A的凭证调用部分API → 为用户B创建访问密钥 → 用新生成的密钥调用GetCallerIdentity API。但直接用createAccessKey返回的密钥时,一直收到错误:
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.
但如果手动把createAccessKey生成的密钥硬编码到程序里(取消下面代码注释并填入密钥),程序就能正常运行:
# NOTE: manually put in the key id and access key created by the createAccessKey call above #cred_new = credential('', '', None)
完整程序代码:
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()
问题原因
你通过create_access_key生成的是IAM用户的长期访问密钥,这类密钥不需要会话令牌(aws_session_token)。但创建client1时,你错误传入了用户A的cred.aws_session_token,导致请求携带了不属于用户B的无效令牌,触发InvalidClientTokenId错误。
手动硬编码时,你显式传入None作为会话令牌,boto3不会在请求中添加令牌参数,所以请求合法。
修复方案
修改创建client1的代码,要么去掉aws_session_token参数,要么传入cred_new.aws_session_token(它本身就是None):
方案1:移除多余参数
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 )
方案2:复用已有函数(更规范)
直接用你写的initialize_each_service函数创建客户端,避免手动拼接参数出错:
client1 = initialize_each_service(cred_new, 'sts')
额外提示
- 不需要
time.sleep(5),IAM访问密钥创建后立即生效,等待毫无必要。
内容的提问来源于stack exchange,提问作者drdot
相关产品推荐
相关产品推荐

