How to identify disabled regions in AWS?

Question:

AWS regularly add new regions. While “old” regions are enabled by default in every AWS account, new regions are disabled by default 1.

I’m trying to scan a particular resource in all available regions using the following Python (pseudo)code:

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)

However, this fails with a cryptic An error occurred (InvalidClientTokenId) when calling the DescribeDBInstances operation: The security token included in the request is invalid when accessing a “new” region.

Other services fail with other errors: e.g. Lambda fails with An error occurred (UnrecognizedClientException) when calling the ListFunctions operation: The security token included in the request is invalid

How can I identify if a region is enabled or not? There does not seem to be an API call to do this…

Asked By: Niobos

||

Answers:

I found an edge case of the API that can be (ab)used to identify enabled regions: The ec2:DescribeRegions API call (and probably others as well, haven’t tried) exhibit a slightly different failure mode in disabled regions:

  • Either the call succeeds, and you know the region is enabled

  • The call fails with an UnauthorizedOperation error. This indicates you don’t have IAM permissions, but the region is enabled

  • The call fails with AuthFailure. This indicates the region is disabled

The following code successfully filters regions in my test cases:

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
Answered By: Niobos

I worked a bit more on the problem, and found a way that relies less on edge case behaviour: Using the sts:GetCallerIdentity call.

This has several advantages over ec2:DescribeRegions in that the API is always enabled (can’t be restricted by IAM). You can disable STS for a region, but even then, GetCallerIdentity still works (only issueing of temporary credentials is disabled 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
Answered By: Niobos

We can use account client to filter all the enabled disabled regions:

account_client = boto_session.client("account")
response = account_client.list_regions(RegionOptStatusContains=['ENABLED', 'ENABLED_BY_DEFAULT'])
print ([x["RegionName"] for x in response["Regions"]])

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/account/client/list_regions.html

Answered By: Kirandeep Singh
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.