mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-05-06 08:47:18 +00:00
fix(aws): get organization's metadata with assumed role (#10894)
This commit is contained in:
@@ -15,6 +15,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
### 🐞 Fixed
|
||||
|
||||
- Alibaba Cloud CS service SDK compatibility, harden other services and improve documentation [(#10871)](https://github.com/prowler-cloud/prowler/pull/10871)
|
||||
- AWS Organizations metadata retrieval for delegated administrator scans by using the assumed role session instead of the pre-assume credentials [(#10894)](https://github.com/prowler-cloud/prowler/pull/10894)
|
||||
- `admincenter_groups_not_public_visibility` check for M365 provider evaluating Security and Distribution groups, now restricted to Microsoft 365 (Unified) groups per CIS M365 Foundations 1.2.1 [(#10899)](https://github.com/prowler-cloud/prowler/pull/10899)
|
||||
- Google Workspace check reports now store the actual domain or account resource subject instead of `provider.identity` [(#10901)](https://github.com/prowler-cloud/prowler/pull/10901)
|
||||
|
||||
|
||||
@@ -318,8 +318,16 @@ class AwsProvider(Provider):
|
||||
########
|
||||
|
||||
######## AWS Organizations Metadata
|
||||
# This is needed in the case we don't assume an AWS Organizations IAM Role
|
||||
aws_organizations_session = self._session.original_session
|
||||
# Default to the current (post-assume) session so DescribeAccount runs
|
||||
# with the same identity that performs the scan. This makes delegated
|
||||
# administrator scenarios work without extra configuration: when the
|
||||
# scan role itself sits in the management or delegated admin account,
|
||||
# it already holds the Organizations permissions needed. The
|
||||
# management-account -> member-account flow is handled by the
|
||||
# original-session fallback below. Use `organizations_role_arn` to
|
||||
# override when Organizations lives in a different account than both
|
||||
# the scan role and the original credentials.
|
||||
aws_organizations_session = self._session.current_session
|
||||
# Get a new session if the organizations_role_arn is set
|
||||
if organizations_role_arn:
|
||||
# Validate the input role
|
||||
@@ -364,6 +372,28 @@ class AwsProvider(Provider):
|
||||
self._organizations_metadata = self.get_organizations_info(
|
||||
aws_organizations_session, self._identity.account
|
||||
)
|
||||
|
||||
# Fallback to the original (pre-assume) session when no explicit
|
||||
# organizations_role_arn is set and the current session could not
|
||||
# retrieve Organizations metadata. This preserves the
|
||||
# management-account -> member-account flow, where DescribeAccount is
|
||||
# only allowed from the management account or a delegated
|
||||
# administrator and the assumed member-account session has no
|
||||
# Organizations permissions.
|
||||
if (
|
||||
not organizations_role_arn
|
||||
and self._session.current_session is not self._session.original_session
|
||||
and (
|
||||
self._organizations_metadata is None
|
||||
or not self._organizations_metadata.organization_id
|
||||
)
|
||||
):
|
||||
logger.info(
|
||||
"Retrying AWS Organizations metadata retrieval with the original session"
|
||||
)
|
||||
self._organizations_metadata = self.get_organizations_info(
|
||||
self._session.original_session, self._identity.account
|
||||
)
|
||||
########
|
||||
|
||||
# Get Enabled Regions
|
||||
|
||||
@@ -455,6 +455,55 @@ class TestAWSProvider:
|
||||
aws_provider.organizations_metadata.organization_arn == organization["Arn"]
|
||||
)
|
||||
|
||||
@mock_aws
|
||||
def test_aws_provider_organizations_uses_assumed_role_session_by_default(self):
|
||||
# Regression test for issue #10215.
|
||||
# When only `role_arn` is provided (no `organizations_role_arn`),
|
||||
# the FIRST attempt to fetch Organizations metadata must use the
|
||||
# assumed role session (current_session), not the pre-assume
|
||||
# credentials. This mirrors the CLI: `aws sts assume-role` followed
|
||||
# by `aws organizations describe-account` uses the assumed identity.
|
||||
role_arn = create_role(AWS_REGION_EU_WEST_1)
|
||||
|
||||
captured_sessions = []
|
||||
original_get_organizations_info = AwsProvider.get_organizations_info
|
||||
|
||||
def capture(self, organizations_session, aws_account_id):
|
||||
captured_sessions.append(organizations_session)
|
||||
return original_get_organizations_info(
|
||||
self, organizations_session, aws_account_id
|
||||
)
|
||||
|
||||
with patch.object(AwsProvider, "get_organizations_info", capture):
|
||||
aws_provider = AwsProvider(role_arn=role_arn, session_duration=900)
|
||||
|
||||
assert captured_sessions[0] is aws_provider.session.current_session
|
||||
assert captured_sessions[0] is not aws_provider.session.original_session
|
||||
|
||||
@mock_aws
|
||||
def test_aws_provider_organizations_falls_back_to_original_session(self):
|
||||
# When `role_arn` is provided and the assumed role session cannot
|
||||
# retrieve Organizations metadata (e.g. management-account ->
|
||||
# member-account flow where the member account has no Organizations
|
||||
# permissions), retry with the original (pre-assume) session.
|
||||
role_arn = create_role(AWS_REGION_EU_WEST_1)
|
||||
|
||||
captured_sessions = []
|
||||
original_get_organizations_info = AwsProvider.get_organizations_info
|
||||
|
||||
def capture(self, organizations_session, aws_account_id):
|
||||
captured_sessions.append(organizations_session)
|
||||
return original_get_organizations_info(
|
||||
self, organizations_session, aws_account_id
|
||||
)
|
||||
|
||||
with patch.object(AwsProvider, "get_organizations_info", capture):
|
||||
aws_provider = AwsProvider(role_arn=role_arn, session_duration=900)
|
||||
|
||||
assert len(captured_sessions) == 2
|
||||
assert captured_sessions[0] is aws_provider.session.current_session
|
||||
assert captured_sessions[1] is aws_provider.session.original_session
|
||||
|
||||
@mock_aws
|
||||
def test_aws_provider_session_with_mfa(self):
|
||||
mfa = True
|
||||
|
||||
Reference in New Issue
Block a user