Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabled opt-in region gives AuthFailure #77

Open
iainelder opened this issue Oct 7, 2023 · 0 comments
Open

Enabled opt-in region gives AuthFailure #77

iainelder opened this issue Oct 7, 2023 · 0 comments

Comments

@iainelder
Copy link
Collaborator

iainelder commented Oct 7, 2023

Alexandre Alencar points out in issue 74 that Botocove can't access any opt-in region. The original issue got muddled so I'm restating the problem here with a simple repro so that I may fix it.

The target account's eu-central-1 region has opt-in status ENABLED_BY_DEFAULT and its eu-central-2 region has opt-in status ENABLED (was previously DISABLED). See Appendix 1 for how to query the opt-in status of the regions.

Use botocove to echo the region name given by the EC2.DescribeAvailabilityZones API.

from botocove import cove
from itertools import chain

response = cove(
    lambda s: (
        s.client("ec2").describe_availability_zones()
        ["AvailabilityZones"][0]["RegionName"]
    ),
    target_ids=["111111111111"],
    regions=["eu-central-1", "eu-central-2"]
)()

for result in chain(
            response["FailedAssumeRole"],
            response["Exceptions"],
            response["Results"],
        ):
    print(
        repr(
            {
                k: v
                for k, v in result.items()
                if k in {"Id", "Region", "Result", "ExceptionDetails"}
            }
        )
    )

Region eu-central-1 echoes its name and region eu-central-2 gives an AuthFailure error.

{'Id': '111111111111', 'Region': 'eu-central-2', 'ExceptionDetails': ClientError('An error occurred (AuthFailure) when calling the DescribeAvailabilityZones operation: AWS was not able to validate the provided access credentials')}
{'Id': '111111111111', 'Region': 'eu-central-1', 'Result': 'eu-central-1'}

The expected behavior is that region eu-central-2 also echo its name.

Appendix 1: Query region opt-in status

You can use the Account parameter of the Accounts.ListRegions API but you first need to enable trusted access in the organization. If you haven't done that you can instead use botocove to check the opt-in status of the target regions.

from botocove import cove

response = cove(
    lambda s: s.client("account").list_regions(), target_ids=["111111111111"]
)()

[
    r
    for r in response["Results"][0]["Result"]["Regions"]
    if r["RegionName"] in {"eu-central-1", "eu-central-2"}
]

The eu-central-1 region has opt-in status ENABLED_BY_DEFAULT, which means it is always enabled. The eu-central-2region has opt-in status ENABLED, which means it was DISABLED until I changed it.

[{'RegionName': 'eu-central-1', 'RegionOptStatus': 'ENABLED_BY_DEFAULT'},
 {'RegionName': 'eu-central-2', 'RegionOptStatus': 'ENABLED'}]
iainelder added a commit to iainelder/botocove that referenced this issue Oct 31, 2023
Initialize the assuming session before initializing the clients.

Inline each client initialization. A little repeated structure here is easier
to read than the complex type signatures of the deleted helper functions.

In a future change the STS client will take extra parameters to support version
2 STS tokens and opt-in regions.

This paves the way to a solution for connelldave#77.
iainelder added a commit to iainelder/botocove that referenced this issue Oct 31, 2023
Initialize the assuming session before initializing the clients.

Inline each client initialization. A little repeated structure here is easier
to read than the complex type signatures of the deleted helper functions.

In a future change the STS client will take extra parameters to support version
2 STS tokens and opt-in regions.

This paves the way to a solution for connelldave#77.
connelldave pushed a commit that referenced this issue Nov 26, 2023
Initialize the assuming session before initializing the clients.

Inline each client initialization. A little repeated structure here is easier
to read than the complex type signatures of the deleted helper functions.

In a future change the STS client will take extra parameters to support version
2 STS tokens and opt-in regions.

This paves the way to a solution for #77.
iainelder added a commit to iainelder/botocove that referenced this issue Dec 29, 2023
Change the host account init to pass these tests:

* `test_when_no_default_region_then_cove_uses_assuming_session_region`
* `test_cove_prefers_assuming_session_region`

A side effect of the change is even if the caller doesn't specify a target
region then the cove result includes a `Region` key. (PR connelldave#79 shows how to avoid
that side effect, but it's simpler to accept it.)

Set the default region for all tests to allow me to test for that side effect.
A real user will always set the region from a profile or an environment
variable if one isn't passed explicitly to botocove.

The default region forces me to update the `test_regions` module. Without
setting a default region, the old test still passed!

* Old: `test_when_region_is_unspecified_then_result_has_no_region_key`
* New: `test_when_region_is_unspecified_then_result_has_default_region_key`

The default region makes a `Region` key appear in tests that check the whole
cove output instead of a single feature. Later I'll refactor these tests
because it's not clear what feature they cover.

The default region is `eu-west-1` and all region arguments use some other value
such as `eu-central-1` or `us-east-1`. This convention makes the tests easier
to read.

Use the `_no_default_region` fixture when you really need to test how cove
behaves without the default region.

Using the `_org_with_one_member` fixture and the `raise_exception=True`
parameter together make the tests easier to write because you can assume the
cove output has a single result and no exceptions. If any exception occurs, use
`pytest.raises` to detect it. Later I'll refactor more tests to use this
calling style. We can use dedicated test modules to cover the behavior of
`raise_exception=False` and of an organization with multiple accounts.

This paves the way to querying the opt-in regions in connelldave#77.
iainelder added a commit to iainelder/botocove that referenced this issue Dec 29, 2023
Change the host account init to pass these tests:

* `test_when_no_default_region_then_cove_uses_assuming_session_region`
* `test_cove_prefers_assuming_session_region`

A side effect of the change is even if the caller doesn't specify a target
region then the cove result includes a `Region` key. (PR connelldave#79 shows how to avoid
that side effect, but it's simpler to accept it.)

Set the default region for all tests to allow me to test for that side effect.
A real user will always set the region from a profile or an environment
variable if one isn't passed explicitly to botocove.

The default region forces me to update the `test_regions` module. Without
setting a default region, the old test still passed!

* Old: `test_when_region_is_unspecified_then_result_has_no_region_key`
* New: `test_when_region_is_unspecified_then_result_has_default_region_key`

The default region makes a `Region` key appear in tests that check the whole
cove output instead of a single feature. Later I'll refactor these tests
because it's not clear what feature they cover.

The default region is `eu-west-1` and all region arguments use some other value
such as `eu-central-1` or `us-east-1`. This convention makes the tests easier
to read.

Use the `_no_default_region` fixture when you really need to test how cove
behaves without the default region.

Using the `_org_with_one_member` fixture and the `raise_exception=True`
parameter together make the tests easier to write because you can assume the
cove output has a single result and no exceptions. If any exception occurs, use
`pytest.raises` to detect it. Later I'll refactor more tests to use this
calling style. We can use dedicated test modules to cover the behavior of
`raise_exception=False` and of an organization with multiple accounts.

This paves the way to querying the opt-in regions in connelldave#77.
connelldave pushed a commit that referenced this issue Jan 3, 2024
Change the host account init to pass these tests:

* `test_when_no_default_region_then_cove_uses_assuming_session_region`
* `test_cove_prefers_assuming_session_region`

A side effect of the change is even if the caller doesn't specify a target
region then the cove result includes a `Region` key. (PR #79 shows how to avoid
that side effect, but it's simpler to accept it.)

Set the default region for all tests to allow me to test for that side effect.
A real user will always set the region from a profile or an environment
variable if one isn't passed explicitly to botocove.

The default region forces me to update the `test_regions` module. Without
setting a default region, the old test still passed!

* Old: `test_when_region_is_unspecified_then_result_has_no_region_key`
* New: `test_when_region_is_unspecified_then_result_has_default_region_key`

The default region makes a `Region` key appear in tests that check the whole
cove output instead of a single feature. Later I'll refactor these tests
because it's not clear what feature they cover.

The default region is `eu-west-1` and all region arguments use some other value
such as `eu-central-1` or `us-east-1`. This convention makes the tests easier
to read.

Use the `_no_default_region` fixture when you really need to test how cove
behaves without the default region.

Using the `_org_with_one_member` fixture and the `raise_exception=True`
parameter together make the tests easier to write because you can assume the
cove output has a single result and no exceptions. If any exception occurs, use
`pytest.raises` to detect it. Later I'll refactor more tests to use this
calling style. We can use dedicated test modules to cover the behavior of
`raise_exception=False` and of an organization with multiple accounts.

This paves the way to querying the opt-in regions in #77.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant