AWS会定期添加新区域。默认情况下,每个AWS账户中都会启用“旧”区域,而默认情况下,1会禁用新区域。
我正在尝试使用以下Python(伪)代码扫描所有可用区域中的特定资源:
regions = boto3_session.get_available_regions('rds')
for region in regions:
boto_rds_client = boto3_session.client('rds', region_name=region)
r_paginator = boto_rds_client.get_paginator('describe_db_instances')
for rdses in r_paginator.paginate():
for rds in rdses['DBInstances']:
do_stuff(rds)
但是,当访问“新”区域时,此操作失败,并显示了一个神秘的An error occurred (InvalidClientTokenId) when calling the DescribeDBInstances operation: The security token included in the request is invalid
。
其他服务因其他错误而失败:例如Lambda失败,An error occurred (UnrecognizedClientException) when calling the ListFunctions operation: The security token included in the request is invalid
如何识别区域是否启用?似乎没有API调用可以执行此操作...
答案 0 :(得分:1)
我发现该API的一种极端情况是可以(滥用)来标识启用的区域:ec2:DescribeRegions API调用(可能还有其他未曾尝试过)在禁用区域中表现出略有不同的故障模式:
呼叫成功,您就会知道该区域已启用
呼叫失败,并显示UnauthorizedOperation
错误。这表明您没有IAM权限,但是该区域已启用
呼叫失败,AuthFailure
。这表明该区域已禁用
以下代码成功过滤了我的测试用例中的区域:
def get_enabled_regions(boto3_session: boto3.Session, service: str) -> typing.Set[str]:
regions = boto3_session.get_available_regions(service)
enabled_regions = set()
for region in regions:
ec2_client = boto3_session.client('ec2', region_name=region)
try:
ec2_client.describe_regions()
except botocore.exceptions.ClientError as e:
if e.response['Error']['Code'] == "AuthFailure":
print(f"region {region} seems disabled, skipping")
continue # Account is disabled
elif e.response['Error']['Code'] == "UnauthorizedOperation":
print(f"region {region} seems enabled (but not sure)")
pass # Access denied is good: we have access to the region, just not to the ec2:DescribeRegions call
else:
raise
enabled_regions.add(region)
return enabled_regions
答案 1 :(得分:0)
我在这个问题上做了更多的工作,发现了一种较少依赖边缘情况的方式:使用sts:GetCallerIdentity
调用。
与ec2:DescribeRegions
相比,它具有多个优点,因为该API始终处于启用状态(不受IAM限制)。您可以为某个区域禁用STS,但是即使这样,GetCallerIdentity仍然可以工作(仅禁用1临时证书的颁发)。
def get_enabled_regions(boto3_session: boto3.Session, service: str) -> typing.Set[str]:
regions = boto3_session.get_available_regions(service)
enabled_regions = set()
for region in regions:
sts_client = boto3_session.client('sts', region_name=region)
try:
sts_client.get_caller_identity()
enabled_regions.add(region)
except botocore.exceptions.ClientError as e:
if e.response['Error']['Code'] == "InvalidClientTokenId":
# error code received when region is disabled
print(f"region {region} is disabled")
pass
else:
raise
return enabled_regions