fix(iam): check always if root credentials are present (#8013)

Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
This commit is contained in:
Prowler BotandAndoni Alonso authored and GitHub committed 2025-06-13 17:20:12 +08:00
1 parent ddd3a292f8
commit fc4536dca8
10 files changed
+756 -113

No files matched your search

@@ -33,11 +33,13 @@ class Test_iam_no_root_access_key_test:
service_client.credential_report[0][
"arn"
] = "arn:aws:iam::123456789012:user/<root_account>"
service_client.credential_report[0]["password_enabled"] = "true"
service_client.credential_report[0]["access_key_1_active"] = "false"
service_client.credential_report[0]["access_key_2_active"] = "false"
check = iam_no_root_access_key()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
@@ -75,11 +77,13 @@ class Test_iam_no_root_access_key_test:
service_client.credential_report[0][
"arn"
] = "arn:aws:iam::123456789012:user/<root_account>"
service_client.credential_report[0]["password_enabled"] = "true"
service_client.credential_report[0]["access_key_1_active"] = "true"
service_client.credential_report[0]["access_key_2_active"] = "false"
check = iam_no_root_access_key()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
@@ -117,11 +121,13 @@ class Test_iam_no_root_access_key_test:
service_client.credential_report[0][
"arn"
] = "arn:aws:iam::123456789012:user/<root_account>"
service_client.credential_report[0]["password_enabled"] = "false"
service_client.credential_report[0]["access_key_1_active"] = "false"
service_client.credential_report[0]["access_key_2_active"] = "true"
check = iam_no_root_access_key()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
@@ -159,11 +165,13 @@ class Test_iam_no_root_access_key_test:
service_client.credential_report[0][
"arn"
] = "arn:aws:iam::123456789012:user/<root_account>"
service_client.credential_report[0]["password_enabled"] = "false"
service_client.credential_report[0]["access_key_1_active"] = "true"
service_client.credential_report[0]["access_key_2_active"] = "true"
check = iam_no_root_access_key()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
@@ -174,3 +182,179 @@ class Test_iam_no_root_access_key_test:
result[0].resource_arn
== "arn:aws:iam::123456789012:user/<root_account>"
)
@mock_aws
def test_root_no_credentials(self):
iam_client = client("iam")
user = "test"
iam_client.create_user(UserName=user)["User"]["Arn"]
from prowler.providers.aws.services.iam.iam_service import IAM
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
):
with mock.patch(
"prowler.providers.aws.services.iam.iam_no_root_access_key.iam_no_root_access_key.iam_client",
new=IAM(aws_provider),
) as service_client:
from prowler.providers.aws.services.iam.iam_no_root_access_key.iam_no_root_access_key import (
iam_no_root_access_key,
)
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0][
"arn"
] = "arn:aws:iam::123456789012:user/<root_account>"
service_client.credential_report[0]["password_enabled"] = "false"
service_client.credential_report[0]["access_key_1_active"] = "false"
service_client.credential_report[0]["access_key_2_active"] = "false"
check = iam_no_root_access_key()
result = check.execute()
# Should return no findings since root has no credentials
assert len(result) == 0
@mock_aws
def test_root_no_access_keys_with_organizational_management_enabled(self):
iam_client = client("iam")
user = "test"
iam_client.create_user(UserName=user)["User"]["Arn"]
from prowler.providers.aws.services.iam.iam_service import IAM
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
):
with mock.patch(
"prowler.providers.aws.services.iam.iam_no_root_access_key.iam_no_root_access_key.iam_client",
new=IAM(aws_provider),
) as service_client:
from prowler.providers.aws.services.iam.iam_no_root_access_key.iam_no_root_access_key import (
iam_no_root_access_key,
)
# Set up organizational root management
service_client.organization_features = ["RootCredentialsManagement"]
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0][
"arn"
] = "arn:aws:iam::123456789012:user/<root_account>"
service_client.credential_report[0]["password_enabled"] = "true"
service_client.credential_report[0]["access_key_1_active"] = "false"
service_client.credential_report[0]["access_key_2_active"] = "false"
check = iam_no_root_access_key()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== "Root account has password configured but no access keys. Consider removing individual root credentials since organizational root management is active."
)
assert result[0].resource_id == "<root_account>"
assert (
result[0].resource_arn
== "arn:aws:iam::123456789012:user/<root_account>"
)
@mock_aws
def test_root_access_keys_with_organizational_management_enabled(self):
iam_client = client("iam")
user = "test"
iam_client.create_user(UserName=user)["User"]["Arn"]
from prowler.providers.aws.services.iam.iam_service import IAM
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
):
with mock.patch(
"prowler.providers.aws.services.iam.iam_no_root_access_key.iam_no_root_access_key.iam_client",
new=IAM(aws_provider),
) as service_client:
from prowler.providers.aws.services.iam.iam_no_root_access_key.iam_no_root_access_key import (
iam_no_root_access_key,
)
# Set up organizational root management
service_client.organization_features = ["RootCredentialsManagement"]
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0][
"arn"
] = "arn:aws:iam::123456789012:user/<root_account>"
service_client.credential_report[0]["password_enabled"] = "true"
service_client.credential_report[0]["access_key_1_active"] = "true"
service_client.credential_report[0]["access_key_2_active"] = "false"
check = iam_no_root_access_key()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "Root account has one active access key despite organizational root management being enabled."
)
assert result[0].resource_id == "<root_account>"
assert (
result[0].resource_arn
== "arn:aws:iam::123456789012:user/<root_account>"
)
@mock_aws
def test_root_both_access_keys_with_organizational_management_enabled(self):
iam_client = client("iam")
user = "test"
iam_client.create_user(UserName=user)["User"]["Arn"]
from prowler.providers.aws.services.iam.iam_service import IAM
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
):
with mock.patch(
"prowler.providers.aws.services.iam.iam_no_root_access_key.iam_no_root_access_key.iam_client",
new=IAM(aws_provider),
) as service_client:
from prowler.providers.aws.services.iam.iam_no_root_access_key.iam_no_root_access_key import (
iam_no_root_access_key,
)
# Set up organizational root management
service_client.organization_features = ["RootCredentialsManagement"]
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0][
"arn"
] = "arn:aws:iam::123456789012:user/<root_account>"
service_client.credential_report[0]["password_enabled"] = "false"
service_client.credential_report[0]["access_key_1_active"] = "true"
service_client.credential_report[0]["access_key_2_active"] = "true"
check = iam_no_root_access_key()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "Root account has two active access keys despite organizational root management being enabled."
)
assert result[0].resource_id == "<root_account>"
assert (
result[0].resource_arn
== "arn:aws:iam::123456789012:user/<root_account>"
)
@@ -1,5 +1,9 @@
from re import search
from unittest import mock
from boto3 import client
from moto import mock_aws
from tests.providers.aws.utils import (
AWS_ACCOUNT_NUMBER,
AWS_REGION_US_EAST_1,
@@ -15,23 +19,14 @@ class Test_iam_root_hardware_mfa_enabled_test:
set_mocked_aws_provider,
)
@mock_aws
def test_root_virtual_mfa_enabled(self):
iam_client = mock.MagicMock
iam_client.account_summary = {
"SummaryMap": {"AccountMFAEnabled": 1},
}
iam_client.virtual_mfa_devices = [
{
"SerialNumber": f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:mfa/mfa",
"User": {"Arn": f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root"},
}
]
iam_client.audited_partition = "aws"
iam_client.region = AWS_REGION_US_EAST_1
iam_client.mfa_arn_template = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:mfa"
iam_client.organization_features = []
iam_client = client("iam")
user = "test-user"
iam_client.create_user(UserName=user)["User"]["Arn"]
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
from prowler.providers.aws.services.iam.iam_service import IAM
with (
mock.patch(
@@ -40,13 +35,32 @@ class Test_iam_root_hardware_mfa_enabled_test:
),
mock.patch(
"prowler.providers.aws.services.iam.iam_root_hardware_mfa_enabled.iam_root_hardware_mfa_enabled.iam_client",
new=iam_client,
),
new=IAM(aws_provider),
) as service_client,
):
from prowler.providers.aws.services.iam.iam_root_hardware_mfa_enabled.iam_root_hardware_mfa_enabled import (
iam_root_hardware_mfa_enabled,
)
# Set up virtual MFA device for root
service_client.virtual_mfa_devices = [
{
"SerialNumber": f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:mfa/mfa",
"User": {"Arn": f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root"},
}
]
service_client.account_summary = {
"SummaryMap": {"AccountMFAEnabled": 1},
}
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0]["password_enabled"] = "true"
service_client.credential_report[0]["access_key_1_active"] = "false"
service_client.credential_report[0]["access_key_2_active"] = "false"
service_client.credential_report[0][
"arn"
] = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root"
check = iam_root_hardware_mfa_enabled()
result = check.execute()
assert len(result) == 1
@@ -58,18 +72,14 @@ class Test_iam_root_hardware_mfa_enabled_test:
assert result[0].resource_id == "<root_account>"
assert result[0].resource_arn == f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:mfa"
@mock_aws
def test_root_hardware_mfa_enabled(self):
iam_client = mock.MagicMock
iam_client.account_summary = {
"SummaryMap": {"AccountMFAEnabled": 1},
}
iam_client.virtual_mfa_devices = []
iam_client.audited_partition = "aws"
iam_client.region = AWS_REGION_US_EAST_1
iam_client.mfa_arn_template = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:mfa"
iam_client.organization_features = []
iam_client = client("iam")
user = "test-user"
iam_client.create_user(UserName=user)["User"]["Arn"]
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
from prowler.providers.aws.services.iam.iam_service import IAM
with (
mock.patch(
@@ -78,13 +88,27 @@ class Test_iam_root_hardware_mfa_enabled_test:
),
mock.patch(
"prowler.providers.aws.services.iam.iam_root_hardware_mfa_enabled.iam_root_hardware_mfa_enabled.iam_client",
new=iam_client,
),
new=IAM(aws_provider),
) as service_client,
):
from prowler.providers.aws.services.iam.iam_root_hardware_mfa_enabled.iam_root_hardware_mfa_enabled import (
iam_root_hardware_mfa_enabled,
)
# No virtual MFA devices (indicating hardware MFA)
service_client.virtual_mfa_devices = []
service_client.account_summary = {
"SummaryMap": {"AccountMFAEnabled": 1},
}
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0]["password_enabled"] = "true"
service_client.credential_report[0]["access_key_1_active"] = "false"
service_client.credential_report[0]["access_key_2_active"] = "false"
service_client.credential_report[0][
"arn"
] = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root"
check = iam_root_hardware_mfa_enabled()
result = check.execute()
assert len(result) == 1
@@ -96,16 +120,14 @@ class Test_iam_root_hardware_mfa_enabled_test:
assert result[0].resource_id == "<root_account>"
assert result[0].resource_arn == f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:mfa"
@mock_aws
def test_root_hardware_mfa_enabled_none_summary(self):
iam_client = mock.MagicMock
iam_client.account_summary = None
iam_client.virtual_mfa_devices = []
iam_client.audited_partition = "aws"
iam_client.region = AWS_REGION_US_EAST_1
iam_client.mfa_arn_template = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:mfa"
iam_client.organization_features = []
iam_client = client("iam")
user = "test-user"
iam_client.create_user(UserName=user)["User"]["Arn"]
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
from prowler.providers.aws.services.iam.iam_service import IAM
with (
mock.patch(
@@ -114,13 +136,222 @@ class Test_iam_root_hardware_mfa_enabled_test:
),
mock.patch(
"prowler.providers.aws.services.iam.iam_root_hardware_mfa_enabled.iam_root_hardware_mfa_enabled.iam_client",
new=iam_client,
),
new=IAM(aws_provider),
) as service_client,
):
from prowler.providers.aws.services.iam.iam_root_hardware_mfa_enabled.iam_root_hardware_mfa_enabled import (
iam_root_hardware_mfa_enabled,
)
# No account summary
service_client.account_summary = None
service_client.virtual_mfa_devices = []
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0]["password_enabled"] = "true"
service_client.credential_report[0]["access_key_1_active"] = "false"
service_client.credential_report[0]["access_key_2_active"] = "false"
service_client.credential_report[0][
"arn"
] = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root"
check = iam_root_hardware_mfa_enabled()
result = check.execute()
assert len(result) == 0
@mock_aws
def test_root_no_credentials(self):
iam_client = client("iam")
user = "test-user"
iam_client.create_user(UserName=user)["User"]["Arn"]
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
from prowler.providers.aws.services.iam.iam_service import IAM
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
),
mock.patch(
"prowler.providers.aws.services.iam.iam_root_hardware_mfa_enabled.iam_root_hardware_mfa_enabled.iam_client",
new=IAM(aws_provider),
) as service_client,
):
from prowler.providers.aws.services.iam.iam_root_hardware_mfa_enabled.iam_root_hardware_mfa_enabled import (
iam_root_hardware_mfa_enabled,
)
service_client.account_summary = {
"SummaryMap": {"AccountMFAEnabled": 1},
}
service_client.virtual_mfa_devices = []
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0]["password_enabled"] = "false"
service_client.credential_report[0]["access_key_1_active"] = "false"
service_client.credential_report[0]["access_key_2_active"] = "false"
service_client.credential_report[0][
"arn"
] = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root"
check = iam_root_hardware_mfa_enabled()
result = check.execute()
# Should return no findings since root has no credentials
assert len(result) == 0
@mock_aws
def test_root_hardware_mfa_with_organizational_management_enabled(self):
iam_client = client("iam")
user = "test-user"
iam_client.create_user(UserName=user)["User"]["Arn"]
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
from prowler.providers.aws.services.iam.iam_service import IAM
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
),
mock.patch(
"prowler.providers.aws.services.iam.iam_root_hardware_mfa_enabled.iam_root_hardware_mfa_enabled.iam_client",
new=IAM(aws_provider),
) as service_client,
):
from prowler.providers.aws.services.iam.iam_root_hardware_mfa_enabled.iam_root_hardware_mfa_enabled import (
iam_root_hardware_mfa_enabled,
)
# Set up organizational root management
service_client.organization_features = ["RootCredentialsManagement"]
service_client.account_summary = {
"SummaryMap": {"AccountMFAEnabled": 1},
}
service_client.virtual_mfa_devices = []
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0]["password_enabled"] = "true"
service_client.credential_report[0]["access_key_1_active"] = "true"
service_client.credential_report[0]["access_key_2_active"] = "false"
service_client.credential_report[0][
"arn"
] = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root"
check = iam_root_hardware_mfa_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert search(
"Root account has credentials with hardware MFA enabled. "
"Consider removing individual root credentials since organizational "
"root management is active.",
result[0].status_extended,
)
assert result[0].resource_id == "<root_account>"
assert result[0].resource_arn == f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:mfa"
@mock_aws
def test_root_virtual_mfa_with_organizational_management_enabled(self):
iam_client = client("iam")
user = "test-user"
iam_client.create_user(UserName=user)["User"]["Arn"]
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
from prowler.providers.aws.services.iam.iam_service import IAM
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
),
mock.patch(
"prowler.providers.aws.services.iam.iam_root_hardware_mfa_enabled.iam_root_hardware_mfa_enabled.iam_client",
new=IAM(aws_provider),
) as service_client,
):
from prowler.providers.aws.services.iam.iam_root_hardware_mfa_enabled.iam_root_hardware_mfa_enabled import (
iam_root_hardware_mfa_enabled,
)
# Set up organizational root management
service_client.organization_features = ["RootCredentialsManagement"]
service_client.account_summary = {
"SummaryMap": {"AccountMFAEnabled": 1},
}
service_client.virtual_mfa_devices = [
{
"SerialNumber": f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:mfa/mfa",
"User": {"Arn": f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root"},
}
]
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0]["password_enabled"] = "true"
service_client.credential_report[0]["access_key_1_active"] = "false"
service_client.credential_report[0]["access_key_2_active"] = "true"
service_client.credential_report[0][
"arn"
] = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root"
check = iam_root_hardware_mfa_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert search(
"Root account has credentials with virtual MFA instead of hardware MFA "
"despite organizational root management being enabled.",
result[0].status_extended,
)
assert result[0].resource_id == "<root_account>"
assert result[0].resource_arn == f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:mfa"
@mock_aws
def test_root_no_mfa_with_organizational_management_enabled(self):
iam_client = client("iam")
user = "test-user"
iam_client.create_user(UserName=user)["User"]["Arn"]
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
from prowler.providers.aws.services.iam.iam_service import IAM
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
),
mock.patch(
"prowler.providers.aws.services.iam.iam_root_hardware_mfa_enabled.iam_root_hardware_mfa_enabled.iam_client",
new=IAM(aws_provider),
) as service_client,
):
from prowler.providers.aws.services.iam.iam_root_hardware_mfa_enabled.iam_root_hardware_mfa_enabled import (
iam_root_hardware_mfa_enabled,
)
# Set up organizational root management
service_client.organization_features = ["RootCredentialsManagement"]
service_client.account_summary = {
"SummaryMap": {"AccountMFAEnabled": 0},
}
service_client.virtual_mfa_devices = []
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0]["password_enabled"] = "true"
service_client.credential_report[0]["access_key_1_active"] = "false"
service_client.credential_report[0]["access_key_2_active"] = "false"
service_client.credential_report[0][
"arn"
] = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root"
check = iam_root_hardware_mfa_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert search(
"Root account has credentials without MFA "
"despite organizational root management being enabled.",
result[0].status_extended,
)
assert result[0].resource_id == "<root_account>"
assert result[0].resource_arn == f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:mfa"
@@ -42,12 +42,16 @@ class Test_iam_root_mfa_enabled_test:
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0]["mfa_active"] = "false"
service_client.credential_report[0]["password_enabled"] = "true"
service_client.credential_report[0]["access_key_1_active"] = "false"
service_client.credential_report[0]["access_key_2_active"] = "false"
service_client.credential_report[0][
"arn"
] = "arn:aws:iam::123456789012:<root_account>:root"
check = iam_root_mfa_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert search(
"MFA is not enabled for root account.", result[0].status_extended
@@ -80,13 +84,149 @@ class Test_iam_root_mfa_enabled_test:
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0]["mfa_active"] = "true"
service_client.credential_report[0]["password_enabled"] = "true"
service_client.credential_report[0]["access_key_1_active"] = "false"
service_client.credential_report[0]["access_key_2_active"] = "false"
service_client.credential_report[0][
"arn"
] = "arn:aws:iam::123456789012:<root_account>:root"
check = iam_root_mfa_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert search("MFA is enabled for root account.", result[0].status_extended)
assert result[0].resource_id == "<root_account>"
assert result[0].resource_arn == service_client.credential_report[0]["arn"]
@mock_aws
def test_root_no_credentials(self):
iam_client = client("iam")
user = "test-user"
iam_client.create_user(UserName=user)["User"]["Arn"]
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
from prowler.providers.aws.services.iam.iam_service import IAM
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
),
mock.patch(
"prowler.providers.aws.services.iam.iam_root_mfa_enabled.iam_root_mfa_enabled.iam_client",
new=IAM(aws_provider),
) as service_client,
):
from prowler.providers.aws.services.iam.iam_root_mfa_enabled.iam_root_mfa_enabled import (
iam_root_mfa_enabled,
)
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0]["mfa_active"] = "false"
service_client.credential_report[0]["password_enabled"] = "false"
service_client.credential_report[0]["access_key_1_active"] = "false"
service_client.credential_report[0]["access_key_2_active"] = "false"
service_client.credential_report[0][
"arn"
] = "arn:aws:iam::123456789012:<root_account>:root"
check = iam_root_mfa_enabled()
result = check.execute()
# Should return no findings since root has no credentials
assert len(result) == 0
@mock_aws
def test_root_mfa_with_organizational_management_enabled(self):
iam_client = client("iam")
user = "test-user"
iam_client.create_user(UserName=user)["User"]["Arn"]
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
from prowler.providers.aws.services.iam.iam_service import IAM
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
),
mock.patch(
"prowler.providers.aws.services.iam.iam_root_mfa_enabled.iam_root_mfa_enabled.iam_client",
new=IAM(aws_provider),
) as service_client,
):
from prowler.providers.aws.services.iam.iam_root_mfa_enabled.iam_root_mfa_enabled import (
iam_root_mfa_enabled,
)
# Set up organizational root management
service_client.organization_features = ["RootCredentialsManagement"]
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0]["mfa_active"] = "true"
service_client.credential_report[0]["password_enabled"] = "true"
service_client.credential_report[0]["access_key_1_active"] = "true"
service_client.credential_report[0]["access_key_2_active"] = "false"
service_client.credential_report[0][
"arn"
] = "arn:aws:iam::123456789012:<root_account>:root"
check = iam_root_mfa_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert search(
"Root account has credentials with MFA enabled. "
"Consider removing individual root credentials since organizational "
"root management is active.",
result[0].status_extended,
)
assert result[0].resource_id == "<root_account>"
assert result[0].resource_arn == service_client.credential_report[0]["arn"]
@mock_aws
def test_root_mfa_disabled_with_organizational_management_enabled(self):
iam_client = client("iam")
user = "test-user"
iam_client.create_user(UserName=user)["User"]["Arn"]
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
from prowler.providers.aws.services.iam.iam_service import IAM
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
),
mock.patch(
"prowler.providers.aws.services.iam.iam_root_mfa_enabled.iam_root_mfa_enabled.iam_client",
new=IAM(aws_provider),
) as service_client,
):
from prowler.providers.aws.services.iam.iam_root_mfa_enabled.iam_root_mfa_enabled import (
iam_root_mfa_enabled,
)
# Set up organizational root management
service_client.organization_features = ["RootCredentialsManagement"]
service_client.credential_report[0]["user"] = "<root_account>"
service_client.credential_report[0]["mfa_active"] = "false"
service_client.credential_report[0]["password_enabled"] = "true"
service_client.credential_report[0]["access_key_1_active"] = "false"
service_client.credential_report[0]["access_key_2_active"] = "true"
service_client.credential_report[0][
"arn"
] = "arn:aws:iam::123456789012:<root_account>:root"
check = iam_root_mfa_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert search(
"Root account has credentials without MFA "
"despite organizational root management being enabled.",
result[0].status_extended,
)
assert result[0].resource_id == "<root_account>"
assert result[0].resource_arn == service_client.credential_report[0]["arn"]