From 9b0dd80f13ee03b38f0999b1ccc75ff797399864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20De=20la=20Torre=20Vico?= Date: Thu, 16 Jan 2025 16:24:53 +0100 Subject: [PATCH] feat(entra): extract Entra resource metadata automated (#6542) Co-authored-by: Sergio Garcia --- ...s_policy_require_mfa_for_management_api.py | 26 +++-- ...ra_global_admin_in_less_than_five_users.py | 4 +- .../entra_non_privileged_user_has_mfa.py | 6 +- ...ult_users_cannot_create_security_groups.py | 7 +- ..._ensure_default_user_cannot_create_apps.py | 7 +- ...sure_default_user_cannot_create_tenants.py | 6 +- ...olicy_guest_invite_only_for_admin_roles.py | 6 +- ..._policy_guest_users_access_restrictions.py | 6 +- ..._policy_restricts_user_consent_for_apps.py | 6 +- ...a_policy_user_consent_for_verified_apps.py | 6 +- .../entra_privileged_user_has_mfa.py | 8 +- .../entra_security_defaults_enabled.py | 8 +- .../azure/services/entra/entra_service.py | 4 + .../entra_trusted_named_locations_exists.py | 13 ++- .../entra_user_with_vm_access_has_mfa.py | 9 +- ...sers_cannot_create_microsoft_365_groups.py | 4 +- ...icy_require_mfa_for_management_api_test.py | 5 + ...obal_admin_in_less_than_five_users_test.py | 107 +++++++++++++----- .../entra_non_privileged_user_has_mfa_test.py | 4 +- .../entra_privileged_user_has_mfa_test.py | 4 +- .../entra_security_defaults_enabled_test.py | 4 +- .../services/entra/entra_service_test.py | 1 + ...tra_trusted_named_locations_exists_test.py | 90 +++++++++------ .../entra_user_with_vm_access_has_mfa_test.py | 4 +- 24 files changed, 220 insertions(+), 125 deletions(-) diff --git a/prowler/providers/azure/services/entra/entra_conditional_access_policy_require_mfa_for_management_api/entra_conditional_access_policy_require_mfa_for_management_api.py b/prowler/providers/azure/services/entra/entra_conditional_access_policy_require_mfa_for_management_api/entra_conditional_access_policy_require_mfa_for_management_api.py index d5e9d9357c..8c76f4d9fd 100644 --- a/prowler/providers/azure/services/entra/entra_conditional_access_policy_require_mfa_for_management_api/entra_conditional_access_policy_require_mfa_for_management_api.py +++ b/prowler/providers/azure/services/entra/entra_conditional_access_policy_require_mfa_for_management_api/entra_conditional_access_policy_require_mfa_for_management_api.py @@ -11,16 +11,7 @@ class entra_conditional_access_policy_require_mfa_for_management_api(Check): tenant_name, conditional_access_policies, ) in entra_client.conditional_access_policy.items(): - report = Check_Report_Azure(self.metadata()) - report.status = "FAIL" - report.subscription = f"Tenant: {tenant_name}" - report.resource_name = "Conditional Access Policy" - report.resource_id = "Conditional Access Policy" - report.status_extended = ( - "Conditional Access Policy does not require MFA for management API." - ) - - for policy_id, policy in conditional_access_policies.items(): + for policy in conditional_access_policies.values(): if ( policy.state == "enabled" and "All" in policy.users["include"] @@ -31,13 +22,24 @@ class entra_conditional_access_policy_require_mfa_for_management_api(Check): for access_control in policy.access_controls["grant"] ) ): + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=policy + ) + report.subscription = f"Tenant: {tenant_name}" report.status = "PASS" report.status_extended = ( "Conditional Access Policy requires MFA for management API." ) - report.resource_id = policy_id - report.resource_name = policy.name break + else: + report = Check_Report_Azure(self.metadata()) + report.subscription = f"Tenant: {tenant_name}" + report.resource_name = "Conditional Access Policy" + report.resource_id = "Conditional Access Policy" + report.status = "FAIL" + report.status_extended = ( + "Conditional Access Policy does not require MFA for management API." + ) findings.append(report) diff --git a/prowler/providers/azure/services/entra/entra_global_admin_in_less_than_five_users/entra_global_admin_in_less_than_five_users.py b/prowler/providers/azure/services/entra/entra_global_admin_in_less_than_five_users/entra_global_admin_in_less_than_five_users.py index b1c5f6bf60..5c415aa500 100644 --- a/prowler/providers/azure/services/entra/entra_global_admin_in_less_than_five_users/entra_global_admin_in_less_than_five_users.py +++ b/prowler/providers/azure/services/entra/entra_global_admin_in_less_than_five_users/entra_global_admin_in_less_than_five_users.py @@ -7,7 +7,9 @@ class entra_global_admin_in_less_than_five_users(Check): findings = [] for tenant_domain, directory_roles in entra_client.directory_roles.items(): - report = Check_Report_Azure(self.metadata()) + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=entra_client.users + ) report.status = "FAIL" report.subscription = f"Tenant: {tenant_domain}" report.resource_name = "Global Administrator" diff --git a/prowler/providers/azure/services/entra/entra_non_privileged_user_has_mfa/entra_non_privileged_user_has_mfa.py b/prowler/providers/azure/services/entra/entra_non_privileged_user_has_mfa/entra_non_privileged_user_has_mfa.py index c2eadfffd6..8603fbb00a 100644 --- a/prowler/providers/azure/services/entra/entra_non_privileged_user_has_mfa/entra_non_privileged_user_has_mfa.py +++ b/prowler/providers/azure/services/entra/entra_non_privileged_user_has_mfa/entra_non_privileged_user_has_mfa.py @@ -14,11 +14,9 @@ class entra_non_privileged_user_has_mfa(Check): if not is_privileged_user( user, entra_client.directory_roles[tenant_domain] ): - report = Check_Report_Azure(self.metadata()) - report.status = "FAIL" + report = Check_Report_Azure(self.metadata(), resource_metadata=user) report.subscription = f"Tenant: {tenant_domain}" - report.resource_name = user_domain_name - report.resource_id = user.id + report.status = "FAIL" report.status_extended = ( f"Non-privileged user {user.name} does not have MFA." ) diff --git a/prowler/providers/azure/services/entra/entra_policy_default_users_cannot_create_security_groups/entra_policy_default_users_cannot_create_security_groups.py b/prowler/providers/azure/services/entra/entra_policy_default_users_cannot_create_security_groups/entra_policy_default_users_cannot_create_security_groups.py index 6b8a36ce40..6cf96507c9 100644 --- a/prowler/providers/azure/services/entra/entra_policy_default_users_cannot_create_security_groups/entra_policy_default_users_cannot_create_security_groups.py +++ b/prowler/providers/azure/services/entra/entra_policy_default_users_cannot_create_security_groups/entra_policy_default_users_cannot_create_security_groups.py @@ -7,12 +7,13 @@ class entra_policy_default_users_cannot_create_security_groups(Check): findings = [] for tenant_domain, auth_policy in entra_client.authorization_policy.items(): - - report = Check_Report_Azure(self.metadata()) - report.status = "FAIL" + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=auth_policy + ) report.subscription = f"Tenant: {tenant_domain}" report.resource_name = getattr(auth_policy, "name", "Authorization Policy") report.resource_id = getattr(auth_policy, "id", "authorizationPolicy") + report.status = "FAIL" report.status_extended = "Non-privileged users are able to create security groups via the Access Panel and the Azure administration portal." if getattr( diff --git a/prowler/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_apps/entra_policy_ensure_default_user_cannot_create_apps.py b/prowler/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_apps/entra_policy_ensure_default_user_cannot_create_apps.py index bf1df9c103..1451c52170 100644 --- a/prowler/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_apps/entra_policy_ensure_default_user_cannot_create_apps.py +++ b/prowler/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_apps/entra_policy_ensure_default_user_cannot_create_apps.py @@ -7,12 +7,13 @@ class entra_policy_ensure_default_user_cannot_create_apps(Check): findings = [] for tenant_domain, auth_policy in entra_client.authorization_policy.items(): - - report = Check_Report_Azure(self.metadata()) - report.status = "FAIL" + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=auth_policy + ) report.subscription = f"Tenant: {tenant_domain}" report.resource_name = getattr(auth_policy, "name", "Authorization Policy") report.resource_id = getattr(auth_policy, "id", "authorizationPolicy") + report.status = "FAIL" report.status_extended = "App creation is not disabled for non-admin users." if getattr( diff --git a/prowler/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.py b/prowler/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.py index 1727b23bdc..3ff924c73a 100644 --- a/prowler/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.py +++ b/prowler/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants.py @@ -7,11 +7,13 @@ class entra_policy_ensure_default_user_cannot_create_tenants(Check): findings = [] for tenant_domain, auth_policy in entra_client.authorization_policy.items(): - report = Check_Report_Azure(self.metadata()) - report.status = "FAIL" + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=auth_policy + ) report.subscription = f"Tenant: {tenant_domain}" report.resource_name = getattr(auth_policy, "name", "Authorization Policy") report.resource_id = getattr(auth_policy, "id", "authorizationPolicy") + report.status = "FAIL" report.status_extended = ( "Tenants creation is not disabled for non-admin users." ) diff --git a/prowler/providers/azure/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py b/prowler/providers/azure/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py index 376ebe4aa5..e40ed9deb7 100644 --- a/prowler/providers/azure/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py +++ b/prowler/providers/azure/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles.py @@ -7,11 +7,13 @@ class entra_policy_guest_invite_only_for_admin_roles(Check): findings = [] for tenant_domain, auth_policy in entra_client.authorization_policy.items(): - report = Check_Report_Azure(self.metadata()) - report.status = "FAIL" + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=auth_policy + ) report.subscription = f"Tenant: {tenant_domain}" report.resource_name = getattr(auth_policy, "name", "Authorization Policy") report.resource_id = getattr(auth_policy, "id", "authorizationPolicy") + report.status = "FAIL" report.status_extended = "Guest invitations are not restricted to users with specific administrative roles only." if ( diff --git a/prowler/providers/azure/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py b/prowler/providers/azure/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py index 65868e7d83..ca730463d7 100644 --- a/prowler/providers/azure/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py +++ b/prowler/providers/azure/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions.py @@ -8,11 +8,13 @@ class entra_policy_guest_users_access_restrictions(Check): findings = [] for tenant_domain, auth_policy in entra_client.authorization_policy.items(): - report = Check_Report_Azure(self.metadata()) - report.status = "FAIL" + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=auth_policy + ) report.subscription = f"Tenant: {tenant_domain}" report.resource_name = getattr(auth_policy, "name", "Authorization Policy") report.resource_id = getattr(auth_policy, "id", "authorizationPolicy") + report.status = "FAIL" report.status_extended = "Guest user access is not restricted to properties and memberships of their own directory objects" if ( diff --git a/prowler/providers/azure/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py b/prowler/providers/azure/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py index fe1c6d2070..df66fa550a 100644 --- a/prowler/providers/azure/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py +++ b/prowler/providers/azure/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps.py @@ -7,11 +7,13 @@ class entra_policy_restricts_user_consent_for_apps(Check): findings = [] for tenant_domain, auth_policy in entra_client.authorization_policy.items(): - report = Check_Report_Azure(self.metadata()) - report.status = "FAIL" + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=auth_policy + ) report.subscription = f"Tenant: {tenant_domain}" report.resource_name = getattr(auth_policy, "name", "Authorization Policy") report.resource_id = getattr(auth_policy, "id", "authorizationPolicy") + report.status = "FAIL" report.status_extended = "Entra allows users to consent apps accessing company data on their behalf" if getattr(auth_policy, "default_user_role_permissions", None) and not any( diff --git a/prowler/providers/azure/services/entra/entra_policy_user_consent_for_verified_apps/entra_policy_user_consent_for_verified_apps.py b/prowler/providers/azure/services/entra/entra_policy_user_consent_for_verified_apps/entra_policy_user_consent_for_verified_apps.py index 36cc9aeabc..869114dc9f 100644 --- a/prowler/providers/azure/services/entra/entra_policy_user_consent_for_verified_apps/entra_policy_user_consent_for_verified_apps.py +++ b/prowler/providers/azure/services/entra/entra_policy_user_consent_for_verified_apps/entra_policy_user_consent_for_verified_apps.py @@ -7,11 +7,13 @@ class entra_policy_user_consent_for_verified_apps(Check): findings = [] for tenant_domain, auth_policy in entra_client.authorization_policy.items(): - report = Check_Report_Azure(self.metadata()) - report.status = "PASS" + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=auth_policy + ) report.subscription = f"Tenant: {tenant_domain}" report.resource_name = getattr(auth_policy, "name", "Authorization Policy") report.resource_id = getattr(auth_policy, "id", "authorizationPolicy") + report.status = "PASS" report.status_extended = "Entra does not allow users to consent non-verified apps accessing company data on their behalf." if getattr(auth_policy, "default_user_role_permissions", None) and any( diff --git a/prowler/providers/azure/services/entra/entra_privileged_user_has_mfa/entra_privileged_user_has_mfa.py b/prowler/providers/azure/services/entra/entra_privileged_user_has_mfa/entra_privileged_user_has_mfa.py index 807e982747..72b2e7b2f3 100644 --- a/prowler/providers/azure/services/entra/entra_privileged_user_has_mfa/entra_privileged_user_has_mfa.py +++ b/prowler/providers/azure/services/entra/entra_privileged_user_has_mfa/entra_privileged_user_has_mfa.py @@ -14,11 +14,11 @@ class entra_privileged_user_has_mfa(Check): if is_privileged_user( user, entra_client.directory_roles[tenant_domain] ): - report = Check_Report_Azure(self.metadata()) - report.status = "FAIL" + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=user + ) report.subscription = f"Tenant: {tenant_domain}" - report.resource_name = user_domain_name - report.resource_id = user.id + report.status = "FAIL" report.status_extended = ( f"Privileged user {user.name} does not have MFA." ) diff --git a/prowler/providers/azure/services/entra/entra_security_defaults_enabled/entra_security_defaults_enabled.py b/prowler/providers/azure/services/entra/entra_security_defaults_enabled/entra_security_defaults_enabled.py index a3f192d85a..a922b7c166 100644 --- a/prowler/providers/azure/services/entra/entra_security_defaults_enabled/entra_security_defaults_enabled.py +++ b/prowler/providers/azure/services/entra/entra_security_defaults_enabled/entra_security_defaults_enabled.py @@ -10,11 +10,11 @@ class entra_security_defaults_enabled(Check): tenant, security_default, ) in entra_client.security_default.items(): - report = Check_Report_Azure(self.metadata()) - report.status = "FAIL" + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=security_default + ) report.subscription = f"Tenant: {tenant}" - report.resource_name = getattr(security_default, "name", "Security Default") - report.resource_id = getattr(security_default, "id", "Security Default") + report.status = "FAIL" report.status_extended = "Entra security defaults is diabled." if getattr(security_default, "is_enabled", False): diff --git a/prowler/providers/azure/services/entra/entra_service.py b/prowler/providers/azure/services/entra/entra_service.py index 8612dbf4a1..97e84c0777 100644 --- a/prowler/providers/azure/services/entra/entra_service.py +++ b/prowler/providers/azure/services/entra/entra_service.py @@ -176,6 +176,7 @@ class Entra(AzureService): named_locations[tenant].update( { named_location.id: NamedLocation( + id=named_location.id, name=named_location.display_name, ip_ranges_addresses=[ getattr(ip_range, "cidr_address", None) @@ -274,6 +275,7 @@ class Entra(AzureService): conditional_access_policy[tenant].update( { policy.id: ConditionalAccessPolicy( + id=policy.id, name=policy.display_name, state=getattr(policy, "state", "None"), users={ @@ -337,6 +339,7 @@ class SecurityDefault(BaseModel): class NamedLocation(BaseModel): + id: str name: str ip_ranges_addresses: List[str] is_trusted: bool @@ -348,6 +351,7 @@ class DirectoryRole(BaseModel): class ConditionalAccessPolicy(BaseModel): + id: str name: str state: str users: dict[str, List[str]] diff --git a/prowler/providers/azure/services/entra/entra_trusted_named_locations_exists/entra_trusted_named_locations_exists.py b/prowler/providers/azure/services/entra/entra_trusted_named_locations_exists/entra_trusted_named_locations_exists.py index c69594565f..d2731b5f15 100644 --- a/prowler/providers/azure/services/entra/entra_trusted_named_locations_exists/entra_trusted_named_locations_exists.py +++ b/prowler/providers/azure/services/entra/entra_trusted_named_locations_exists/entra_trusted_named_locations_exists.py @@ -7,7 +7,9 @@ class entra_trusted_named_locations_exists(Check): findings = [] for tenant, named_locations in entra_client.named_locations.items(): - report = Check_Report_Azure(self.metadata()) + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=named_locations + ) report.status = "FAIL" report.subscription = f"Tenant: {tenant}" report.resource_name = "Named Locations" @@ -15,11 +17,12 @@ class entra_trusted_named_locations_exists(Check): report.status_extended = ( "There is no trusted location with IP ranges defined." ) - for named_location_id, named_location in named_locations.items(): - report.resource_name = named_location.name - report.resource_id = named_location_id - + for named_location in named_locations.values(): if named_location.ip_ranges_addresses and named_location.is_trusted: + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=named_location + ) + report.subscription = f"Tenant: {tenant}" report.status = "PASS" report.status_extended = f"Exits trusted location with trusted IP ranges, this IPs ranges are: {[ip_range for ip_range in named_location.ip_ranges_addresses if ip_range]}" break diff --git a/prowler/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa.py b/prowler/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa.py index a3fc52e22f..5a053e294e 100644 --- a/prowler/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa.py +++ b/prowler/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa.py @@ -37,13 +37,12 @@ class entra_user_with_vm_access_has_mfa(Check): ] and assignment.agent_id == user.id ): - report = Check_Report_Azure(self.metadata()) + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=user + ) + report.subscription = subscription_name report.status = "FAIL" report.status_extended = f"User {user.name} without MFA can access VMs in subscription {subscription_name}" - report.subscription = subscription_name - report.resource_name = user_domain_name - report.resource_id = user.id - if len(user.authentication_methods) > 1: report.status = "PASS" report.status_extended = f"User {user.name} can access VMs in subscription {subscription_name} but it has MFA." diff --git a/prowler/providers/azure/services/entra/entra_users_cannot_create_microsoft_365_groups/entra_users_cannot_create_microsoft_365_groups.py b/prowler/providers/azure/services/entra/entra_users_cannot_create_microsoft_365_groups/entra_users_cannot_create_microsoft_365_groups.py index d329f8966e..cde6f3e1a3 100644 --- a/prowler/providers/azure/services/entra/entra_users_cannot_create_microsoft_365_groups/entra_users_cannot_create_microsoft_365_groups.py +++ b/prowler/providers/azure/services/entra/entra_users_cannot_create_microsoft_365_groups/entra_users_cannot_create_microsoft_365_groups.py @@ -7,7 +7,9 @@ class entra_users_cannot_create_microsoft_365_groups(Check): findings = [] for tenant_domain, group_settings in entra_client.group_settings.items(): - report = Check_Report_Azure(self.metadata()) + report = Check_Report_Azure( + metadata=self.metadata(), resource_metadata=group_settings + ) report.status = "FAIL" report.subscription = f"Tenant: {tenant_domain}" report.resource_name = "Microsoft365 Groups" diff --git a/tests/providers/azure/services/entra/entra_conditional_access_policy_require_mfa_for_management_api/entra_conditional_access_policy_require_mfa_for_management_api_test.py b/tests/providers/azure/services/entra/entra_conditional_access_policy_require_mfa_for_management_api/entra_conditional_access_policy_require_mfa_for_management_api_test.py index 81fbfc5195..1a4fafc2b7 100644 --- a/tests/providers/azure/services/entra/entra_conditional_access_policy_require_mfa_for_management_api/entra_conditional_access_policy_require_mfa_for_management_api_test.py +++ b/tests/providers/azure/services/entra/entra_conditional_access_policy_require_mfa_for_management_api/entra_conditional_access_policy_require_mfa_for_management_api_test.py @@ -72,6 +72,7 @@ class Test_entra_conditional_access_policy_require_mfa_for_management_api: ) policy = ConditionalAccessPolicy( + id=policy_id, name="Test Policy", state="enabled", users={"include": ["All"]}, @@ -112,6 +113,7 @@ class Test_entra_conditional_access_policy_require_mfa_for_management_api: ) policy = ConditionalAccessPolicy( + id=policy_id, name="Test Policy", state="enabled", users={"include": ["All"]}, @@ -152,6 +154,7 @@ class Test_entra_conditional_access_policy_require_mfa_for_management_api: ) policy = ConditionalAccessPolicy( + id=policy_id, name="Test Policy", state="disabled", users={"include": ["All"]}, @@ -192,6 +195,7 @@ class Test_entra_conditional_access_policy_require_mfa_for_management_api: ) policy = ConditionalAccessPolicy( + id=policy_id, name="Test Policy", state="enabled", users={"include": ["All"]}, @@ -232,6 +236,7 @@ class Test_entra_conditional_access_policy_require_mfa_for_management_api: ) policy = ConditionalAccessPolicy( + id=policy_id, name="Test Policy", state="enabled", users={"include": []}, diff --git a/tests/providers/azure/services/entra/entra_global_admin_in_less_than_five_users/entra_global_admin_in_less_than_five_users_test.py b/tests/providers/azure/services/entra/entra_global_admin_in_less_than_five_users/entra_global_admin_in_less_than_five_users_test.py index a362b2a63d..470983995f 100644 --- a/tests/providers/azure/services/entra/entra_global_admin_in_less_than_five_users/entra_global_admin_in_less_than_five_users_test.py +++ b/tests/providers/azure/services/entra/entra_global_admin_in_less_than_five_users/entra_global_admin_in_less_than_five_users_test.py @@ -8,12 +8,15 @@ class Test_entra_global_admin_in_less_than_five_users: def test_entra_no_tenants(self): entra_client = mock.MagicMock - with mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_azure_provider(), - ), mock.patch( - "prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users.entra_client", - new=entra_client, + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users.entra_client", + new=entra_client, + ), ): from prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users import ( entra_global_admin_in_less_than_five_users, @@ -21,6 +24,8 @@ class Test_entra_global_admin_in_less_than_five_users: entra_client.directory_roles = {} + entra_client.uses = {} + check = entra_global_admin_in_less_than_five_users() result = check.execute() assert len(result) == 0 @@ -28,12 +33,15 @@ class Test_entra_global_admin_in_less_than_five_users: def test_entra_tenant_empty(self): entra_client = mock.MagicMock - with mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_azure_provider(), - ), mock.patch( - "prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users.entra_client", - new=entra_client, + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users.entra_client", + new=entra_client, + ), ): from prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users import ( entra_global_admin_in_less_than_five_users, @@ -41,6 +49,8 @@ class Test_entra_global_admin_in_less_than_five_users: entra_client.directory_roles = {DOMAIN: {}} + entra_client.users = {DOMAIN: {}} + check = entra_global_admin_in_less_than_five_users() result = check.execute() assert len(result) == 0 @@ -48,12 +58,15 @@ class Test_entra_global_admin_in_less_than_five_users: def test_entra_less_than_five_global_admins(self): entra_client = mock.MagicMock - with mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_azure_provider(), - ), mock.patch( - "prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users.entra_client", - new=entra_client, + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users.entra_client", + new=entra_client, + ), ): from prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users import ( entra_global_admin_in_less_than_five_users, @@ -79,6 +92,13 @@ class Test_entra_global_admin_in_less_than_five_users: } } + entra_client.users = { + DOMAIN: { + f"User1@{DOMAIN}": User(id=id_user1, name="User1"), + f"User2@{DOMAIN}": User(id=id_user2, name="User2"), + } + } + check = entra_global_admin_in_less_than_five_users() result = check.execute() assert len(result) == 1 @@ -91,12 +111,15 @@ class Test_entra_global_admin_in_less_than_five_users: def test_entra_more_than_five_global_admins(self): entra_client = mock.MagicMock - with mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_azure_provider(), - ), mock.patch( - "prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users.entra_client", - new=entra_client, + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users.entra_client", + new=entra_client, + ), ): from prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users import ( entra_global_admin_in_less_than_five_users, @@ -130,6 +153,17 @@ class Test_entra_global_admin_in_less_than_five_users: } } + entra_client.users = { + DOMAIN: { + f"User1@{DOMAIN}": User(id=id_user1, name="User1"), + f"User2@{DOMAIN}": User(id=id_user2, name="User2"), + f"User3@{DOMAIN}": User(id=id_user3, name="User3"), + f"User4@{DOMAIN}": User(id=id_user4, name="User4"), + f"User5@{DOMAIN}": User(id=id_user5, name="User5"), + f"User6@{DOMAIN}": User(id=id_user6, name="User6"), + } + } + check = entra_global_admin_in_less_than_five_users() result = check.execute() assert len(result) == 1 @@ -145,12 +179,15 @@ class Test_entra_global_admin_in_less_than_five_users: def test_entra_exactly_five_global_admins(self): entra_client = mock.MagicMock - with mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_azure_provider(), - ), mock.patch( - "prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users.entra_client", - new=entra_client, + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users.entra_client", + new=entra_client, + ), ): from prowler.providers.azure.services.entra.entra_global_admin_in_less_than_five_users.entra_global_admin_in_less_than_five_users import ( entra_global_admin_in_less_than_five_users, @@ -182,6 +219,16 @@ class Test_entra_global_admin_in_less_than_five_users: } } + entra_client.users = { + DOMAIN: { + f"User1@{DOMAIN}": User(id=id_user1, name="User1"), + f"User2@{DOMAIN}": User(id=id_user2, name="User2"), + f"User3@{DOMAIN}": User(id=id_user3, name="User3"), + f"User4@{DOMAIN}": User(id=id_user4, name="User4"), + f"User5@{DOMAIN}": User(id=id_user5, name="User5"), + } + } + check = entra_global_admin_in_less_than_five_users() result = check.execute() assert len(result) == 1 diff --git a/tests/providers/azure/services/entra/entra_non_privileged_user_has_mfa/entra_non_privileged_user_has_mfa_test.py b/tests/providers/azure/services/entra/entra_non_privileged_user_has_mfa/entra_non_privileged_user_has_mfa_test.py index 481558e6fd..5b05a04ff5 100644 --- a/tests/providers/azure/services/entra/entra_non_privileged_user_has_mfa/entra_non_privileged_user_has_mfa_test.py +++ b/tests/providers/azure/services/entra/entra_non_privileged_user_has_mfa/entra_non_privileged_user_has_mfa_test.py @@ -81,7 +81,7 @@ class Test_entra_non_privileged_user_has_mfa: result[0].status_extended == "Non-privileged user foo does not have MFA." ) - assert result[0].resource_name == f"foo@{DOMAIN}" + assert result[0].resource_name == "foo" assert result[0].resource_id == user_id assert result[0].subscription == f"Tenant: {DOMAIN}" @@ -118,7 +118,7 @@ class Test_entra_non_privileged_user_has_mfa: assert len(result) == 1 assert result[0].status == "PASS" assert result[0].status_extended == "Non-privileged user foo has MFA." - assert result[0].resource_name == f"foo@{DOMAIN}" + assert result[0].resource_name == "foo" assert result[0].resource_id == user_id assert result[0].subscription == f"Tenant: {DOMAIN}" diff --git a/tests/providers/azure/services/entra/entra_privileged_user_has_mfa/entra_privileged_user_has_mfa_test.py b/tests/providers/azure/services/entra/entra_privileged_user_has_mfa/entra_privileged_user_has_mfa_test.py index 551bc5ac21..d3b4863c19 100644 --- a/tests/providers/azure/services/entra/entra_privileged_user_has_mfa/entra_privileged_user_has_mfa_test.py +++ b/tests/providers/azure/services/entra/entra_privileged_user_has_mfa/entra_privileged_user_has_mfa_test.py @@ -144,7 +144,7 @@ class Test_entra_privileged_user_has_mfa: assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].status_extended == "Privileged user foo does not have MFA." - assert result[0].resource_name == f"foo@{DOMAIN}" + assert result[0].resource_name == "foo" assert result[0].resource_id == user_id assert result[0].subscription == f"Tenant: {DOMAIN}" @@ -183,6 +183,6 @@ class Test_entra_privileged_user_has_mfa: assert len(result) == 1 assert result[0].status == "PASS" assert result[0].status_extended == "Privileged user foo has MFA." - assert result[0].resource_name == f"foo@{DOMAIN}" + assert result[0].resource_name == "foo" assert result[0].resource_id == user_id assert result[0].subscription == f"Tenant: {DOMAIN}" diff --git a/tests/providers/azure/services/entra/entra_security_defaults_enabled/entra_security_defaults_enabled_test.py b/tests/providers/azure/services/entra/entra_security_defaults_enabled/entra_security_defaults_enabled_test.py index 406d473037..b1887a7425 100644 --- a/tests/providers/azure/services/entra/entra_security_defaults_enabled/entra_security_defaults_enabled_test.py +++ b/tests/providers/azure/services/entra/entra_security_defaults_enabled/entra_security_defaults_enabled_test.py @@ -47,8 +47,8 @@ class Test_entra_security_defaults_enabled: assert result[0].status == "FAIL" assert result[0].status_extended == "Entra security defaults is diabled." assert result[0].subscription == f"Tenant: {DOMAIN}" - assert result[0].resource_name == "Security Default" - assert result[0].resource_id == "Security Default" + assert result[0].resource_name == "" + assert result[0].resource_id == "" def test_entra_security_default_enabled(self): entra_client = mock.MagicMock diff --git a/tests/providers/azure/services/entra/entra_service_test.py b/tests/providers/azure/services/entra/entra_service_test.py index 9db6c13499..1e2716f65b 100644 --- a/tests/providers/azure/services/entra/entra_service_test.py +++ b/tests/providers/azure/services/entra/entra_service_test.py @@ -61,6 +61,7 @@ async def mock_entra_get_named_locations(_): return { DOMAIN: { "id-1": NamedLocation( + id="id-1", name="Test", ip_ranges_addresses=[], is_trusted=False, diff --git a/tests/providers/azure/services/entra/entra_trusted_named_locations_exists/entra_trusted_named_locations_exists_test.py b/tests/providers/azure/services/entra/entra_trusted_named_locations_exists/entra_trusted_named_locations_exists_test.py index cd7aba739c..6aacab9bc2 100644 --- a/tests/providers/azure/services/entra/entra_trusted_named_locations_exists/entra_trusted_named_locations_exists_test.py +++ b/tests/providers/azure/services/entra/entra_trusted_named_locations_exists/entra_trusted_named_locations_exists_test.py @@ -7,12 +7,15 @@ class Test_entra_trusted_named_locations_exists: def test_entra_no_tenants(self): entra_client = mock.MagicMock - with mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_azure_provider(), - ), mock.patch( - "prowler.providers.azure.services.entra.entra_trusted_named_locations_exists.entra_trusted_named_locations_exists.entra_client", - new=entra_client, + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.entra.entra_trusted_named_locations_exists.entra_trusted_named_locations_exists.entra_client", + new=entra_client, + ), ): from prowler.providers.azure.services.entra.entra_trusted_named_locations_exists.entra_trusted_named_locations_exists import ( entra_trusted_named_locations_exists, @@ -27,12 +30,15 @@ class Test_entra_trusted_named_locations_exists: def test_entra_tenant_empty(self): entra_client = mock.MagicMock - with mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_azure_provider(), - ), mock.patch( - "prowler.providers.azure.services.entra.entra_trusted_named_locations_exists.entra_trusted_named_locations_exists.entra_client", - new=entra_client, + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.entra.entra_trusted_named_locations_exists.entra_trusted_named_locations_exists.entra_client", + new=entra_client, + ), ): from prowler.providers.azure.services.entra.entra_trusted_named_locations_exists.entra_trusted_named_locations_exists import ( entra_trusted_named_locations_exists, @@ -55,12 +61,15 @@ class Test_entra_trusted_named_locations_exists: def test_entra_named_location_with_ip_ranges(self): entra_client = mock.MagicMock - with mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_azure_provider(), - ), mock.patch( - "prowler.providers.azure.services.entra.entra_trusted_named_locations_exists.entra_trusted_named_locations_exists.entra_client", - new=entra_client, + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.entra.entra_trusted_named_locations_exists.entra_trusted_named_locations_exists.entra_client", + new=entra_client, + ), ): from prowler.providers.azure.services.entra.entra_service import ( NamedLocation, @@ -72,6 +81,7 @@ class Test_entra_trusted_named_locations_exists: entra_client.named_locations = { DOMAIN: { "location_id": NamedLocation( + id="location_id", name="Test Location", ip_ranges_addresses=["192.168.0.1/24"], is_trusted=True, @@ -94,12 +104,15 @@ class Test_entra_trusted_named_locations_exists: def test_entra_named_location_without_ip_ranges(self): entra_client = mock.MagicMock - with mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_azure_provider(), - ), mock.patch( - "prowler.providers.azure.services.entra.entra_trusted_named_locations_exists.entra_trusted_named_locations_exists.entra_client", - new=entra_client, + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.entra.entra_trusted_named_locations_exists.entra_trusted_named_locations_exists.entra_client", + new=entra_client, + ), ): from prowler.providers.azure.services.entra.entra_service import ( NamedLocation, @@ -111,7 +124,10 @@ class Test_entra_trusted_named_locations_exists: entra_client.named_locations = { DOMAIN: { "location_id": NamedLocation( - name="Test Location", ip_ranges_addresses=[], is_trusted=True + id="location_id", + name="Test Location", + ip_ranges_addresses=[], + is_trusted=True, ) } } @@ -125,18 +141,21 @@ class Test_entra_trusted_named_locations_exists: == "There is no trusted location with IP ranges defined." ) assert result[0].subscription == f"Tenant: {DOMAIN}" - assert result[0].resource_name == "Test Location" - assert result[0].resource_id == "location_id" + assert result[0].resource_name == "Named Locations" + assert result[0].resource_id == "Named Locations" def test_entra_new_named_location_with_ip_ranges_not_trusted(self): entra_client = mock.MagicMock - with mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=set_mocked_azure_provider(), - ), mock.patch( - "prowler.providers.azure.services.entra.entra_trusted_named_locations_exists.entra_trusted_named_locations_exists.entra_client", - new=entra_client, + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_azure_provider(), + ), + mock.patch( + "prowler.providers.azure.services.entra.entra_trusted_named_locations_exists.entra_trusted_named_locations_exists.entra_client", + new=entra_client, + ), ): from prowler.providers.azure.services.entra.entra_service import ( NamedLocation, @@ -148,6 +167,7 @@ class Test_entra_trusted_named_locations_exists: entra_client.named_locations = { DOMAIN: { "location_id": NamedLocation( + id="location_id", name="Test Location", ip_ranges_addresses=["192.168.0.1/24"], is_trusted=False, @@ -164,5 +184,5 @@ class Test_entra_trusted_named_locations_exists: == "There is no trusted location with IP ranges defined." ) assert result[0].subscription == f"Tenant: {DOMAIN}" - assert result[0].resource_name == "Test Location" - assert result[0].resource_id == "location_id" + assert result[0].resource_name == "Named Locations" + assert result[0].resource_id == "Named Locations" diff --git a/tests/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa_test.py b/tests/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa_test.py index a2c1ab5e3c..6c60379699 100644 --- a/tests/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa_test.py +++ b/tests/providers/azure/services/entra/entra_user_with_vm_access_has_mfa/entra_user_with_vm_access_has_mfa_test.py @@ -92,7 +92,7 @@ class Test_iam_assignment_priviledge_access_vm_has_mfa: == f"User test can access VMs in subscription {AZURE_SUBSCRIPTION_ID} but it has MFA." ) assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == f"test@{DOMAIN}" + assert result[0].resource_name == "test" assert result[0].resource_id == user_id def test_entra_user_with_vm_access_has_mfa_no_mfa(self): @@ -150,7 +150,7 @@ class Test_iam_assignment_priviledge_access_vm_has_mfa: == f"User test without MFA can access VMs in subscription {AZURE_SUBSCRIPTION_ID}" ) assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == f"test@{DOMAIN}" + assert result[0].resource_name == "test" assert result[0].resource_id == user_id def test_entra_user_with_vm_access_has_mfa_no_user(self):