fix(azure): standardize resource_id values across Azure checks (#9994)

This commit is contained in:
Hugo Pereira Brito
2026-02-23 17:53:31 +01:00
committed by GitHub
parent cd12a9451f
commit f7895e206b
64 changed files with 467 additions and 221 deletions
+4
View File
@@ -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)
@@ -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."
@@ -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:
@@ -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:
@@ -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}."
@@ -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}."
@@ -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
@@ -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."
@@ -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."
@@ -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."
@@ -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."
@@ -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."
@@ -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"
@@ -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"
@@ -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."
@@ -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]
@@ -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
@@ -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
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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
@@ -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)
@@ -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
@@ -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
@@ -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,
@@ -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
@@ -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())
@@ -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}"
@@ -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}"
@@ -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,
@@ -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."
@@ -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."
@@ -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."
@@ -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."
@@ -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."
@@ -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"
@@ -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"
@@ -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=[],
@@ -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]
@@ -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
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
@@ -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}."
)
@@ -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}."
)
@@ -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
@@ -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"