Skip to content

Conversation

@viren-nadkarni
Copy link
Member

@viren-nadkarni viren-nadkarni commented Nov 2, 2023

Motivation

This PR fixes multi-account/multi-region region functionality that misbehave in non-default region and accounts.

In effect, fixes following tests:

  • tests.aws.services.sqs.test_sqs.TestSqsQueryApi
    • test_get_queue_attributes_works_without_authparams
    • test_get_queue_url_works_for_same_queue[standard]
    • test_get_queue_url_works_for_same_queue[domain]
    • test_get_queue_url_works_for_same_queue[path]
    • test_get_queue_url_work_for_different_queue[standard]
    • test_get_queue_url_work_for_different_queue[domain]
    • test_get_queue_url_work_for_different_queue[path]
  • tests.aws.services.sqs.test_sqs.TestSQSMultiAccounts
    • test_cross_account_get_queue_url[standard]
    • test_cross_account_get_queue_url[domain]
    • test_cross_account_get_queue_url[path]
  • tests.aws.services.stepfunctions.legacy.test_stepfunctions_legacy
    • test_default_logging_configuration
  • tests.aws.services.dynamodb.test_dynamodb.TestDynamoDB
    • test_stream_spec_and_region_replacement
  • tests.aws.services.logs.test_logs.TestCloudWatchLogs
    • test_put_subscription_filter_lambda
    • test_put_subscription_filter_firehose
    • test_put_subscription_filter_kinesis
  • tests.aws.services.sqs.test_sqs_backdoor.TestSqsDeveloperEndpoints
    • test_list_messages_with_invisible_messages[standard]
    • test_list_messages_with_invisible_messages[domain]
    • test_list_messages_with_invisible_messages[path]
    • test_list_messages_with_delayed_messages[standard]
    • test_list_messages_with_delayed_messages[domain]
    • test_list_messages_with_delayed_messages[path]
  • tests.aws.services.s3.test_s3.TestS3MultiAccounts
    • test_shared_bucket_namespace
    • test_cross_account_access

@viren-nadkarni viren-nadkarni self-assigned this Nov 2, 2023
@viren-nadkarni viren-nadkarni changed the title Fix xaccount test Fix internal clients not using proper credentials Nov 2, 2023
@viren-nadkarni viren-nadkarni added the semver: patch Non-breaking changes which can be included in patch releases label Nov 2, 2023

# create target S3 bucket
aws_client.s3.create_bucket(Bucket=bucket_name)
s3_create_bucket(Bucket=bucket_name)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using this fixture ensures the the appropriate LocationConstraint is added automatically.

Comment on lines +95 to +96
monkeypatch.setattr(config, "SQS_ENDPOINT_STRATEGY", strategy)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parametrized value for SQS endpoint strategy was not being taken into account.

Comment on lines 290 to 292
Principal=f"logs.{TEST_AWS_REGION_NAME}.amazonaws.com",
Action="lambda:InvokeFunction",
SourceArn=f"arn:aws:logs:{config.AWS_REGION_US_EAST_1}:{account_id}:log-group:{logs_log_group}:*",
SourceArn=f"arn:aws:logs:{TEST_AWS_REGION_NAME}:{account_id}:log-group:{logs_log_group}:*",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assertions expected the us-east-1 region even when the resources were created in a different region (by setting TEST_AWS_REGION_NAME)

@coveralls
Copy link

coveralls commented Nov 2, 2023

Coverage Status

coverage: 83.985% (-0.02%) from 84.009%
when pulling 17c34bd on fix-xaccount-test
into d099d08 on master.

@github-actions
Copy link

github-actions bot commented Nov 2, 2023

LocalStack Community integration with Pro

       2 files         2 suites   1h 4m 27s ⏱️
2 328 tests 2 029 ✔️ 299 💤 0
2 329 runs  2 029 ✔️ 300 💤 0

Results for commit 17c34bd.

♻️ This comment has been updated with latest results.

@viren-nadkarni viren-nadkarni changed the title Fix internal clients not using proper credentials Fix broken multi-account/multi-region functionality Nov 3, 2023
client = connect_to().firehose
client = connect_to(
aws_access_key_id=arn_data["account"], region_name=arn_data["region"]
).firehose
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensures logs are sent to correct account and region.

Identified in following tests:

  • test_put_subscription_filter_lambda
  • test_put_subscription_filter_firehose
  • test_put_subscription_filter_kinesis


# assert ARN formats
expected_arn_prefix = "arn:aws:dynamodb:" + aws_stack.get_local_region()
expected_arn_prefix = "arn:aws:dynamodb:" + TEST_AWS_REGION_NAME
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensures expected value is correctly constructed.

Fixes this test: test_stream_spec_and_region_replacement

assert result["ResponseMetadata"]["HTTPStatusCode"] == 200
assert result["loggingConfiguration"] == {"level": "OFF", "includeExecutionData": False}
finally:
custom_client.stepfunctions.delete_state_machine(stateMachineArn=result["stateMachineArn"])
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test did not use custom_client to create the statemachine and then failed during retrieval using this client.

Affected test: test_default_logging_configuration

queue_url = sqs_create_queue(QueueName=queue_name)
account_id, region_name, queue_name_from_url = parse_queue_url(queue_url)
assert account_id == DEFAULT_AWS_ACCOUNT_ID
assert account_id == TEST_AWS_ACCOUNT_ID
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assertion was done against the wrong account

@viren-nadkarni viren-nadkarni marked this pull request as ready for review November 3, 2023 08:53
@viren-nadkarni viren-nadkarni requested review from sannya-singal and removed request for MEPalma, baermat, bentsku, giograno, silv-io and steffyP November 3, 2023 08:54
Copy link
Contributor

@bentsku bentsku left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice changes! I have some comments regarding the lambda changes, I'd also like the opinion of @dfangl (for IAM, maybe future?) or maybe a lambda service owner, but I believe we should use the ARN there. Good catch for the S3 buckets as well, more cleanups! 🧹

What about the default region changes? I believe some of the test logic was always expecting us-east-1 to be the default, especially for S3, and snapshots might need to be regenerated.

Comment on lines 345 to 358
if ":lambda:" in destination_arn:
client = connect_to(region_name=extract_region_from_arn(destination_arn)).lambda_
client = connect_to(
aws_access_key_id=arn_data["account"], region_name=arn_data["region"]
).lambda_
lambda_name = arns.lambda_function_name(destination_arn)
client.invoke(FunctionName=lambda_name, Payload=json.dumps(event))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as commented above, I believe we shouldn't extract the lambda function name but use the ARN to invoke the function:

client = connect_to(region_name=extract_region_from_arn(destination_arn)).lambda_
client.invoke(FunctionName=destination_arn, Payload=json.dumps(event))

@viren-nadkarni viren-nadkarni requested a review from dfangl November 3, 2023 11:30
@dfangl
Copy link
Member

dfangl commented Nov 7, 2023

Thanks for the tag @bentsku ! You are right, for cross account/region requests which are done on behalf of the service, we should definitely work on having the proper account just in the request body as the target resource, and use the request metadata to set the service name, instead of setting the account id as access key id. If we do the latter, IAM for example would not detect it as a cross-account request, as the originating account is the same as the targets. Ideally, all services extract the account id from the arn if provided, to access the correct account.

@viren-nadkarni viren-nadkarni marked this pull request as draft November 9, 2023 09:22
@viren-nadkarni viren-nadkarni added this to the Playground milestone Nov 10, 2023
@viren-nadkarni viren-nadkarni marked this pull request as ready for review November 14, 2023 10:21
@viren-nadkarni viren-nadkarni requested review from bentsku and removed request for sannya-singal November 14, 2023 10:22
Copy link
Contributor

@bentsku bentsku left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! This is looking great! thanks for addressing the comments! There's just this part with the role and with_assumed_role and the else part which I'm not sure I understand the intricacies, but the rest is all good to me!

There's just 2 S3 tests that are not cleaning up due to the use of localstack.utils.aws.resources.create_s3_bucket now. Maybe we could add its cleanup to the cleanups fixture.

Thanks a lot again for all of these fixes! 🚀

Comment on lines +260 to +261
else:
factory = connect_to(aws_access_key_id=arn_data["account"], region_name=arn_data["region"])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q: is this a fallback? this whole with_assumed_role addition is looking really nice 😄 I lack some knowledge in the IAM part, so this kind of things I don't feel qualified enough to review.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're correct, if a role ARN is available, IAM enforcement can be performed. Else there is a fallback.

This usage is similar to elsewhere, eg:

if role_arn := subscriber.get("SubscriptionRoleArn"):
factory = connect_to.with_assumed_role(
role_arn=role_arn, service_principal=ServicePrincipal.sns, region_name=region
)
else:
account_id = extract_account_id_from_arn(subscriber["Endpoint"])
factory = connect_to(aws_access_key_id=account_id, region_name=region)

or

if role_arn := s3_destination_description.get("RoleARN"):
factory = connect_to.with_assumed_role(
role_arn=role_arn, service_principal=ServicePrincipal.firehose
)
else:
factory = connect_to()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IAM enforcement can be performed in both cases. However, only if the aws_access_key_id is set to the INTERNAL_AWS_ACCESS_KEY_ID value. There should be no case, other than resource creation, to set the account id as access key id for internal clients, in my opinion. The first snippet by viren for example leads to no IAM enforcement in the else case, which is neither parity nor should happen.

@viren-nadkarni viren-nadkarni merged commit 177773b into master Nov 20, 2023
@viren-nadkarni viren-nadkarni deleted the fix-xaccount-test branch November 20, 2023 12:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

semver: patch Non-breaking changes which can be included in patch releases

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants