升级boto库后调用CloudTrail的describe_trails遇UnrecognizedClientException
根据你的描述,升级boto3(1.9.44→1.14.45)和botocore(1.12.44→1.17.45)后调用describe_trails出现UnrecognizedClientException,但旧版本正常且权限配置正确,最可能的原因是新版本返回的CloudTrail可用区域列表中包含了你的AWS账户未启用的区域,导致调用这些区域的接口时触发凭证无效错误。
具体原因解释
在旧版本的botocore(1.12.x)中,get_available_regions('cloudtrail')返回的区域数量较少,仅包含AWS早期推出的成熟区域。而升级到botocore 1.17.x后,该函数会返回更多新增的AWS区域(比如af-south-1、ap-east-1、eu-south-1等)。如果你的AWS账户尚未启用这些新增区域,调用对应区域的CloudTrail客户端时,AWS会返回UnrecognizedClientException——因为账户在该区域未激活,凭证无法被识别。
验证方法
你可以先打印get_region_list()返回的区域列表,对比新旧版本的差异:
print(get_region_list())
然后逐个测试这些区域的客户端,定位到具体报错的区域:
region_list = get_region_list() access_key = "your_access_key" secret_key = "your_secret_key" for region in region_list: try: client = boto3.client( 'cloudtrail', aws_access_key_id=access_key, aws_secret_access_key=secret_key, region_name=region ) print(f"Success for region: {region}") print(client.describe_trails()) except Exception as e: print(f"Error for region: {region} - {str(e)}")
解决方案
针对这个问题,你可以采用以下两种方式解决:
1. 启用报错的AWS区域
登录AWS控制台,进入我的账户 > 区域设置,找到报错的区域并启用。等待几分钟后,再次运行代码即可正常访问这些区域的CloudTrail服务。
2. 过滤掉未启用的区域
如果不需要访问所有区域,可以在代码中过滤掉账户未启用的区域。你可以通过调用ec2:DescribeRegions API来获取账户已启用的区域,然后只生成这些区域的CloudTrail客户端:
def get_enabled_regions(access_key, secret_key): """获取账户已启用的AWS区域列表""" ec2_client = boto3.client( 'ec2', aws_access_key_id=access_key, aws_secret_access_key=secret_key, region_name='us-east-1' # 主区域,用于查询已启用区域 ) response = ec2_client.describe_regions() return [region['RegionName'] for region in response['Regions']] def generate_cloudtrail_clients(access_key, secret_key): """只针对已启用的区域生成CloudTrail客户端""" enabled_regions = get_enabled_regions(access_key, secret_key) # 过滤出CloudTrail支持的已启用区域 cloudtrail_regions = [r for r in enabled_regions if r in get_region_list()] for region in cloudtrail_regions: yield boto3.client( 'cloudtrail', aws_access_key_id=access_key, aws_secret_access_key=secret_key, region_name=region ) # 使用新的客户端生成函数 clients = generate_cloudtrail_clients(access_key, secret_key) for client in clients: print(client.describe_trails())
其他可能的排查方向
如果上述解决方案无效,还可以检查以下几点:
- 确认你的
access_key和secret_key没有拼写错误,且未过期(如果是临时凭证,还需传入aws_session_token)。 - 检查是否有其他凭证源(比如环境变量
AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY,或者~/.aws/credentials文件)覆盖了你显式传入的凭证——新版本botocore的凭证链优先级可能有细微调整,但显式传入的凭证应该优先于其他源。
内容的提问来源于stack exchange,提问作者user2013904

