如何识别 AWS 中的禁用区域?

How to identify disabled regions in AWS?

AWS 会定期添加新区域。虽然 "old" 个区域在每个 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)

但是,当访问 "new" 区域时,这会失败并显示一个神秘的 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 调用来执行此操作...

我发现了 API 的边缘情况,可以(滥用)用于识别启用的区域:ec2:DescribeRegions API 调用(可能还有其他调用,没有) t tried) 在禁用区域中表现出略微不同的故障模式:

  • 要么调用成功,你知道该区域已启用

  • 调用失败并出现 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

我在这个问题上做了更多工作,找到了一种较少依赖边缘情况行为的方法:使用 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