diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index b593b33cc1..b77f01bc15 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -29,6 +29,10 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add file descriptor limits (`ulimits`) to Docker Compose worker services to prevent `Too many open files` errors [(#10107)](https://github.com/prowler-cloud/prowler/pull/10107) - CIS 6.0 for the AWS provider [(#10127)](https://github.com/prowler-cloud/prowler/pull/10127) +### 🐞 Fixed + +- Standardize resource_id values across Azure checks to use actual Azure resource IDs and prevent duplicate resource entries [(#9994)](https://github.com/prowler-cloud/prowler/pull/9994) + ### 🔄 Changed - Update Azure Monitor service metadata to new format [(#9622)](https://github.com/prowler-cloud/prowler/pull/9622) diff --git a/prowler/providers/azure/services/apim/apim_threat_detection_llm_jacking/apim_threat_detection_llm_jacking.py b/prowler/providers/azure/services/apim/apim_threat_detection_llm_jacking/apim_threat_detection_llm_jacking.py index e511b9859b..c08d4fe954 100644 --- a/prowler/providers/azure/services/apim/apim_threat_detection_llm_jacking/apim_threat_detection_llm_jacking.py +++ b/prowler/providers/azure/services/apim/apim_threat_detection_llm_jacking/apim_threat_detection_llm_jacking.py @@ -97,8 +97,10 @@ class apim_threat_detection_llm_jacking(Check): # 4. If no threats were found after checking all principals, create a single PASS report if not found_potential_llm_jacking_attackers: report = Check_Report_Azure(self.metadata(), resource={}) - report.resource_name = "Azure API Management" - report.resource_id = "Azure API Management" + report.resource_name = subscription + report.resource_id = ( + f"/subscriptions/{apim_client.subscriptions[subscription]}" + ) report.subscription = subscription report.status = "PASS" report.status_extended = f"No potential LLM Jacking attacks detected across all monitored APIM instances in the last {threat_detection_minutes} minutes." diff --git a/prowler/providers/azure/services/appinsights/appinsights_ensure_is_configured/appinsights_ensure_is_configured.py b/prowler/providers/azure/services/appinsights/appinsights_ensure_is_configured/appinsights_ensure_is_configured.py index aa6510804a..c7761c115e 100644 --- a/prowler/providers/azure/services/appinsights/appinsights_ensure_is_configured/appinsights_ensure_is_configured.py +++ b/prowler/providers/azure/services/appinsights/appinsights_ensure_is_configured/appinsights_ensure_is_configured.py @@ -12,8 +12,10 @@ class appinsights_ensure_is_configured(Check): report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.status = "PASS" report.subscription = subscription_name - report.resource_name = "AppInsights" - report.resource_id = "AppInsights" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{appinsights_client.subscriptions[subscription_name]}" + ) report.status_extended = f"There is at least one AppInsight configured in subscription {subscription_name}." if len(components) < 1: diff --git a/prowler/providers/azure/services/defender/defender_ensure_iot_hub_defender_is_on/defender_ensure_iot_hub_defender_is_on.py b/prowler/providers/azure/services/defender/defender_ensure_iot_hub_defender_is_on/defender_ensure_iot_hub_defender_is_on.py index 92b09b100e..e608e09fbd 100644 --- a/prowler/providers/azure/services/defender/defender_ensure_iot_hub_defender_is_on/defender_ensure_iot_hub_defender_is_on.py +++ b/prowler/providers/azure/services/defender/defender_ensure_iot_hub_defender_is_on/defender_ensure_iot_hub_defender_is_on.py @@ -14,8 +14,10 @@ class defender_ensure_iot_hub_defender_is_on(Check): report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.status = "FAIL" report.subscription = subscription_name - report.resource_name = "IoT Hub Defender" - report.resource_id = "IoT Hub Defender" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{defender_client.subscriptions[subscription_name]}" + ) report.status_extended = f"No IoT Security Solutions found in the subscription {subscription_name}." findings.append(report) else: diff --git a/prowler/providers/azure/services/defender/defender_ensure_mcas_is_enabled/defender_ensure_mcas_is_enabled.py b/prowler/providers/azure/services/defender/defender_ensure_mcas_is_enabled/defender_ensure_mcas_is_enabled.py index fb21e4c9d2..4899f2dc06 100644 --- a/prowler/providers/azure/services/defender/defender_ensure_mcas_is_enabled/defender_ensure_mcas_is_enabled.py +++ b/prowler/providers/azure/services/defender/defender_ensure_mcas_is_enabled/defender_ensure_mcas_is_enabled.py @@ -13,8 +13,10 @@ class defender_ensure_mcas_is_enabled(Check): if "MCAS" not in settings: report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.subscription = subscription_name - report.resource_name = "MCAS" - report.resource_id = "MCAS" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{defender_client.subscriptions[subscription_name]}" + ) report.status = "FAIL" report.status_extended = f"Microsoft Defender for Cloud Apps not exists for subscription {subscription_name}." else: @@ -22,7 +24,6 @@ class defender_ensure_mcas_is_enabled(Check): metadata=self.metadata(), resource=settings["MCAS"] ) report.subscription = subscription_name - report.resource_name = "MCAS" if settings["MCAS"].enabled: report.status = "PASS" report.status_extended = f"Microsoft Defender for Cloud Apps is enabled for subscription {subscription_name}." diff --git a/prowler/providers/azure/services/defender/defender_ensure_wdatp_is_enabled/defender_ensure_wdatp_is_enabled.py b/prowler/providers/azure/services/defender/defender_ensure_wdatp_is_enabled/defender_ensure_wdatp_is_enabled.py index 5cc6ebde57..47aa40a904 100644 --- a/prowler/providers/azure/services/defender/defender_ensure_wdatp_is_enabled/defender_ensure_wdatp_is_enabled.py +++ b/prowler/providers/azure/services/defender/defender_ensure_wdatp_is_enabled/defender_ensure_wdatp_is_enabled.py @@ -13,8 +13,10 @@ class defender_ensure_wdatp_is_enabled(Check): if "WDATP" not in settings: report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.subscription = subscription_name - report.resource_name = "WDATP" - report.resource_id = "WDATP" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{defender_client.subscriptions[subscription_name]}" + ) report.status = "FAIL" report.status_extended = f"Microsoft Defender for Endpoint integration not exists for subscription {subscription_name}." else: @@ -22,7 +24,6 @@ class defender_ensure_wdatp_is_enabled(Check): metadata=self.metadata(), resource=settings["WDATP"] ) report.subscription = subscription_name - report.resource_name = "WDATP" if settings["WDATP"].enabled: report.status = "PASS" report.status_extended = f"Microsoft Defender for Endpoint integration is enabled for subscription {subscription_name}." diff --git a/prowler/providers/azure/services/defender/defender_service.py b/prowler/providers/azure/services/defender/defender_service.py index 396899e86d..089a8846d7 100644 --- a/prowler/providers/azure/services/defender/defender_service.py +++ b/prowler/providers/azure/services/defender/defender_service.py @@ -136,6 +136,7 @@ class Defender(AzureService): { setting.name: Setting( resource_id=setting.id, + resource_name=setting.name or setting.id, resource_type=setting.type, kind=setting.kind, enabled=setting.enabled, @@ -311,6 +312,7 @@ class Assesment(BaseModel): class Setting(BaseModel): resource_id: str + resource_name: str resource_type: str kind: str enabled: bool 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 e5a5083f2c..6f8f387697 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 @@ -7,8 +7,10 @@ class entra_conditional_access_policy_require_mfa_for_management_api(Check): def execute(self) -> Check_Report_Azure: findings = [] + tenant_id = entra_client.tenant_ids[0] + for ( - tenant_name, + tenant_domain, conditional_access_policies, ) in entra_client.conditional_access_policy.items(): for policy in conditional_access_policies.values(): @@ -25,7 +27,7 @@ class entra_conditional_access_policy_require_mfa_for_management_api(Check): report = Check_Report_Azure( metadata=self.metadata(), resource=policy ) - report.subscription = f"Tenant: {tenant_name}" + report.subscription = f"Tenant: {tenant_domain}" report.status = "PASS" report.status_extended = ( "Conditional Access Policy requires MFA for management API." @@ -36,9 +38,9 @@ class entra_conditional_access_policy_require_mfa_for_management_api(Check): metadata=self.metadata(), resource=conditional_access_policies, ) - report.subscription = f"Tenant: {tenant_name}" - report.resource_name = "Conditional Access Policy" - report.resource_id = "Conditional Access Policy" + report.subscription = f"Tenant: {tenant_domain}" + report.resource_name = tenant_domain + report.resource_id = tenant_id report.status = "FAIL" report.status_extended = ( "Conditional Access Policy does not require MFA for management API." 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 6387f8d726..f9db7a4e39 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 @@ -10,7 +10,7 @@ class entra_policy_default_users_cannot_create_security_groups(Check): report = Check_Report_Azure(metadata=self.metadata(), resource=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.resource_id = auth_policy.id report.status = "FAIL" report.status_extended = "Non-privileged users are able to create security groups via the Access Panel and the Azure administration portal." 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 5d4115347f..c7148d54aa 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 @@ -10,7 +10,7 @@ class entra_policy_ensure_default_user_cannot_create_apps(Check): report = Check_Report_Azure(metadata=self.metadata(), resource=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.resource_id = auth_policy.id report.status = "FAIL" report.status_extended = "App creation is not disabled for non-admin users." 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 6f621d1042..e9b2944108 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 @@ -10,7 +10,7 @@ class entra_policy_ensure_default_user_cannot_create_tenants(Check): report = Check_Report_Azure(metadata=self.metadata(), resource=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.resource_id = auth_policy.id 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 1a9ffc40af..03742d4580 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 @@ -10,7 +10,7 @@ class entra_policy_guest_invite_only_for_admin_roles(Check): report = Check_Report_Azure(metadata=self.metadata(), resource=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.resource_id = auth_policy.id report.status = "FAIL" report.status_extended = "Guest invitations are not restricted to users with specific administrative roles only." 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 2563c3330b..eb568e4491 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 @@ -11,7 +11,7 @@ class entra_policy_guest_users_access_restrictions(Check): report = Check_Report_Azure(metadata=self.metadata(), resource=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.resource_id = auth_policy.id report.status = "FAIL" report.status_extended = "Guest user access is not restricted to properties and memberships of their own directory objects" 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 882ae71f61..b097626b15 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 @@ -10,7 +10,7 @@ class entra_policy_restricts_user_consent_for_apps(Check): report = Check_Report_Azure(metadata=self.metadata(), resource=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.resource_id = auth_policy.id report.status = "FAIL" report.status_extended = "Entra allows users to consent apps accessing company data on their behalf" 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 ab893e044a..c8ff0d0648 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 @@ -10,7 +10,7 @@ class entra_policy_user_consent_for_verified_apps(Check): report = Check_Report_Azure(metadata=self.metadata(), resource=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.resource_id = auth_policy.id report.status = "PASS" report.status_extended = "Entra does not allow users to consent non-verified apps accessing company data on their behalf." diff --git a/prowler/providers/azure/services/entra/entra_service.py b/prowler/providers/azure/services/entra/entra_service.py index fffd64b976..011ea675b0 100644 --- a/prowler/providers/azure/services/entra/entra_service.py +++ b/prowler/providers/azure/services/entra/entra_service.py @@ -16,6 +16,8 @@ class Entra(AzureService): def __init__(self, provider: AzureProvider): super().__init__(GraphServiceClient, provider) + self.tenant_ids = provider.identity.tenant_ids + created_loop = False try: loop = asyncio.get_running_loop() @@ -214,6 +216,7 @@ class Entra(AzureService): group_settings[tenant].update( { group_setting.id: GroupSetting( + id=group_setting.id, name=getattr(group_setting, "display_name", None), template_id=getattr(group_setting, "template_id", None), settings=[ @@ -434,6 +437,7 @@ class SettingValue(BaseModel): class GroupSetting(BaseModel): + id: str name: Optional[str] = None template_id: Optional[str] = None settings: List[SettingValue] 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 4b930b9c57..29b89cf982 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 @@ -6,27 +6,30 @@ class entra_trusted_named_locations_exists(Check): def execute(self) -> Check_Report_Azure: findings = [] - for tenant, named_locations in entra_client.named_locations.items(): - report = Check_Report_Azure( - metadata=self.metadata(), resource=named_locations - ) - report.status = "FAIL" - report.subscription = f"Tenant: {tenant}" - report.resource_name = "Named Locations" - report.resource_id = "Named Locations" - report.status_extended = ( - "There is no trusted location with IP ranges defined." - ) + tenant_id = entra_client.tenant_ids[0] + + for tenant_domain, named_locations in entra_client.named_locations.items(): + trusted_location_found = False 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=named_location ) - report.subscription = f"Tenant: {tenant}" + report.subscription = f"Tenant: {tenant_domain}" 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 + report.status_extended = f"Trusted location {named_location.name} exists with trusted IP ranges: {[ip_range for ip_range in named_location.ip_ranges_addresses if ip_range]}" + findings.append(report) + trusted_location_found = True - findings.append(report) + if not trusted_location_found: + report = Check_Report_Azure(metadata=self.metadata(), resource={}) + report.status = "FAIL" + report.subscription = f"Tenant: {tenant_domain}" + report.resource_name = tenant_domain + report.resource_id = tenant_id + report.status_extended = ( + "There is no trusted location with IP ranges defined." + ) + findings.append(report) return findings 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 5dc0d7f445..4e9be832d5 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 @@ -6,18 +6,20 @@ class entra_users_cannot_create_microsoft_365_groups(Check): def execute(self) -> Check_Report_Azure: findings = [] - for tenant_domain, group_settings in entra_client.group_settings.items(): - report = Check_Report_Azure( - metadata=self.metadata(), resource=group_settings - ) - report.status = "FAIL" - report.subscription = f"Tenant: {tenant_domain}" - report.resource_name = "Microsoft365 Groups" - report.resource_id = "Microsoft365 Groups" - report.status_extended = "Users can create Microsoft 365 groups." + tenant_id = entra_client.tenant_ids[0] + for tenant_domain, group_settings in entra_client.group_settings.items(): + group_unified_found = False for group_setting in group_settings.values(): if group_setting.name == "Group.Unified": + group_unified_found = True + report = Check_Report_Azure( + metadata=self.metadata(), resource=group_setting + ) + report.subscription = f"Tenant: {tenant_domain}" + report.status = "FAIL" + report.status_extended = "Users can create Microsoft 365 groups." + for setting_value in group_setting.settings: if ( getattr(setting_value, "name", "") == "EnableGroupCreation" @@ -29,6 +31,16 @@ class entra_users_cannot_create_microsoft_365_groups(Check): ) break - findings.append(report) + findings.append(report) + break + + if not group_unified_found: + report = Check_Report_Azure(metadata=self.metadata(), resource={}) + report.subscription = f"Tenant: {tenant_domain}" + report.resource_name = tenant_domain + report.resource_id = tenant_id + report.status = "FAIL" + report.status_extended = "Users can create Microsoft 365 groups." + findings.append(report) return findings diff --git a/prowler/providers/azure/services/monitor/monitor_alert_create_policy_assignment/monitor_alert_create_policy_assignment.py b/prowler/providers/azure/services/monitor/monitor_alert_create_policy_assignment/monitor_alert_create_policy_assignment.py index eeb9da5a24..2a7d99b622 100644 --- a/prowler/providers/azure/services/monitor/monitor_alert_create_policy_assignment/monitor_alert_create_policy_assignment.py +++ b/prowler/providers/azure/services/monitor/monitor_alert_create_policy_assignment/monitor_alert_create_policy_assignment.py @@ -25,8 +25,10 @@ class monitor_alert_create_policy_assignment(Check): else: report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.subscription = subscription_name - report.resource_name = "Monitor" - report.resource_id = "Monitor" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{monitor_client.subscriptions[subscription_name]}" + ) report.status = "FAIL" report.status_extended = f"There is not an alert for creating Policy Assignments in subscription {subscription_name}." diff --git a/prowler/providers/azure/services/monitor/monitor_alert_create_update_nsg/monitor_alert_create_update_nsg.py b/prowler/providers/azure/services/monitor/monitor_alert_create_update_nsg/monitor_alert_create_update_nsg.py index 41df8f0c6c..2decfe40be 100644 --- a/prowler/providers/azure/services/monitor/monitor_alert_create_update_nsg/monitor_alert_create_update_nsg.py +++ b/prowler/providers/azure/services/monitor/monitor_alert_create_update_nsg/monitor_alert_create_update_nsg.py @@ -25,8 +25,10 @@ class monitor_alert_create_update_nsg(Check): else: report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.subscription = subscription_name - report.resource_name = "Monitor" - report.resource_id = "Monitor" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{monitor_client.subscriptions[subscription_name]}" + ) report.status = "FAIL" report.status_extended = f"There is not an alert for creating/updating Network Security Groups in subscription {subscription_name}." diff --git a/prowler/providers/azure/services/monitor/monitor_alert_create_update_public_ip_address_rule/monitor_alert_create_update_public_ip_address_rule.py b/prowler/providers/azure/services/monitor/monitor_alert_create_update_public_ip_address_rule/monitor_alert_create_update_public_ip_address_rule.py index b820380966..bc8f0bc694 100644 --- a/prowler/providers/azure/services/monitor/monitor_alert_create_update_public_ip_address_rule/monitor_alert_create_update_public_ip_address_rule.py +++ b/prowler/providers/azure/services/monitor/monitor_alert_create_update_public_ip_address_rule/monitor_alert_create_update_public_ip_address_rule.py @@ -25,8 +25,10 @@ class monitor_alert_create_update_public_ip_address_rule(Check): else: report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.subscription = subscription_name - report.resource_name = "Monitor" - report.resource_id = "Monitor" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{monitor_client.subscriptions[subscription_name]}" + ) report.status = "FAIL" report.status_extended = f"There is not an alert for creating/updating Public IP address rule in subscription {subscription_name}." diff --git a/prowler/providers/azure/services/monitor/monitor_alert_create_update_security_solution/monitor_alert_create_update_security_solution.py b/prowler/providers/azure/services/monitor/monitor_alert_create_update_security_solution/monitor_alert_create_update_security_solution.py index 09a67006d7..71334a364b 100644 --- a/prowler/providers/azure/services/monitor/monitor_alert_create_update_security_solution/monitor_alert_create_update_security_solution.py +++ b/prowler/providers/azure/services/monitor/monitor_alert_create_update_security_solution/monitor_alert_create_update_security_solution.py @@ -25,8 +25,10 @@ class monitor_alert_create_update_security_solution(Check): else: report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.subscription = subscription_name - report.resource_name = "Monitor" - report.resource_id = "Monitor" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{monitor_client.subscriptions[subscription_name]}" + ) report.status = "FAIL" report.status_extended = f"There is not an alert for creating/updating Security Solution in subscription {subscription_name}." diff --git a/prowler/providers/azure/services/monitor/monitor_alert_create_update_sqlserver_fr/monitor_alert_create_update_sqlserver_fr.py b/prowler/providers/azure/services/monitor/monitor_alert_create_update_sqlserver_fr/monitor_alert_create_update_sqlserver_fr.py index c020c558ed..feae49c01d 100644 --- a/prowler/providers/azure/services/monitor/monitor_alert_create_update_sqlserver_fr/monitor_alert_create_update_sqlserver_fr.py +++ b/prowler/providers/azure/services/monitor/monitor_alert_create_update_sqlserver_fr/monitor_alert_create_update_sqlserver_fr.py @@ -25,8 +25,10 @@ class monitor_alert_create_update_sqlserver_fr(Check): else: report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.subscription = subscription_name - report.resource_name = "Monitor" - report.resource_id = "Monitor" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{monitor_client.subscriptions[subscription_name]}" + ) report.status = "FAIL" report.status_extended = f"There is not an alert for creating/updating SQL Server firewall rule in subscription {subscription_name}." diff --git a/prowler/providers/azure/services/monitor/monitor_alert_delete_nsg/monitor_alert_delete_nsg.py b/prowler/providers/azure/services/monitor/monitor_alert_delete_nsg/monitor_alert_delete_nsg.py index 6186d2e4cb..bf4d2eb170 100644 --- a/prowler/providers/azure/services/monitor/monitor_alert_delete_nsg/monitor_alert_delete_nsg.py +++ b/prowler/providers/azure/services/monitor/monitor_alert_delete_nsg/monitor_alert_delete_nsg.py @@ -27,8 +27,10 @@ class monitor_alert_delete_nsg(Check): else: report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.subscription = subscription_name - report.resource_name = "Monitor" - report.resource_id = "Monitor" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{monitor_client.subscriptions[subscription_name]}" + ) report.status = "FAIL" report.status_extended = f"There is not an alert for deleting Network Security Groups in subscription {subscription_name}." diff --git a/prowler/providers/azure/services/monitor/monitor_alert_delete_policy_assignment/monitor_alert_delete_policy_assignment.py b/prowler/providers/azure/services/monitor/monitor_alert_delete_policy_assignment/monitor_alert_delete_policy_assignment.py index 10e6e9e525..cd236de59d 100644 --- a/prowler/providers/azure/services/monitor/monitor_alert_delete_policy_assignment/monitor_alert_delete_policy_assignment.py +++ b/prowler/providers/azure/services/monitor/monitor_alert_delete_policy_assignment/monitor_alert_delete_policy_assignment.py @@ -25,8 +25,10 @@ class monitor_alert_delete_policy_assignment(Check): else: report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.subscription = subscription_name - report.resource_name = "Monitor" - report.resource_id = "Monitor" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{monitor_client.subscriptions[subscription_name]}" + ) report.status = "FAIL" report.status_extended = f"There is not an alert for deleting policy assignment in subscription {subscription_name}." diff --git a/prowler/providers/azure/services/monitor/monitor_alert_delete_public_ip_address_rule/monitor_alert_delete_public_ip_address_rule.py b/prowler/providers/azure/services/monitor/monitor_alert_delete_public_ip_address_rule/monitor_alert_delete_public_ip_address_rule.py index ff9f8de32d..a60a972d65 100644 --- a/prowler/providers/azure/services/monitor/monitor_alert_delete_public_ip_address_rule/monitor_alert_delete_public_ip_address_rule.py +++ b/prowler/providers/azure/services/monitor/monitor_alert_delete_public_ip_address_rule/monitor_alert_delete_public_ip_address_rule.py @@ -25,8 +25,10 @@ class monitor_alert_delete_public_ip_address_rule(Check): else: report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.subscription = subscription_name - report.resource_name = "Monitor" - report.resource_id = "Monitor" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{monitor_client.subscriptions[subscription_name]}" + ) report.status = "FAIL" report.status_extended = f"There is not an alert for deleting public IP address rule in subscription {subscription_name}." diff --git a/prowler/providers/azure/services/monitor/monitor_alert_delete_security_solution/monitor_alert_delete_security_solution.py b/prowler/providers/azure/services/monitor/monitor_alert_delete_security_solution/monitor_alert_delete_security_solution.py index a637e761f0..94b0f510e2 100644 --- a/prowler/providers/azure/services/monitor/monitor_alert_delete_security_solution/monitor_alert_delete_security_solution.py +++ b/prowler/providers/azure/services/monitor/monitor_alert_delete_security_solution/monitor_alert_delete_security_solution.py @@ -25,8 +25,10 @@ class monitor_alert_delete_security_solution(Check): else: report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.subscription = subscription_name - report.resource_name = "Monitor" - report.resource_id = "Monitor" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{monitor_client.subscriptions[subscription_name]}" + ) report.status = "FAIL" report.status_extended = f"There is not an alert for deleting Security Solution in subscription {subscription_name}." diff --git a/prowler/providers/azure/services/monitor/monitor_alert_delete_sqlserver_fr/monitor_alert_delete_sqlserver_fr.py b/prowler/providers/azure/services/monitor/monitor_alert_delete_sqlserver_fr/monitor_alert_delete_sqlserver_fr.py index 04ed052887..7b09098aaf 100644 --- a/prowler/providers/azure/services/monitor/monitor_alert_delete_sqlserver_fr/monitor_alert_delete_sqlserver_fr.py +++ b/prowler/providers/azure/services/monitor/monitor_alert_delete_sqlserver_fr/monitor_alert_delete_sqlserver_fr.py @@ -25,8 +25,10 @@ class monitor_alert_delete_sqlserver_fr(Check): else: report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.subscription = subscription_name - report.resource_name = "Monitor" - report.resource_id = "Monitor" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{monitor_client.subscriptions[subscription_name]}" + ) report.status = "FAIL" report.status_extended = f"There is not an alert for deleting SQL Server firewall rule in subscription {subscription_name}." diff --git a/prowler/providers/azure/services/monitor/monitor_alert_service_health_exists/monitor_alert_service_health_exists.py b/prowler/providers/azure/services/monitor/monitor_alert_service_health_exists/monitor_alert_service_health_exists.py index 94dc9747c3..1a20efcdd3 100644 --- a/prowler/providers/azure/services/monitor/monitor_alert_service_health_exists/monitor_alert_service_health_exists.py +++ b/prowler/providers/azure/services/monitor/monitor_alert_service_health_exists/monitor_alert_service_health_exists.py @@ -38,8 +38,10 @@ class monitor_alert_service_health_exists(Check): else: report = Check_Report_Azure(metadata=self.metadata(), resource={}) report.subscription = subscription_name - report.resource_name = "Monitor" - report.resource_id = "Monitor" + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{monitor_client.subscriptions[subscription_name]}" + ) report.status = "FAIL" report.status_extended = f"There is no activity log alert for Service Health in subscription {subscription_name}." diff --git a/prowler/providers/azure/services/monitor/monitor_diagnostic_setting_with_appropriate_categories/monitor_diagnostic_setting_with_appropriate_categories.py b/prowler/providers/azure/services/monitor/monitor_diagnostic_setting_with_appropriate_categories/monitor_diagnostic_setting_with_appropriate_categories.py index 22e0bd193b..0e5ee3f3ec 100644 --- a/prowler/providers/azure/services/monitor/monitor_diagnostic_setting_with_appropriate_categories/monitor_diagnostic_setting_with_appropriate_categories.py +++ b/prowler/providers/azure/services/monitor/monitor_diagnostic_setting_with_appropriate_categories/monitor_diagnostic_setting_with_appropriate_categories.py @@ -10,44 +10,50 @@ class monitor_diagnostic_setting_with_appropriate_categories(Check): subscription_name, diagnostic_settings, ) in monitor_client.diagnostics_settings.items(): - report = Check_Report_Azure(metadata=self.metadata(), resource={}) - report.subscription = subscription_name - report.resource_name = "Monitor" - report.resource_id = "Monitor" - report.status = "FAIL" - report.status_extended = f"There are no diagnostic settings capturing appropiate categories in subscription {subscription_name}." - administrative_enabled = False - security_enabled = False - service_health_enabled = False - alert_enabled = False + compliant_setting = None + for diagnostic_setting in diagnostic_settings: + administrative_enabled = False + security_enabled = False + alert_enabled = False + policy_enabled = False + for log in diagnostic_setting.logs: if log.category == "Administrative" and log.enabled: administrative_enabled = True if log.category == "Security" and log.enabled: security_enabled = True if log.category == "Alert" and log.enabled: - service_health_enabled = True - if log.category == "Policy" and log.enabled: alert_enabled = True + if log.category == "Policy" and log.enabled: + policy_enabled = True - if ( - administrative_enabled - and security_enabled - and service_health_enabled - and alert_enabled - ): - report.status = "PASS" - report.status_extended = f"There is at least one diagnostic setting capturing appropiate categories in subscription {subscription_name}." - break if ( administrative_enabled and security_enabled - and service_health_enabled and alert_enabled + and policy_enabled ): + compliant_setting = diagnostic_setting break + if compliant_setting: + report = Check_Report_Azure( + metadata=self.metadata(), resource=compliant_setting + ) + report.subscription = subscription_name + report.status = "PASS" + report.status_extended = f"Diagnostic setting {compliant_setting.name} captures appropriate categories in subscription {subscription_name}." + else: + report = Check_Report_Azure(metadata=self.metadata(), resource={}) + report.subscription = subscription_name + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{monitor_client.subscriptions[subscription_name]}" + ) + report.status = "FAIL" + report.status_extended = f"No diagnostic setting captures all appropriate categories (Administrative, Security, Alert, Policy) in subscription {subscription_name}." + findings.append(report) return findings diff --git a/prowler/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists.py b/prowler/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists.py index c78a125b3b..c23e7a2af1 100644 --- a/prowler/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists.py +++ b/prowler/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists.py @@ -10,18 +10,26 @@ class monitor_diagnostic_settings_exists(Check): subscription_name, diagnostic_settings, ) in monitor_client.diagnostics_settings.items(): - report = Check_Report_Azure(metadata=self.metadata(), resource={}) - report.subscription = subscription_name - report.resource_name = "Diagnostic Settings" - report.resource_id = "diagnostic_settings" - report.status = "FAIL" - report.status_extended = ( - f"No diagnostic settings found in subscription {subscription_name}." - ) if diagnostic_settings: + # At least one diagnostic setting exists - report on the first one + diagnostic_setting = diagnostic_settings[0] + report = Check_Report_Azure( + metadata=self.metadata(), resource=diagnostic_setting + ) + report.subscription = subscription_name report.status = "PASS" + report.status_extended = f"Diagnostic setting {diagnostic_setting.name} found in subscription {subscription_name}." + else: + # No diagnostic settings - report on subscription + report = Check_Report_Azure(metadata=self.metadata(), resource={}) + report.subscription = subscription_name + report.resource_name = subscription_name + report.resource_id = ( + f"/subscriptions/{monitor_client.subscriptions[subscription_name]}" + ) + report.status = "FAIL" report.status_extended = ( - f"Diagnostic settings found in subscription {subscription_name}." + f"No diagnostic settings found in subscription {subscription_name}." ) findings.append(report) diff --git a/prowler/providers/azure/services/network/network_bastion_host_exists/network_bastion_host_exists.py b/prowler/providers/azure/services/network/network_bastion_host_exists/network_bastion_host_exists.py index b567066f92..85e815b3ab 100644 --- a/prowler/providers/azure/services/network/network_bastion_host_exists/network_bastion_host_exists.py +++ b/prowler/providers/azure/services/network/network_bastion_host_exists/network_bastion_host_exists.py @@ -7,23 +7,25 @@ class network_bastion_host_exists(Check): findings = [] for subscription, bastion_hosts in network_client.bastion_hosts.items(): if not bastion_hosts: - status = "FAIL" - status_extended = ( + report = Check_Report_Azure(metadata=self.metadata(), resource={}) + report.subscription = subscription + report.resource_name = subscription + report.resource_id = ( + f"/subscriptions/{network_client.subscriptions[subscription]}" + ) + report.status = "FAIL" + report.status_extended = ( f"Bastion Host from subscription {subscription} does not exist" ) + findings.append(report) else: - bastion_names = ", ".join( - [bastion_host.name for bastion_host in bastion_hosts] - ) - status = "PASS" - status_extended = f"Bastion Host from subscription {subscription} available are: {bastion_names}" - - report = Check_Report_Azure(metadata=self.metadata(), resource={}) - report.subscription = subscription - report.resource_name = "Bastion Host" - report.resource_id = "Bastion Host" - report.status = status - report.status_extended = status_extended - findings.append(report) + for bastion_host in bastion_hosts: + report = Check_Report_Azure( + metadata=self.metadata(), resource=bastion_host + ) + report.subscription = subscription + report.status = "PASS" + report.status_extended = f"Bastion Host {bastion_host.name} exists in subscription {subscription}." + findings.append(report) return findings diff --git a/prowler/providers/azure/services/network/network_watcher_enabled/network_watcher_enabled.py b/prowler/providers/azure/services/network/network_watcher_enabled/network_watcher_enabled.py index 06d06ca5fc..5235ac0d73 100644 --- a/prowler/providers/azure/services/network/network_watcher_enabled/network_watcher_enabled.py +++ b/prowler/providers/azure/services/network/network_watcher_enabled/network_watcher_enabled.py @@ -6,23 +6,31 @@ class network_watcher_enabled(Check): def execute(self) -> list[Check_Report_Azure]: findings = [] for subscription, network_watchers in network_client.network_watchers.items(): - report = Check_Report_Azure(metadata=self.metadata(), resource={}) - report.subscription = subscription - report.resource_name = "Network Watcher" - report.location = "global" - report.resource_id = f"/subscriptions/{network_client.subscriptions[subscription]}/resourceGroups/NetworkWatcherRG/providers/Microsoft.Network/networkWatchers/NetworkWatcher_*" - missing_locations = set(network_client.locations[subscription]) - set( network_watcher.location for network_watcher in network_watchers ) if missing_locations: + # Report against the subscription when network watchers are missing + report = Check_Report_Azure(metadata=self.metadata(), resource={}) + report.subscription = subscription + report.resource_name = subscription + report.resource_id = ( + f"/subscriptions/{network_client.subscriptions[subscription]}" + ) + report.location = "global" report.status = "FAIL" report.status_extended = f"Network Watcher is not enabled for the following locations in subscription '{subscription}': {', '.join(missing_locations)}." + findings.append(report) else: - report.status = "PASS" - report.status_extended = f"Network Watcher is enabled for all locations in subscription '{subscription}'." - - findings.append(report) + # Report each network watcher that exists + for network_watcher in network_watchers: + report = Check_Report_Azure( + metadata=self.metadata(), resource=network_watcher + ) + report.subscription = subscription + report.status = "PASS" + report.status_extended = f"Network Watcher {network_watcher.name} is enabled in location {network_watcher.location} in subscription '{subscription}'." + findings.append(report) return findings diff --git a/tests/providers/azure/services/apim/apim_threat_detection_llm_jacking/apim_threat_detection_llm_jacking_test.py b/tests/providers/azure/services/apim/apim_threat_detection_llm_jacking/apim_threat_detection_llm_jacking_test.py index d37385f585..a551b33c7e 100644 --- a/tests/providers/azure/services/apim/apim_threat_detection_llm_jacking/apim_threat_detection_llm_jacking_test.py +++ b/tests/providers/azure/services/apim/apim_threat_detection_llm_jacking/apim_threat_detection_llm_jacking_test.py @@ -184,6 +184,7 @@ class Test_apim_threat_detection_llm_jacking: ) ] } + apim_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} apim_client.audit_config = { "apim_threat_detection_llm_jacking_threshold": 0.9, "apim_threat_detection_llm_jacking_minutes": 1440, @@ -301,6 +302,7 @@ class Test_apim_threat_detection_llm_jacking: ) ] } + apim_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} apim_client.audit_config = { "apim_threat_detection_llm_jacking_threshold": 0.9, "apim_threat_detection_llm_jacking_minutes": 1440, @@ -365,6 +367,7 @@ class Test_apim_threat_detection_llm_jacking: ) ] } + apim_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} apim_client.audit_config = { "apim_threat_detection_llm_jacking_threshold": 0.9, "apim_threat_detection_llm_jacking_minutes": 1440, @@ -436,6 +439,10 @@ class Test_apim_threat_detection_llm_jacking: ) ], } + apim_client.subscriptions = { + AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID, + "another-subscription": "another-subscription-id", + } apim_client.audit_config = { "apim_threat_detection_llm_jacking_threshold": 0.9, "apim_threat_detection_llm_jacking_minutes": 1440, diff --git a/tests/providers/azure/services/appinsights/appinsights_ensure_is_configured/appinsights_ensure_is_configured_test.py b/tests/providers/azure/services/appinsights/appinsights_ensure_is_configured/appinsights_ensure_is_configured_test.py index d948d78c18..4982a718cc 100644 --- a/tests/providers/azure/services/appinsights/appinsights_ensure_is_configured/appinsights_ensure_is_configured_test.py +++ b/tests/providers/azure/services/appinsights/appinsights_ensure_is_configured/appinsights_ensure_is_configured_test.py @@ -33,6 +33,9 @@ class Test_appinsights_ensure_is_configured: def test_no_appinsights(self): appinsights_client = mock.MagicMock appinsights_client.components = {AZURE_SUBSCRIPTION_ID: {}} + appinsights_client.subscriptions = { + AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID + } with ( mock.patch( @@ -53,9 +56,8 @@ class Test_appinsights_ensure_is_configured: assert len(result) == 1 assert result[0].subscription == AZURE_SUBSCRIPTION_ID assert result[0].status == "FAIL" - assert result[0].resource_id == "AppInsights" - assert result[0].resource_name == "AppInsights" - assert result[0].location == "global" + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID assert ( result[0].status_extended == f"There are no AppInsight configured in subscription {AZURE_SUBSCRIPTION_ID}." @@ -66,13 +68,16 @@ class Test_appinsights_ensure_is_configured: appinsights_client.components = { AZURE_SUBSCRIPTION_ID: { "app_id-1": Component( - resource_id="/subscriptions/resource_id", + resource_id=f"/subscriptions/{AZURE_SUBSCRIPTION_ID}/resourceGroups/test-rg/providers/microsoft.insights/components/AppInsightsTest", resource_name="AppInsightsTest", location="westeurope", instrumentation_key="", ) } } + appinsights_client.subscriptions = { + AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID + } with ( mock.patch( @@ -93,8 +98,8 @@ class Test_appinsights_ensure_is_configured: assert len(result) == 1 assert result[0].subscription == AZURE_SUBSCRIPTION_ID assert result[0].status == "PASS" - assert result[0].resource_id == "AppInsights" - assert result[0].resource_name == "AppInsights" + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID assert result[0].location == "global" assert ( result[0].status_extended diff --git a/tests/providers/azure/services/defender/defender_ensure_iot_hub_defender_is_on/defender_ensure_iot_hub_defender_is_on_test.py b/tests/providers/azure/services/defender/defender_ensure_iot_hub_defender_is_on/defender_ensure_iot_hub_defender_is_on_test.py index 0f895117f8..14ae870fdf 100644 --- a/tests/providers/azure/services/defender/defender_ensure_iot_hub_defender_is_on/defender_ensure_iot_hub_defender_is_on_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_iot_hub_defender_is_on/defender_ensure_iot_hub_defender_is_on_test.py @@ -36,6 +36,7 @@ class Test_defender_ensure_iot_hub_defender_is_on: def test_defender_no_iot_hub_solutions(self): defender_client = mock.MagicMock defender_client.iot_security_solutions = {AZURE_SUBSCRIPTION_ID: {}} + defender_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( @@ -59,8 +60,8 @@ class Test_defender_ensure_iot_hub_defender_is_on: result[0].status_extended == f"No IoT Security Solutions found in the subscription {AZURE_SUBSCRIPTION_ID}." ) - assert result[0].resource_name == "IoT Hub Defender" - assert result[0].resource_id == "IoT Hub Defender" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" def test_defender_iot_hub_solution_disabled(self): resource_id = str(uuid4()) diff --git a/tests/providers/azure/services/defender/defender_ensure_mcas_is_enabled/defender_ensure_mcas_is_enabled_test.py b/tests/providers/azure/services/defender/defender_ensure_mcas_is_enabled/defender_ensure_mcas_is_enabled_test.py index 26f7bb880a..5db8eb19a0 100644 --- a/tests/providers/azure/services/defender/defender_ensure_mcas_is_enabled/defender_ensure_mcas_is_enabled_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_mcas_is_enabled/defender_ensure_mcas_is_enabled_test.py @@ -38,6 +38,7 @@ class Test_defender_ensure_mcas_is_enabled: AZURE_SUBSCRIPTION_ID: { "MCAS": Setting( resource_id=resource_id, + resource_name="MCAS", resource_type="Microsoft.Security/locations/settings", kind="DataExportSettings", enabled=False, @@ -78,6 +79,7 @@ class Test_defender_ensure_mcas_is_enabled: AZURE_SUBSCRIPTION_ID: { "MCAS": Setting( resource_id=resource_id, + resource_name="MCAS", resource_type="Microsoft.Security/locations/settings", kind="DataExportSettings", enabled=True, @@ -114,6 +116,7 @@ class Test_defender_ensure_mcas_is_enabled: def test_defender_mcas_no_settings(self): defender_client = mock.MagicMock defender_client.settings = {AZURE_SUBSCRIPTION_ID: {}} + defender_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( @@ -138,5 +141,5 @@ class Test_defender_ensure_mcas_is_enabled: == f"Microsoft Defender for Cloud Apps not exists for subscription {AZURE_SUBSCRIPTION_ID}." ) assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "MCAS" - assert result[0].resource_id == "MCAS" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" diff --git a/tests/providers/azure/services/defender/defender_ensure_wdatp_is_enabled/defender_ensure_wdatp_is_enabled_test.py b/tests/providers/azure/services/defender/defender_ensure_wdatp_is_enabled/defender_ensure_wdatp_is_enabled_test.py index c7d7a120e9..fba1d24ba8 100644 --- a/tests/providers/azure/services/defender/defender_ensure_wdatp_is_enabled/defender_ensure_wdatp_is_enabled_test.py +++ b/tests/providers/azure/services/defender/defender_ensure_wdatp_is_enabled/defender_ensure_wdatp_is_enabled_test.py @@ -38,6 +38,7 @@ class Test_defender_ensure_wdatp_is_enabled: AZURE_SUBSCRIPTION_ID: { "WDATP": Setting( resource_id=resource_id, + resource_name="WDATP", resource_type="Microsoft.Security/locations/settings", kind="DataExportSettings", enabled=False, @@ -78,6 +79,7 @@ class Test_defender_ensure_wdatp_is_enabled: AZURE_SUBSCRIPTION_ID: { "WDATP": Setting( resource_id=resource_id, + resource_name="WDATP", resource_type="Microsoft.Security/locations/settings", kind="DataExportSettings", enabled=True, @@ -114,6 +116,7 @@ class Test_defender_ensure_wdatp_is_enabled: def test_defender_wdatp_no_settings(self): defender_client = mock.MagicMock defender_client.settings = {AZURE_SUBSCRIPTION_ID: {}} + defender_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( @@ -138,5 +141,5 @@ class Test_defender_ensure_wdatp_is_enabled: == f"Microsoft Defender for Endpoint integration not exists for subscription {AZURE_SUBSCRIPTION_ID}." ) assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "WDATP" - assert result[0].resource_id == "WDATP" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" diff --git a/tests/providers/azure/services/defender/defender_service_test.py b/tests/providers/azure/services/defender/defender_service_test.py index 2a05cd8fb1..4308467263 100644 --- a/tests/providers/azure/services/defender/defender_service_test.py +++ b/tests/providers/azure/services/defender/defender_service_test.py @@ -84,6 +84,7 @@ def mock_defender_get_settings(_): AZURE_SUBSCRIPTION_ID: { "MCAS": Setting( resource_id="/subscriptions/resource_id", + resource_name="MCAS", resource_type="Microsoft.Security/locations/settings", kind="DataExportSettings", enabled=True, 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 3c880886ee..4822b5dee4 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 @@ -1,7 +1,11 @@ from unittest import mock from uuid import uuid4 -from tests.providers.azure.azure_fixtures import DOMAIN, set_mocked_azure_provider +from tests.providers.azure.azure_fixtures import ( + DOMAIN, + TENANT_IDS, + set_mocked_azure_provider, +) class Test_entra_conditional_access_policy_require_mfa_for_management_api: @@ -23,6 +27,7 @@ class Test_entra_conditional_access_policy_require_mfa_for_management_api: ) entra_client.conditional_access_policy = {} + entra_client.tenant_ids = TENANT_IDS check = entra_conditional_access_policy_require_mfa_for_management_api() result = check.execute() @@ -45,15 +50,17 @@ class Test_entra_conditional_access_policy_require_mfa_for_management_api: entra_conditional_access_policy_require_mfa_for_management_api, ) + # No policies configured entra_client.conditional_access_policy = {DOMAIN: {}} + entra_client.tenant_ids = TENANT_IDS check = entra_conditional_access_policy_require_mfa_for_management_api() result = check.execute() assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == f"Tenant: {DOMAIN}" - assert result[0].resource_name == "Conditional Access Policy" - assert result[0].resource_id == "Conditional Access Policy" + assert result[0].resource_name == DOMAIN + assert result[0].resource_id == TENANT_IDS[0] assert ( result[0].status_extended == "Conditional Access Policy does not require MFA for management API." @@ -90,14 +97,16 @@ class Test_entra_conditional_access_policy_require_mfa_for_management_api: ) entra_client.conditional_access_policy = {DOMAIN: {policy_id: policy}} + entra_client.tenant_ids = TENANT_IDS check = entra_conditional_access_policy_require_mfa_for_management_api() result = check.execute() assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == f"Tenant: {DOMAIN}" - assert result[0].resource_name == "Conditional Access Policy" - assert result[0].resource_id == "Conditional Access Policy" + # When policy exists but doesn't meet requirements, resource defaults to tenant + assert result[0].resource_name == DOMAIN + assert result[0].resource_id == TENANT_IDS[0] assert ( result[0].status_extended == "Conditional Access Policy does not require MFA for management API." @@ -134,6 +143,7 @@ class Test_entra_conditional_access_policy_require_mfa_for_management_api: ) entra_client.conditional_access_policy = {DOMAIN: {policy_id: policy}} + entra_client.tenant_ids = TENANT_IDS check = entra_conditional_access_policy_require_mfa_for_management_api() result = check.execute() @@ -178,14 +188,16 @@ class Test_entra_conditional_access_policy_require_mfa_for_management_api: ) entra_client.conditional_access_policy = {DOMAIN: {policy_id: policy}} + entra_client.tenant_ids = TENANT_IDS check = entra_conditional_access_policy_require_mfa_for_management_api() result = check.execute() assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == f"Tenant: {DOMAIN}" - assert result[0].resource_name == "Conditional Access Policy" - assert result[0].resource_id == "Conditional Access Policy" + # When policy is disabled, resource defaults to tenant + assert result[0].resource_name == DOMAIN + assert result[0].resource_id == TENANT_IDS[0] assert ( result[0].status_extended == "Conditional Access Policy does not require MFA for management API." @@ -222,14 +234,16 @@ class Test_entra_conditional_access_policy_require_mfa_for_management_api: ) entra_client.conditional_access_policy = {DOMAIN: {policy_id: policy}} + entra_client.tenant_ids = TENANT_IDS check = entra_conditional_access_policy_require_mfa_for_management_api() result = check.execute() assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == f"Tenant: {DOMAIN}" - assert result[0].resource_name == "Conditional Access Policy" - assert result[0].resource_id == "Conditional Access Policy" + # When policy doesn't target management API, resource defaults to tenant + assert result[0].resource_name == DOMAIN + assert result[0].resource_id == TENANT_IDS[0] assert ( result[0].status_extended == "Conditional Access Policy does not require MFA for management API." @@ -266,14 +280,16 @@ class Test_entra_conditional_access_policy_require_mfa_for_management_api: ) entra_client.conditional_access_policy = {DOMAIN: {policy_id: policy}} + entra_client.tenant_ids = TENANT_IDS check = entra_conditional_access_policy_require_mfa_for_management_api() result = check.execute() assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == f"Tenant: {DOMAIN}" - assert result[0].resource_name == "Conditional Access Policy" - assert result[0].resource_id == "Conditional Access Policy" + # When policy doesn't include all users, resource defaults to tenant + assert result[0].resource_name == DOMAIN + assert result[0].resource_id == TENANT_IDS[0] assert ( result[0].status_extended == "Conditional Access Policy does not require MFA for management API." diff --git a/tests/providers/azure/services/entra/entra_policy_default_users_cannot_create_security_groups/entra_policy_default_users_cannot_create_security_groups_test.py b/tests/providers/azure/services/entra/entra_policy_default_users_cannot_create_security_groups/entra_policy_default_users_cannot_create_security_groups_test.py index 6e67d8381e..603fae5863 100644 --- a/tests/providers/azure/services/entra/entra_policy_default_users_cannot_create_security_groups/entra_policy_default_users_cannot_create_security_groups_test.py +++ b/tests/providers/azure/services/entra/entra_policy_default_users_cannot_create_security_groups/entra_policy_default_users_cannot_create_security_groups_test.py @@ -29,7 +29,7 @@ class Test_entra_policy_default_users_cannot_create_security_groups: def test_entra_tenant_empty(self): entra_client = mock.MagicMock - entra_client.authorization_policy = {DOMAIN: {}} + id = str(uuid4()) with ( mock.patch( @@ -44,6 +44,20 @@ class Test_entra_policy_default_users_cannot_create_security_groups: from prowler.providers.azure.services.entra.entra_policy_default_users_cannot_create_security_groups.entra_policy_default_users_cannot_create_security_groups import ( entra_policy_default_users_cannot_create_security_groups, ) + from prowler.providers.azure.services.entra.entra_service import ( + AuthorizationPolicy, + ) + + # Policy with no default user role permissions + entra_client.authorization_policy = { + DOMAIN: AuthorizationPolicy( + id=id, + name="Authorization Policy", + description="Default policy", + guest_invite_settings="everyone", + guest_user_role_id=uuid4(), + ) + } check = entra_policy_default_users_cannot_create_security_groups() result = check.execute() @@ -51,7 +65,7 @@ class Test_entra_policy_default_users_cannot_create_security_groups: assert result[0].status == "FAIL" assert result[0].subscription == f"Tenant: {DOMAIN}" assert result[0].resource_name == "Authorization Policy" - assert result[0].resource_id == "authorizationPolicy" + assert result[0].resource_id == id assert ( result[0].status_extended == "Non-privileged users are able to create security groups via the Access Panel and the Azure administration portal." diff --git a/tests/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_apps/entra_policy_ensure_default_user_cannot_create_apps_test.py b/tests/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_apps/entra_policy_ensure_default_user_cannot_create_apps_test.py index 2dd8dc94bf..d62941388c 100644 --- a/tests/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_apps/entra_policy_ensure_default_user_cannot_create_apps_test.py +++ b/tests/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_apps/entra_policy_ensure_default_user_cannot_create_apps_test.py @@ -30,6 +30,7 @@ class Test_entra_policy_ensure_default_user_cannot_create_apps: def test_entra_tenant_empty(self): entra_client = mock.MagicMock + id = str(uuid4()) with ( mock.patch( @@ -44,8 +45,20 @@ class Test_entra_policy_ensure_default_user_cannot_create_apps: from prowler.providers.azure.services.entra.entra_policy_ensure_default_user_cannot_create_apps.entra_policy_ensure_default_user_cannot_create_apps import ( entra_policy_ensure_default_user_cannot_create_apps, ) + from prowler.providers.azure.services.entra.entra_service import ( + AuthorizationPolicy, + ) - entra_client.authorization_policy = {DOMAIN: {}} + # Policy with no default user role permissions + entra_client.authorization_policy = { + DOMAIN: AuthorizationPolicy( + id=id, + name="Authorization Policy", + description="Default policy", + guest_invite_settings="none", + guest_user_role_id=uuid4(), + ) + } check = entra_policy_ensure_default_user_cannot_create_apps() result = check.execute() @@ -53,7 +66,7 @@ class Test_entra_policy_ensure_default_user_cannot_create_apps: assert result[0].status == "FAIL" assert result[0].subscription == f"Tenant: {DOMAIN}" assert result[0].resource_name == "Authorization Policy" - assert result[0].resource_id == "authorizationPolicy" + assert result[0].resource_id == id assert ( result[0].status_extended == "App creation is not disabled for non-admin users." diff --git a/tests/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants_test.py b/tests/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants_test.py index 7e97b4558d..b9a678bc08 100644 --- a/tests/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants_test.py +++ b/tests/providers/azure/services/entra/entra_policy_ensure_default_user_cannot_create_tenants/entra_policy_ensure_default_user_cannot_create_tenants_test.py @@ -29,7 +29,7 @@ class Test_entra_policy_ensure_default_user_cannot_create_tenants: def test_entra_empty_tenant(self): entra_client = mock.MagicMock - entra_client.authorization_policy = {DOMAIN: {}} + id = str(uuid4()) with ( mock.patch( @@ -44,6 +44,20 @@ class Test_entra_policy_ensure_default_user_cannot_create_tenants: from prowler.providers.azure.services.entra.entra_policy_ensure_default_user_cannot_create_tenants.entra_policy_ensure_default_user_cannot_create_tenants import ( entra_policy_ensure_default_user_cannot_create_tenants, ) + from prowler.providers.azure.services.entra.entra_service import ( + AuthorizationPolicy, + ) + + # Policy with no default user role permissions + entra_client.authorization_policy = { + DOMAIN: AuthorizationPolicy( + id=id, + name="Authorization Policy", + description="Default policy", + guest_invite_settings="everyone", + guest_user_role_id=uuid4(), + ) + } check = entra_policy_ensure_default_user_cannot_create_tenants() result = check.execute() @@ -51,7 +65,7 @@ class Test_entra_policy_ensure_default_user_cannot_create_tenants: assert result[0].status == "FAIL" assert result[0].subscription == f"Tenant: {DOMAIN}" assert result[0].resource_name == "Authorization Policy" - assert result[0].resource_id == "authorizationPolicy" + assert result[0].resource_id == id assert ( result[0].status_extended == "Tenants creation is not disabled for non-admin users." diff --git a/tests/providers/azure/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles_test.py b/tests/providers/azure/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles_test.py index 6c2b3fbe2f..a59c84b6b3 100644 --- a/tests/providers/azure/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles_test.py +++ b/tests/providers/azure/services/entra/entra_policy_guest_invite_only_for_admin_roles/entra_policy_guest_invite_only_for_admin_roles_test.py @@ -30,6 +30,7 @@ class Test_entra_policy_guest_invite_only_for_admin_roles: def test_entra_empty_tenant(self): entra_client = mock.MagicMock + id = str(uuid4()) with ( mock.patch( @@ -44,8 +45,22 @@ class Test_entra_policy_guest_invite_only_for_admin_roles: from prowler.providers.azure.services.entra.entra_policy_guest_invite_only_for_admin_roles.entra_policy_guest_invite_only_for_admin_roles import ( entra_policy_guest_invite_only_for_admin_roles, ) + from prowler.providers.azure.services.entra.entra_service import ( + AuthorizationPolicy, + DefaultUserRolePermissions, + ) - entra_client.authorization_policy = {DOMAIN: {}} + # Policy with default settings (everyone can invite guests) + entra_client.authorization_policy = { + DOMAIN: AuthorizationPolicy( + id=id, + name="Authorization Policy", + description="Default policy", + default_user_role_permissions=DefaultUserRolePermissions(), + guest_invite_settings="everyone", + guest_user_role_id=uuid4(), + ) + } check = entra_policy_guest_invite_only_for_admin_roles() result = check.execute() @@ -53,7 +68,7 @@ class Test_entra_policy_guest_invite_only_for_admin_roles: assert result[0].status == "FAIL" assert result[0].subscription == f"Tenant: {DOMAIN}" assert result[0].resource_name == "Authorization Policy" - assert result[0].resource_id == "authorizationPolicy" + assert result[0].resource_id == id assert ( result[0].status_extended == "Guest invitations are not restricted to users with specific administrative roles only." diff --git a/tests/providers/azure/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions_test.py b/tests/providers/azure/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions_test.py index 8961acf45b..4f70895846 100644 --- a/tests/providers/azure/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions_test.py +++ b/tests/providers/azure/services/entra/entra_policy_guest_users_access_restrictions/entra_policy_guest_users_access_restrictions_test.py @@ -30,6 +30,7 @@ class Test_entra_policy_guest_users_access_restrictions: def test_entra_tenant_empty(self): entra_client = mock.MagicMock + id = str(uuid4()) with ( mock.patch( @@ -44,8 +45,20 @@ class Test_entra_policy_guest_users_access_restrictions: from prowler.providers.azure.services.entra.entra_policy_guest_users_access_restrictions.entra_policy_guest_users_access_restrictions import ( entra_policy_guest_users_access_restrictions, ) + from prowler.providers.azure.services.entra.entra_service import ( + AuthorizationPolicy, + ) - entra_client.authorization_policy = {DOMAIN: {}} + # Policy with guest user role set to same as member (not restricted) + entra_client.authorization_policy = { + DOMAIN: AuthorizationPolicy( + id=id, + name="Authorization Policy", + description="", + guest_invite_settings="none", + guest_user_role_id=UUID("a0b1b346-4d3e-4e8b-98f8-753987be4970"), + ) + } check = entra_policy_guest_users_access_restrictions() result = check.execute() @@ -53,7 +66,7 @@ class Test_entra_policy_guest_users_access_restrictions: assert result[0].status == "FAIL" assert result[0].subscription == f"Tenant: {DOMAIN}" assert result[0].resource_name == "Authorization Policy" - assert result[0].resource_id == "authorizationPolicy" + assert result[0].resource_id == id assert ( result[0].status_extended == "Guest user access is not restricted to properties and memberships of their own directory objects" diff --git a/tests/providers/azure/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps_test.py b/tests/providers/azure/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps_test.py index ecc7433746..36a03cab1d 100644 --- a/tests/providers/azure/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps_test.py +++ b/tests/providers/azure/services/entra/entra_policy_restricts_user_consent_for_apps/entra_policy_restricts_user_consent_for_apps_test.py @@ -30,6 +30,7 @@ class Test_entra_policy_restricts_user_consent_for_apps: def test_entra_tenant_empty(self): entra_client = mock.MagicMock + id = str(uuid4()) with ( mock.patch( @@ -44,8 +45,20 @@ class Test_entra_policy_restricts_user_consent_for_apps: from prowler.providers.azure.services.entra.entra_policy_restricts_user_consent_for_apps.entra_policy_restricts_user_consent_for_apps import ( entra_policy_restricts_user_consent_for_apps, ) + from prowler.providers.azure.services.entra.entra_service import ( + AuthorizationPolicy, + ) - entra_client.authorization_policy = {DOMAIN: {}} + # Policy with no default user role permissions + entra_client.authorization_policy = { + DOMAIN: AuthorizationPolicy( + id=id, + name="Authorization Policy", + description="Default policy", + guest_invite_settings="none", + guest_user_role_id=uuid4(), + ) + } check = entra_policy_restricts_user_consent_for_apps() result = check.execute() @@ -53,7 +66,7 @@ class Test_entra_policy_restricts_user_consent_for_apps: assert result[0].status == "FAIL" assert result[0].subscription == f"Tenant: {DOMAIN}" assert result[0].resource_name == "Authorization Policy" - assert result[0].resource_id == "authorizationPolicy" + assert result[0].resource_id == id assert ( result[0].status_extended == "Entra allows users to consent apps accessing company data on their behalf" diff --git a/tests/providers/azure/services/entra/entra_service_test.py b/tests/providers/azure/services/entra/entra_service_test.py index b038d075b1..8e3a25e59f 100644 --- a/tests/providers/azure/services/entra/entra_service_test.py +++ b/tests/providers/azure/services/entra/entra_service_test.py @@ -41,6 +41,7 @@ async def mock_entra_get_group_settings(_): return { DOMAIN: { "id-1": GroupSetting( + id="id-1", name="Test", template_id="id-group-setting", settings=[], 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 6aacab9bc2..2af5c975cb 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 @@ -1,6 +1,10 @@ from unittest import mock -from tests.providers.azure.azure_fixtures import DOMAIN, set_mocked_azure_provider +from tests.providers.azure.azure_fixtures import ( + DOMAIN, + TENANT_IDS, + set_mocked_azure_provider, +) class Test_entra_trusted_named_locations_exists: @@ -22,6 +26,7 @@ class Test_entra_trusted_named_locations_exists: ) entra_client.named_locations = {} + entra_client.tenant_ids = TENANT_IDS check = entra_trusted_named_locations_exists() result = check.execute() @@ -44,7 +49,9 @@ class Test_entra_trusted_named_locations_exists: entra_trusted_named_locations_exists, ) + # No named locations configured entra_client.named_locations = {DOMAIN: {}} + entra_client.tenant_ids = TENANT_IDS check = entra_trusted_named_locations_exists() result = check.execute() @@ -55,8 +62,8 @@ 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 == "Named Locations" - assert result[0].resource_id == "Named Locations" + assert result[0].resource_name == DOMAIN + assert result[0].resource_id == TENANT_IDS[0] def test_entra_named_location_with_ip_ranges(self): entra_client = mock.MagicMock @@ -88,6 +95,7 @@ class Test_entra_trusted_named_locations_exists: ) } } + entra_client.tenant_ids = TENANT_IDS check = entra_trusted_named_locations_exists() result = check.execute() @@ -95,7 +103,7 @@ class Test_entra_trusted_named_locations_exists: assert result[0].status == "PASS" assert ( result[0].status_extended - == "Exits trusted location with trusted IP ranges, this IPs ranges are: ['192.168.0.1/24']" + == "Trusted location Test Location exists with trusted IP ranges: ['192.168.0.1/24']" ) assert result[0].subscription == f"Tenant: {DOMAIN}" assert result[0].resource_name == "Test Location" @@ -131,6 +139,7 @@ class Test_entra_trusted_named_locations_exists: ) } } + entra_client.tenant_ids = TENANT_IDS check = entra_trusted_named_locations_exists() result = check.execute() @@ -141,8 +150,9 @@ 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 == "Named Locations" - assert result[0].resource_id == "Named Locations" + # When no trusted location found, resource defaults to tenant + assert result[0].resource_name == DOMAIN + assert result[0].resource_id == TENANT_IDS[0] def test_entra_new_named_location_with_ip_ranges_not_trusted(self): entra_client = mock.MagicMock @@ -174,6 +184,7 @@ class Test_entra_trusted_named_locations_exists: ) } } + entra_client.tenant_ids = TENANT_IDS check = entra_trusted_named_locations_exists() result = check.execute() @@ -184,5 +195,6 @@ 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 == "Named Locations" - assert result[0].resource_id == "Named Locations" + # When location exists but is not trusted, resource defaults to tenant + assert result[0].resource_name == DOMAIN + assert result[0].resource_id == TENANT_IDS[0] diff --git a/tests/providers/azure/services/entra/entra_users_cannot_create_microsoft_365_groups/entra_users_cannot_create_microsoft_365_groups_test.py b/tests/providers/azure/services/entra/entra_users_cannot_create_microsoft_365_groups/entra_users_cannot_create_microsoft_365_groups_test.py index 9e28397880..ee82e9a07a 100644 --- a/tests/providers/azure/services/entra/entra_users_cannot_create_microsoft_365_groups/entra_users_cannot_create_microsoft_365_groups_test.py +++ b/tests/providers/azure/services/entra/entra_users_cannot_create_microsoft_365_groups/entra_users_cannot_create_microsoft_365_groups_test.py @@ -1,7 +1,11 @@ from unittest import mock from uuid import uuid4 -from tests.providers.azure.azure_fixtures import DOMAIN, set_mocked_azure_provider +from tests.providers.azure.azure_fixtures import ( + DOMAIN, + TENANT_IDS, + set_mocked_azure_provider, +) class Test_entra_users_cannot_create_microsoft_365_groups: @@ -23,6 +27,7 @@ class Test_entra_users_cannot_create_microsoft_365_groups: ) entra_client.group_settings = {} + entra_client.tenant_ids = TENANT_IDS check = entra_users_cannot_create_microsoft_365_groups() result = check.execute() @@ -45,7 +50,9 @@ class Test_entra_users_cannot_create_microsoft_365_groups: entra_users_cannot_create_microsoft_365_groups, ) + # Empty group settings - no Group.Unified found entra_client.group_settings = {DOMAIN: {}} + entra_client.tenant_ids = TENANT_IDS check = entra_users_cannot_create_microsoft_365_groups() result = check.execute() @@ -53,8 +60,8 @@ class Test_entra_users_cannot_create_microsoft_365_groups: assert result[0].status == "FAIL" assert result[0].status_extended == "Users can create Microsoft 365 groups." assert result[0].subscription == f"Tenant: {DOMAIN}" - assert result[0].resource_name == "Microsoft365 Groups" - assert result[0].resource_id == "Microsoft365 Groups" + assert result[0].resource_name == DOMAIN + assert result[0].resource_id == TENANT_IDS[0] def test_entra_users_cannot_create_microsoft_365_groups(self): entra_client = mock.MagicMock @@ -85,12 +92,14 @@ class Test_entra_users_cannot_create_microsoft_365_groups: entra_client.group_settings = { DOMAIN: { id: GroupSetting( + id=id, name="Group.Unified", template_id=template_id, settings=[setting], ) } } + entra_client.tenant_ids = TENANT_IDS check = entra_users_cannot_create_microsoft_365_groups() result = check.execute() @@ -100,8 +109,8 @@ class Test_entra_users_cannot_create_microsoft_365_groups: result[0].status_extended == "Users cannot create Microsoft 365 groups." ) assert result[0].subscription == f"Tenant: {DOMAIN}" - assert result[0].resource_name == "Microsoft365 Groups" - assert result[0].resource_id == "Microsoft365 Groups" + assert result[0].resource_name == "Group.Unified" + assert result[0].resource_id == id def test_entra_users_can_create_microsoft_365_groups(self): entra_client = mock.MagicMock @@ -132,12 +141,14 @@ class Test_entra_users_cannot_create_microsoft_365_groups: entra_client.group_settings = { DOMAIN: { id: GroupSetting( + id=id, name="Group.Unified", template_id=template_id, settings=[setting], ) } } + entra_client.tenant_ids = TENANT_IDS check = entra_users_cannot_create_microsoft_365_groups() result = check.execute() @@ -145,8 +156,8 @@ class Test_entra_users_cannot_create_microsoft_365_groups: assert result[0].status == "FAIL" assert result[0].status_extended == "Users can create Microsoft 365 groups." assert result[0].subscription == f"Tenant: {DOMAIN}" - assert result[0].resource_name == "Microsoft365 Groups" - assert result[0].resource_id == "Microsoft365 Groups" + assert result[0].resource_name == "Group.Unified" + assert result[0].resource_id == id def test_entra_users_can_create_microsoft_365_groups_no_setting(self): entra_client = mock.MagicMock @@ -174,12 +185,14 @@ class Test_entra_users_cannot_create_microsoft_365_groups: entra_client.group_settings = { DOMAIN: { id: GroupSetting( + id=id, name="Group.Unified", template_id=template_id, settings=[], ) } } + entra_client.tenant_ids = TENANT_IDS check = entra_users_cannot_create_microsoft_365_groups() result = check.execute() @@ -187,5 +200,5 @@ class Test_entra_users_cannot_create_microsoft_365_groups: assert result[0].status == "FAIL" assert result[0].status_extended == "Users can create Microsoft 365 groups." assert result[0].subscription == f"Tenant: {DOMAIN}" - assert result[0].resource_name == "Microsoft365 Groups" - assert result[0].resource_id == "Microsoft365 Groups" + assert result[0].resource_name == "Group.Unified" + assert result[0].resource_id == id diff --git a/tests/providers/azure/services/monitor/monitor_alert_create_policy_assignment/monitor_alert_create_policy_assignment_test.py b/tests/providers/azure/services/monitor/monitor_alert_create_policy_assignment/monitor_alert_create_policy_assignment_test.py index 9c91b432b0..4e380d2c33 100644 --- a/tests/providers/azure/services/monitor/monitor_alert_create_policy_assignment/monitor_alert_create_policy_assignment_test.py +++ b/tests/providers/azure/services/monitor/monitor_alert_create_policy_assignment/monitor_alert_create_policy_assignment_test.py @@ -34,6 +34,7 @@ class Test_monitor_alert_create_policy_assignment: def test_no_alert_rules(self): monitor_client = mock.MagicMock monitor_client.alert_rules = {AZURE_SUBSCRIPTION_ID: []} + monitor_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -53,8 +54,8 @@ class Test_monitor_alert_create_policy_assignment: assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Monitor" - assert result[0].resource_id == "Monitor" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" assert ( result[0].status_extended == f"There is not an alert for creating Policy Assignments in subscription {AZURE_SUBSCRIPTION_ID}." diff --git a/tests/providers/azure/services/monitor/monitor_alert_create_update_nsg/monitor_alert_create_update_nsg_test.py b/tests/providers/azure/services/monitor/monitor_alert_create_update_nsg/monitor_alert_create_update_nsg_test.py index b99e2dfd11..ef620f468b 100644 --- a/tests/providers/azure/services/monitor/monitor_alert_create_update_nsg/monitor_alert_create_update_nsg_test.py +++ b/tests/providers/azure/services/monitor/monitor_alert_create_update_nsg/monitor_alert_create_update_nsg_test.py @@ -33,6 +33,7 @@ class Test_monitor_alert_create_update_nsg: def test_no_alert_rules(self): monitor_client = mock.MagicMock() monitor_client.alert_rules = {AZURE_SUBSCRIPTION_ID: []} + monitor_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -52,8 +53,8 @@ class Test_monitor_alert_create_update_nsg: assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Monitor" - assert result[0].resource_id == "Monitor" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" assert ( result[0].status_extended == f"There is not an alert for creating/updating Network Security Groups in subscription {AZURE_SUBSCRIPTION_ID}." diff --git a/tests/providers/azure/services/monitor/monitor_alert_create_update_public_ip_address_rule/monitor_alert_create_update_public_ip_address_rule_test.py b/tests/providers/azure/services/monitor/monitor_alert_create_update_public_ip_address_rule/monitor_alert_create_update_public_ip_address_rule_test.py index aa2625db35..987532ed24 100644 --- a/tests/providers/azure/services/monitor/monitor_alert_create_update_public_ip_address_rule/monitor_alert_create_update_public_ip_address_rule_test.py +++ b/tests/providers/azure/services/monitor/monitor_alert_create_update_public_ip_address_rule/monitor_alert_create_update_public_ip_address_rule_test.py @@ -33,6 +33,7 @@ class Test_monitor_alert_create_update_security_solution: def test_no_alert_rules(self): monitor_client = mock.MagicMock() monitor_client.alert_rules = {AZURE_SUBSCRIPTION_ID: []} + monitor_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -52,8 +53,8 @@ class Test_monitor_alert_create_update_security_solution: assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Monitor" - assert result[0].resource_id == "Monitor" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" assert ( result[0].status_extended == f"There is not an alert for creating/updating Public IP address rule in subscription {AZURE_SUBSCRIPTION_ID}." diff --git a/tests/providers/azure/services/monitor/monitor_alert_create_update_security_solution/monitor_alert_create_update_security_solution_test.py b/tests/providers/azure/services/monitor/monitor_alert_create_update_security_solution/monitor_alert_create_update_security_solution_test.py index b6b926e463..ba7f475ca3 100644 --- a/tests/providers/azure/services/monitor/monitor_alert_create_update_security_solution/monitor_alert_create_update_security_solution_test.py +++ b/tests/providers/azure/services/monitor/monitor_alert_create_update_security_solution/monitor_alert_create_update_security_solution_test.py @@ -33,6 +33,7 @@ class Test_monitor_alert_create_update_security_solution: def test_no_alert_rules(self): monitor_client = mock.MagicMock() monitor_client.alert_rules = {AZURE_SUBSCRIPTION_ID: []} + monitor_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -52,8 +53,8 @@ class Test_monitor_alert_create_update_security_solution: assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Monitor" - assert result[0].resource_id == "Monitor" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" assert ( result[0].status_extended == f"There is not an alert for creating/updating Security Solution in subscription {AZURE_SUBSCRIPTION_ID}." diff --git a/tests/providers/azure/services/monitor/monitor_alert_create_update_sqlserver_fr/monitor_alert_create_update_sqlserver_fr_test.py b/tests/providers/azure/services/monitor/monitor_alert_create_update_sqlserver_fr/monitor_alert_create_update_sqlserver_fr_test.py index e386357e62..7195e321e3 100644 --- a/tests/providers/azure/services/monitor/monitor_alert_create_update_sqlserver_fr/monitor_alert_create_update_sqlserver_fr_test.py +++ b/tests/providers/azure/services/monitor/monitor_alert_create_update_sqlserver_fr/monitor_alert_create_update_sqlserver_fr_test.py @@ -33,6 +33,7 @@ class Test_monitor_alert_create_update_sqlserver_fr: def test_no_alert_rules(self): monitor_client = mock.MagicMock() monitor_client.alert_rules = {AZURE_SUBSCRIPTION_ID: []} + monitor_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -52,8 +53,8 @@ class Test_monitor_alert_create_update_sqlserver_fr: assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Monitor" - assert result[0].resource_id == "Monitor" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" assert ( result[0].status_extended == f"There is not an alert for creating/updating SQL Server firewall rule in subscription {AZURE_SUBSCRIPTION_ID}." diff --git a/tests/providers/azure/services/monitor/monitor_alert_delete_nsg/monitor_alert_delete_nsg_test.py b/tests/providers/azure/services/monitor/monitor_alert_delete_nsg/monitor_alert_delete_nsg_test.py index 3525ab6a13..161b0de95d 100644 --- a/tests/providers/azure/services/monitor/monitor_alert_delete_nsg/monitor_alert_delete_nsg_test.py +++ b/tests/providers/azure/services/monitor/monitor_alert_delete_nsg/monitor_alert_delete_nsg_test.py @@ -33,6 +33,7 @@ class Test_monitor_alert_delete_nsg: def test_no_alert_rules(self): monitor_client = mock.MagicMock() monitor_client.alert_rules = {AZURE_SUBSCRIPTION_ID: []} + monitor_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -52,8 +53,8 @@ class Test_monitor_alert_delete_nsg: assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Monitor" - assert result[0].resource_id == "Monitor" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" assert ( result[0].status_extended == f"There is not an alert for deleting Network Security Groups in subscription {AZURE_SUBSCRIPTION_ID}." diff --git a/tests/providers/azure/services/monitor/monitor_alert_delete_policy_assignment/monitor_alert_delete_policy_assignment_test.py b/tests/providers/azure/services/monitor/monitor_alert_delete_policy_assignment/monitor_alert_delete_policy_assignment_test.py index 627874eed7..1f52f15480 100644 --- a/tests/providers/azure/services/monitor/monitor_alert_delete_policy_assignment/monitor_alert_delete_policy_assignment_test.py +++ b/tests/providers/azure/services/monitor/monitor_alert_delete_policy_assignment/monitor_alert_delete_policy_assignment_test.py @@ -34,6 +34,7 @@ class Test_monitor_alert_delete_policy_assignment: def test_no_alert_rules(self): monitor_client = mock.MagicMock monitor_client.alert_rules = {AZURE_SUBSCRIPTION_ID: []} + monitor_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -53,8 +54,8 @@ class Test_monitor_alert_delete_policy_assignment: assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Monitor" - assert result[0].resource_id == "Monitor" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" assert ( result[0].status_extended == f"There is not an alert for deleting policy assignment in subscription {AZURE_SUBSCRIPTION_ID}." diff --git a/tests/providers/azure/services/monitor/monitor_alert_delete_public_ip_address_rule/monitor_alert_delete_public_ip_address_rule_test.py b/tests/providers/azure/services/monitor/monitor_alert_delete_public_ip_address_rule/monitor_alert_delete_public_ip_address_rule_test.py index ff217c21ab..79aef33e20 100644 --- a/tests/providers/azure/services/monitor/monitor_alert_delete_public_ip_address_rule/monitor_alert_delete_public_ip_address_rule_test.py +++ b/tests/providers/azure/services/monitor/monitor_alert_delete_public_ip_address_rule/monitor_alert_delete_public_ip_address_rule_test.py @@ -33,6 +33,7 @@ class Test_monitor_alert_create_update_security_solution: def test_no_alert_rules(self): monitor_client = mock.MagicMock() monitor_client.alert_rules = {AZURE_SUBSCRIPTION_ID: []} + monitor_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -52,8 +53,8 @@ class Test_monitor_alert_create_update_security_solution: assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Monitor" - assert result[0].resource_id == "Monitor" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" assert ( result[0].status_extended == f"There is not an alert for deleting public IP address rule in subscription {AZURE_SUBSCRIPTION_ID}." diff --git a/tests/providers/azure/services/monitor/monitor_alert_delete_security_solution/monitor_alert_delete_security_solution_test.py b/tests/providers/azure/services/monitor/monitor_alert_delete_security_solution/monitor_alert_delete_security_solution_test.py index b0da67d639..ba80bfff41 100644 --- a/tests/providers/azure/services/monitor/monitor_alert_delete_security_solution/monitor_alert_delete_security_solution_test.py +++ b/tests/providers/azure/services/monitor/monitor_alert_delete_security_solution/monitor_alert_delete_security_solution_test.py @@ -33,6 +33,7 @@ class Test_monitor_alert_create_update_security_solution: def test_no_alert_rules(self): monitor_client = mock.MagicMock() monitor_client.alert_rules = {AZURE_SUBSCRIPTION_ID: []} + monitor_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -52,8 +53,8 @@ class Test_monitor_alert_create_update_security_solution: assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Monitor" - assert result[0].resource_id == "Monitor" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" assert ( result[0].status_extended == f"There is not an alert for deleting Security Solution in subscription {AZURE_SUBSCRIPTION_ID}." diff --git a/tests/providers/azure/services/monitor/monitor_alert_delete_sqlserver_fr/monitor_alert_delete_sqlserver_fr_test.py b/tests/providers/azure/services/monitor/monitor_alert_delete_sqlserver_fr/monitor_alert_delete_sqlserver_fr_test.py index 43cd769e13..2725fafd19 100644 --- a/tests/providers/azure/services/monitor/monitor_alert_delete_sqlserver_fr/monitor_alert_delete_sqlserver_fr_test.py +++ b/tests/providers/azure/services/monitor/monitor_alert_delete_sqlserver_fr/monitor_alert_delete_sqlserver_fr_test.py @@ -33,6 +33,7 @@ class Test_monitor_alert_delete_sqlserver_fr: def test_no_alert_rules(self): monitor_client = mock.MagicMock() monitor_client.alert_rules = {AZURE_SUBSCRIPTION_ID: []} + monitor_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -52,8 +53,8 @@ class Test_monitor_alert_delete_sqlserver_fr: assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Monitor" - assert result[0].resource_id == "Monitor" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" assert ( result[0].status_extended == f"There is not an alert for deleting SQL Server firewall rule in subscription {AZURE_SUBSCRIPTION_ID}." diff --git a/tests/providers/azure/services/monitor/monitor_alert_service_health_exists/monitor_alert_service_health_exists_test.py b/tests/providers/azure/services/monitor/monitor_alert_service_health_exists/monitor_alert_service_health_exists_test.py index 1d7dbb12b5..3cfd80bedf 100644 --- a/tests/providers/azure/services/monitor/monitor_alert_service_health_exists/monitor_alert_service_health_exists_test.py +++ b/tests/providers/azure/services/monitor/monitor_alert_service_health_exists/monitor_alert_service_health_exists_test.py @@ -31,6 +31,7 @@ class Test_monitor_alert_service_health_exists: def test_no_alert_rules(self): monitor_client = mock.MagicMock() monitor_client.alert_rules = {AZURE_SUBSCRIPTION_ID: []} + monitor_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -50,8 +51,8 @@ class Test_monitor_alert_service_health_exists: assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Monitor" - assert result[0].resource_id == "Monitor" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" assert ( result[0].status_extended == f"There is no activity log alert for Service Health in subscription {AZURE_SUBSCRIPTION_ID}." @@ -151,13 +152,16 @@ class Test_monitor_alert_service_health_exists: ), ] } + monitor_client.subscriptions = { + AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID + } check = monitor_alert_service_health_exists() result = check.execute() assert len(result) == 1 assert result[0].status == "FAIL" assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Monitor" - assert result[0].resource_id == "Monitor" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" assert ( result[0].status_extended == f"There is no activity log alert for Service Health in subscription {AZURE_SUBSCRIPTION_ID}." diff --git a/tests/providers/azure/services/monitor/monitor_diagnostic_setting_with_appropriate_categories/monitor_diagnostic_setting_with_appropriate_categories_test.py b/tests/providers/azure/services/monitor/monitor_diagnostic_setting_with_appropriate_categories/monitor_diagnostic_setting_with_appropriate_categories_test.py index fd3c44f961..56d10199bc 100644 --- a/tests/providers/azure/services/monitor/monitor_diagnostic_setting_with_appropriate_categories/monitor_diagnostic_setting_with_appropriate_categories_test.py +++ b/tests/providers/azure/services/monitor/monitor_diagnostic_setting_with_appropriate_categories/monitor_diagnostic_setting_with_appropriate_categories_test.py @@ -23,7 +23,6 @@ class Test_monitor_diagnostic_setting_with_appropriate_categories: new=monitor_client, ), ): - from prowler.providers.azure.services.monitor.monitor_diagnostic_setting_with_appropriate_categories.monitor_diagnostic_setting_with_appropriate_categories import ( monitor_diagnostic_setting_with_appropriate_categories, ) @@ -35,6 +34,7 @@ class Test_monitor_diagnostic_setting_with_appropriate_categories: def test_no_diagnostic_settings(self): monitor_client = mock.MagicMock monitor_client.diagnostics_settings = {AZURE_SUBSCRIPTION_ID: []} + monitor_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -54,11 +54,11 @@ class Test_monitor_diagnostic_setting_with_appropriate_categories: assert len(result) == 1 assert result[0].subscription == AZURE_SUBSCRIPTION_ID assert result[0].status == "FAIL" - assert result[0].resource_id == "Monitor" - assert result[0].resource_name == "Monitor" + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID assert ( result[0].status_extended - == f"There are no diagnostic settings capturing appropiate categories in subscription {AZURE_SUBSCRIPTION_ID}." + == f"No diagnostic setting captures all appropriate categories (Administrative, Security, Alert, Policy) in subscription {AZURE_SUBSCRIPTION_ID}." ) def test_diagnostic_settings_configured(self): @@ -119,12 +119,14 @@ class Test_monitor_diagnostic_setting_with_appropriate_categories: } check = monitor_diagnostic_setting_with_appropriate_categories() result = check.execute() + # Now returns only one finding per subscription (first compliant setting found) assert len(result) == 1 + # First diagnostic setting has all required categories enabled assert result[0].subscription == AZURE_SUBSCRIPTION_ID assert result[0].status == "PASS" - assert result[0].resource_id == "Monitor" - assert result[0].resource_name == "Monitor" + assert result[0].resource_id == "id" + assert result[0].resource_name == "name" assert ( result[0].status_extended - == f"There is at least one diagnostic setting capturing appropiate categories in subscription {AZURE_SUBSCRIPTION_ID}." + == f"Diagnostic setting name captures appropriate categories in subscription {AZURE_SUBSCRIPTION_ID}." ) diff --git a/tests/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists_test.py b/tests/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists_test.py index 1faff2d267..a4638ffac7 100644 --- a/tests/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists_test.py +++ b/tests/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists_test.py @@ -7,7 +7,6 @@ from tests.providers.azure.azure_fixtures import ( class Test_monitor_diagnostic_settings_exists: - def test_monitor_diagnostic_settings_exists_no_subscriptions( self, ): @@ -35,6 +34,7 @@ class Test_monitor_diagnostic_settings_exists: def test_no_diagnostic_settings(self): monitor_client = mock.MagicMock monitor_client.diagnostics_settings = {AZURE_SUBSCRIPTION_ID: []} + monitor_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -54,6 +54,8 @@ class Test_monitor_diagnostic_settings_exists: assert len(result) == 1 assert result[0].subscription == AZURE_SUBSCRIPTION_ID assert result[0].status == "FAIL" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" assert ( result[0].status_extended == f"No diagnostic settings found in subscription {AZURE_SUBSCRIPTION_ID}." @@ -186,10 +188,13 @@ class Test_monitor_diagnostic_settings_exists: } check = monitor_diagnostic_settings_exists() result = check.execute() + # Now returns only one finding per subscription (first diagnostic setting found) assert len(result) == 1 assert result[0].subscription == AZURE_SUBSCRIPTION_ID assert result[0].status == "PASS" + assert result[0].resource_name == "name" + assert result[0].resource_id == "id" assert ( result[0].status_extended - == f"Diagnostic settings found in subscription {AZURE_SUBSCRIPTION_ID}." + == f"Diagnostic setting name found in subscription {AZURE_SUBSCRIPTION_ID}." ) diff --git a/tests/providers/azure/services/network/network_bastion_host_exists/network_bastion_host_exists_test.py b/tests/providers/azure/services/network/network_bastion_host_exists/network_bastion_host_exists_test.py index cae45b65c0..4d5d1b49f1 100644 --- a/tests/providers/azure/services/network/network_bastion_host_exists/network_bastion_host_exists_test.py +++ b/tests/providers/azure/services/network/network_bastion_host_exists/network_bastion_host_exists_test.py @@ -12,6 +12,7 @@ class Test_network_bastion_host_exists: def test_no_bastion_hosts(self): network_client = mock.MagicMock network_client.bastion_hosts = {AZURE_SUBSCRIPTION_ID: []} + network_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_ID} with ( mock.patch( @@ -40,8 +41,8 @@ class Test_network_bastion_host_exists: == f"Bastion Host from subscription {AZURE_SUBSCRIPTION_ID} does not exist" ) assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Bastion Host" - assert result[0].resource_id == "Bastion Host" + assert result[0].resource_name == AZURE_SUBSCRIPTION_ID + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" def test_network_bastion_host_exists(self): network_client = mock.MagicMock @@ -82,8 +83,8 @@ class Test_network_bastion_host_exists: assert result[0].status == "PASS" assert ( result[0].status_extended - == f"Bastion Host from subscription {AZURE_SUBSCRIPTION_ID} available are: {bastion_host_name}" + == f"Bastion Host {bastion_host_name} exists in subscription {AZURE_SUBSCRIPTION_ID}." ) assert result[0].subscription == AZURE_SUBSCRIPTION_ID - assert result[0].resource_name == "Bastion Host" - assert result[0].resource_id == "Bastion Host" + assert result[0].resource_name == bastion_host_name + assert result[0].resource_id == bastion_host_id diff --git a/tests/providers/azure/services/network/network_watcher_enabled/network_watcher_enabled_test.py b/tests/providers/azure/services/network/network_watcher_enabled/network_watcher_enabled_test.py index c6189c5cf4..aca77ea13e 100644 --- a/tests/providers/azure/services/network/network_watcher_enabled/network_watcher_enabled_test.py +++ b/tests/providers/azure/services/network/network_watcher_enabled/network_watcher_enabled_test.py @@ -84,8 +84,8 @@ class Test_network_watcher_enabled: == f"Network Watcher is not enabled for the following locations in subscription '{AZURE_SUBSCRIPTION_NAME}': location." ) assert result[0].subscription == AZURE_SUBSCRIPTION_NAME - assert result[0].resource_name == network_watcher_name - assert result[0].resource_id == network_watcher_id + assert result[0].resource_name == AZURE_SUBSCRIPTION_NAME + assert result[0].resource_id == f"/subscriptions/{AZURE_SUBSCRIPTION_ID}" assert result[0].location == "global" def test_network_valid_network_watchers(self): @@ -131,9 +131,8 @@ class Test_network_watcher_enabled: assert result[0].status == "PASS" assert ( result[0].status_extended - == f"Network Watcher is enabled for all locations in subscription '{AZURE_SUBSCRIPTION_NAME}'." + == f"Network Watcher {network_watcher_name} is enabled in location location in subscription '{AZURE_SUBSCRIPTION_NAME}'." ) assert result[0].subscription == AZURE_SUBSCRIPTION_NAME assert result[0].resource_name == network_watcher_name assert result[0].resource_id == network_watcher_id - assert result[0].location == "global"