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

Multi-Account support - IAM Client #6284

Closed
coraliz opened this issue May 4, 2023 · 3 comments
Closed

Multi-Account support - IAM Client #6284

coraliz opened this issue May 4, 2023 · 3 comments
Labels

Comments

@coraliz
Copy link

coraliz commented May 4, 2023

Hi,
Moto 4.1.8 (installed it through poetry).

I'm trying to run a test with multi account support.
I assume a mocked role from the account i want to use. When using only RDS & EC2 Clients the resources created are using the assumed role's account ID. When adding an IAM client which is using the same session, RDS, EC2 & IAM clients go back to default account.

Attaching sample code

##SETUP 
from typing import Iterator
import boto3
import pytest
from moto import mock_sts, mock_iam, mock_rds, mock_s3, mock_ec2
from mypy_boto3_ec2 import EC2Client
from mypy_boto3_rds import RDSClient
from mypy_boto3_s3 import S3Client

@pytest.fixture
def session() -> boto3.Session:
    with mock_sts():
        sts_client = boto3.client("sts", "us-east-1")

        response = sts_client.assume_role(
            RoleArn=f"arn:aws:iam::1111111111:role/my_role", RoleSessionName="test"
        )
        yield boto3.Session(
            aws_access_key_id=response["Credentials"]["AccessKeyId"],
            aws_secret_access_key=response["Credentials"]["SecretAccessKey"],
            aws_session_token=response["Credentials"]["SessionToken"],
            region_name="us-east-1",
        )


@pytest.fixture
def moto_rds(session) -> RDSClient:
    with mock_rds():
        rds_client = session.client("rds")
        yield rds_client


@pytest.fixture
def moto_iam(session):
    with mock_iam():
        iam_client = session.client("iam")
        yield iam_client


@pytest.fixture
def moto_ec2(session: boto3.Session) -> Iterator[EC2Client]:
    with mock_ec2():
        client = session.client("ec2")
        yield client

when I call the test this way I get the correct account id inside the ARN :

def test_me(moto_rds: RDSClient, moto_ec2: EC2Client):
    # RDS TEST
    resp = moto_rds.create_db_instance(
        DBInstanceIdentifier="my-rds-instance",
        DBInstanceClass="db.t2.micro",
        Engine="mysql",
    )
    assert "arn:aws:rds:us-east-1:1111111111:db:my-rds-instance" == resp["DBInstance"]["DBInstanceArn"]

    #EC2 TEST
    image_id = moto_ec2.describe_images()["Images"][0]["ImageId"]  # Any ImageID would suffice
    response = moto_ec2.run_instances(
        ImageId=image_id,
        MinCount=1,
        MaxCount=1,

    )
    account_id = response["OwnerId"]
    assert account_id == '1111111111'

BUT when I call it with the mocked iam client, unfortunately, the account id changes. (Notice just calling the moto_iam fixture not even using it.)

def test_me(moto_iam, moto_rds: RDSClient, moto_ec2: EC2Client):
    # RDS TEST
    resp = moto_rds.create_db_instance(
        DBInstanceIdentifier="my-rds-instance",
        DBInstanceClass="db.t2.micro",
        Engine="mysql",
    )
    assert "arn:aws:rds:us-east-1:1111111111:db:my-rds-instance" == resp["DBInstance"]["DBInstanceArn"]

->'arn:aws:iam::123456789012:role/my-role-ScannerRole-' != 'arn:aws:iam::1111111111:role/my-role-ScannerRole-'

Thanks in advance
Coral

@bblommers
Copy link
Collaborator

Hi @coraliz, that's a bug indeed - thanks for raising this.

To give some context: when starting a mock, Moto will delete all existing data. This ensures that there is no data leakage from previous tests.

In this test, that means that the following happens:

  1. The moto_iam(session)-fixture is invoked - that in turn invokes the session()-fixture
  2. session() starts the STS mock (and any STS data is removed)
  3. assume_role creates a temporary IAM key
  4. moto_iam then starts the IAM mock, and deletes all IAM data - including the temp key that was just created

At the end, when create_db_instance is invoked, it is invoked with an unknown AccessKey, so Moto will fall-back to the default account ID 123456789012


One workaround would be to start the IAM mock as part of the session()-fixture:

@pytest.fixture
def session() -> boto3.Session:
    print("called session")
    with mock_sts():
        with mock_iam():
            sts_client = boto3.client("sts", "us-east-1")

            ...

That means that the moto_iam-fixture no longer needs to start the mock:

@pytest.fixture
def moto_iam(session):
    iam_client = boto3.client("iam")
    yield iam_client

@bblommers bblommers added the bug label May 8, 2023
@bblommers
Copy link
Collaborator

Hi @coraliz, this should be fixed in the upcoming v5 release.

We've just released an alpha version to gather some early feedback, moto==5.0.0alpha1. Are you able to verify that this version fixes your issue?

Note that there are breaking changes in this release: all service-specific decorators have been replaced with a single @mock_aws decorator.
See the full release announcement here: #7198

@bblommers
Copy link
Collaborator

Moto V5 has now been released with a fix for this bug, so I'll close this.

Release: https://pypi.org/project/moto/5.0.0/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants