fix(azure): migrate resource models to avoid using SDK defaults (#7043)

Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
This commit is contained in:
Prowler Bot
2025-02-26 10:49:33 +01:00
committed by GitHub
parent ca375dd79c
commit 6491bce5a6
25 changed files with 624 additions and 142 deletions
@@ -2,7 +2,6 @@ from dataclasses import dataclass
from typing import List
from azure.mgmt.containerservice import ContainerServiceClient
from azure.mgmt.containerservice.models import ManagedClusterAgentPoolProfile
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
@@ -42,9 +41,19 @@ class AKS(AzureService):
if getattr(cluster, "network_profile", None)
else None
),
agent_pool_profiles=getattr(
cluster, "agent_pool_profiles", []
),
agent_pool_profiles=[
ManagedClusterAgentPoolProfile(
name=agent_pool_profile.name,
enable_node_public_ip=getattr(
agent_pool_profile,
"enable_node_public_ip",
False,
),
)
for agent_pool_profile in getattr(
cluster, "agent_pool_profiles", []
)
],
rbac_enabled=getattr(cluster, "enable_rbac", False),
)
}
@@ -57,6 +66,12 @@ class AKS(AzureService):
return clusters
@dataclass
class ManagedClusterAgentPoolProfile:
name: str
enable_node_public_ip: bool
@dataclass
class Cluster:
id: str
@@ -1,8 +1,7 @@
from dataclasses import dataclass
from typing import Dict
from dataclasses import dataclass, field
from typing import Dict, List
from azure.mgmt.web import WebSiteManagementClient
from azure.mgmt.web.models import ManagedServiceIdentity, SiteConfigResource
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
@@ -37,6 +36,11 @@ class App(AzureService):
None,
)
# Get app configurations
app_configurations = client.web_apps.get_configuration(
resource_group_name=app.resource_group, name=app.name
)
apps[subscription_name].update(
{
app.id: WebApp(
@@ -47,9 +51,30 @@ class App(AzureService):
if platform_auth
else False
),
configurations=client.web_apps.get_configuration(
resource_group_name=app.resource_group,
name=app.name,
configurations=SiteConfigResource(
id=app_configurations.id,
name=app_configurations.name,
linux_fx_version=getattr(
app_configurations, "linux_fx_version", ""
),
java_version=getattr(
app_configurations, "java_version", ""
),
php_version=getattr(
app_configurations, "php_version", ""
),
python_version=getattr(
app_configurations, "python_version", ""
),
http20_enabled=getattr(
app_configurations, "http20_enabled", False
),
ftps_state=getattr(
app_configurations, "ftps_state", ""
),
min_tls_version=getattr(
app_configurations, "min_tls_version", ""
),
),
client_cert_mode=self._get_client_cert_mode(
getattr(app, "client_cert_enabled", False),
@@ -59,7 +84,21 @@ class App(AzureService):
app.name, app.resource_group, subscription_name
),
https_only=getattr(app, "https_only", False),
identity=getattr(app, "identity", None),
identity=ManagedServiceIdentity(
principal_id=getattr(
getattr(app, "identity", {}),
"principal_id",
"",
),
tenant_id=getattr(
getattr(app, "identity", {}),
"tenant_id",
"",
),
type=getattr(
getattr(app, "identity", {}), "type", ""
),
),
location=app.location,
kind=app.kind,
)
@@ -171,6 +210,26 @@ class App(AzureService):
return monitor_diagnostics_settings
@dataclass
class ManagedServiceIdentity:
principal_id: str
tenant_id: str
type: str
@dataclass
class SiteConfigResource:
id: str
name: str
linux_fx_version: str
java_version: str
php_version: str
python_version: str
http20_enabled: bool
ftps_state: str
min_tls_version: str
@dataclass
class WebApp:
resource_id: str
@@ -181,7 +240,7 @@ class WebApp:
client_cert_mode: str = "Ignore"
auth_enabled: bool = False
https_only: bool = False
monitor_diagnostic_settings: list[DiagnosticSetting] = None
monitor_diagnostic_settings: List[DiagnosticSetting] = field(default_factory=list)
kind: str = "app"
@@ -1,10 +1,6 @@
from dataclasses import dataclass
from azure.mgmt.containerregistry import ContainerRegistryManagementClient
from azure.mgmt.containerregistry.models import (
NetworkRuleSet,
PrivateEndpointConnection,
)
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
@@ -40,7 +36,9 @@ class ContainerRegistry(AzureService):
public_network_access=(
False
if getattr(
registry, "public_network_access" "Enabled"
registry,
"public_network_access_enabled",
"Enabled",
)
== "Disabled"
else True
@@ -54,9 +52,16 @@ class ContainerRegistry(AzureService):
monitor_diagnostic_settings=self._get_registry_monitor_settings(
registry.name, resource_group, subscription
),
private_endpoint_connections=getattr(
registry, "private_endpoint_connections", []
),
private_endpoint_connections=[
PrivateEndpointConnection(
id=pec.id,
name=pec.name,
type=pec.type,
)
for pec in getattr(
registry, "private_endpoint_connections", []
)
],
)
},
)
@@ -90,6 +95,13 @@ class ContainerRegistry(AzureService):
return monitor_diagnostics_settings
@dataclass
class PrivateEndpointConnection:
id: str
name: str
type: str
@dataclass
class ContainerRegistryInfo:
id: str
@@ -100,6 +112,5 @@ class ContainerRegistryInfo:
login_server: str
public_network_access: bool
admin_user_enabled: bool
network_rule_set: NetworkRuleSet
monitor_diagnostic_settings: list[DiagnosticSetting]
private_endpoint_connections: list[PrivateEndpointConnection]
@@ -1,7 +1,7 @@
from dataclasses import dataclass, field
from dataclasses import dataclass
from typing import List
from azure.mgmt.cosmosdb import CosmosDBManagementClient
from azure.mgmt.cosmosdb.models import PrivateEndpointConnection
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
@@ -30,7 +30,14 @@ class CosmosDB(AzureService):
type=account.type,
tags=account.tags,
is_virtual_network_filter_enabled=account.is_virtual_network_filter_enabled,
private_endpoint_connections=account.private_endpoint_connections,
private_endpoint_connections=[
PrivateEndpointConnection(
id=private_endpoint_connection.id,
name=private_endpoint_connection.name,
type=private_endpoint_connection.type,
)
for private_endpoint_connection in account.private_endpoint_connections
],
disable_local_auth=account.disable_local_auth,
)
)
@@ -41,6 +48,13 @@ class CosmosDB(AzureService):
return accounts
@dataclass
class PrivateEndpointConnection:
id: str
name: str
type: str
@dataclass
class Account:
id: str
@@ -50,7 +64,5 @@ class Account:
tags: dict
is_virtual_network_filter_enabled: bool
location: str
private_endpoint_connections: list[PrivateEndpointConnection] = field(
default_factory=list
)
private_endpoint_connections: List[PrivateEndpointConnection]
disable_local_auth: bool = False
@@ -48,7 +48,7 @@ class Entra(AzureService):
for user in users_list.value:
users[tenant].update(
{
user.user_principal_name: User(
user.id: User(
id=user.id,
name=user.display_name,
authentication_methods=[
@@ -261,11 +261,9 @@ class Entra(AzureService):
directory_role.display_name: DirectoryRole(
id=directory_role.id,
members=[
self.users[tenant][member.user_principal_name]
self.users[tenant][member.id]
for member in directory_role_members.value
if self.users[tenant].get(
member.user_principal_name, None
)
if self.users[tenant].get(member.id, None)
],
)
}
@@ -1,7 +1,7 @@
from dataclasses import dataclass
from typing import List
from azure.mgmt.authorization import AuthorizationManagementClient
from azure.mgmt.authorization.v2022_04_01.models import Permission
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
@@ -33,7 +33,16 @@ class IAM(AzureService):
name=role.role_name,
type=role.role_type,
assignable_scopes=role.assignable_scopes,
permissions=role.permissions,
permissions=[
Permission(
condition=getattr(permission, "condition", ""),
condition_version=getattr(
permission, "condition_version", ""
),
actions=getattr(permission, "actions", []),
)
for permission in getattr(role, "permissions", [])
],
)
)
else:
@@ -82,13 +91,20 @@ class IAM(AzureService):
return role_assignments
@dataclass
class Permission:
actions: List[str]
condition: str
condition_version: str
@dataclass
class Role:
id: str
name: str
type: str
assignable_scopes: list[str]
permissions: list[Permission]
assignable_scopes: List[str]
permissions: List[Permission]
@dataclass
@@ -16,11 +16,7 @@ class keyvault_key_expiration_set_in_non_rbac(Check):
report.status_extended = f"Keyvault {keyvault.name} from subscription {subscription} has all the keys with expiration date set."
has_key_without_expiration = False
for key in keyvault.keys:
if (
key.attributes
and not key.attributes.expires
and key.enabled
):
if not key.attributes.expires and key.enabled:
report.status = "FAIL"
report.status_extended = f"Keyvault {keyvault.name} from subscription {subscription} has the key {key.name} without expiration date set."
has_key_without_expiration = True
@@ -19,11 +19,7 @@ class keyvault_non_rbac_secret_expiration_set(Check):
report.status_extended = f"Keyvault {keyvault.name} from subscription {subscription} has all the secrets with expiration date set."
has_secret_without_expiration = False
for secret in keyvault.secrets:
if (
secret.attributes
and not secret.attributes.expires
and secret.enabled
):
if not secret.attributes.expires and secret.enabled:
report.status = "FAIL"
report.status_extended = f"Keyvault {keyvault.name} from subscription {subscription} has the secret {secret.name} without expiration date set."
has_secret_without_expiration = True
@@ -16,11 +16,7 @@ class keyvault_rbac_key_expiration_set(Check):
report.status_extended = f"Keyvault {keyvault.name} from subscription {subscription} has all the keys with expiration date set."
has_key_without_expiration = False
for key in keyvault.keys:
if (
key.attributes
and not key.attributes.expires
and key.enabled
):
if not key.attributes.expires and key.enabled:
report.status = "FAIL"
report.status_extended = f"Keyvault {keyvault.name} from subscription {subscription} has the key {key.name} without expiration date set."
has_key_without_expiration = True
@@ -16,11 +16,7 @@ class keyvault_rbac_secret_expiration_set(Check):
report.status_extended = f"Keyvault {keyvault.name} from subscription {subscription} has all the secrets with expiration date set."
has_secret_without_expiration = False
for secret in keyvault.secrets:
if (
secret.attributes
and not secret.attributes.expires
and secret.enabled
):
if not secret.attributes.expires and secret.enabled:
report.status = "FAIL"
report.status_extended = f"Keyvault {keyvault.name} from subscription {subscription} has the secret {secret.name} without expiration date set."
has_secret_without_expiration = True
@@ -1,13 +1,10 @@
from dataclasses import dataclass
from datetime import datetime
from typing import List, Optional, Union
from azure.core.exceptions import HttpResponseError
from azure.keyvault.keys import KeyClient
from azure.mgmt.keyvault import KeyVaultManagementClient
from azure.mgmt.keyvault.v2023_07_01.models import (
KeyAttributes,
SecretAttributes,
VaultProperties,
)
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
@@ -47,7 +44,30 @@ class KeyVault(AzureService):
name=getattr(keyvault, "name", ""),
location=getattr(keyvault, "location", ""),
resource_group=resource_group,
properties=keyvault_properties,
properties=VaultProperties(
tenant_id=getattr(keyvault_properties, "tenant_id", ""),
enable_rbac_authorization=getattr(
keyvault_properties,
"enable_rbac_authorization",
False,
),
private_endpoint_connections=[
PrivateEndpointConnection(id=conn.id)
for conn in getattr(
keyvault_properties,
"private_endpoint_connections",
[],
)
],
enable_soft_delete=getattr(
keyvault_properties, "enable_soft_delete", False
),
enable_purge_protection=getattr(
keyvault_properties,
"enable_purge_protection",
False,
),
),
keys=keys,
secrets=secrets,
monitor_diagnostic_settings=self._get_vault_monitor_settings(
@@ -74,7 +94,12 @@ class KeyVault(AzureService):
name=getattr(key, "name", ""),
enabled=getattr(key.attributes, "enabled", False),
location=getattr(key, "location", ""),
attributes=getattr(key, "attributes", None),
attributes=KeyAttributes(
enabled=getattr(key.attributes, "enabled", False),
created=getattr(key.attributes, "created", 0),
updated=getattr(key.attributes, "updated", 0),
expires=getattr(key.attributes, "expires", 0),
),
)
)
except Exception as error:
@@ -93,11 +118,17 @@ class KeyVault(AzureService):
policy = key_client.get_key_rotation_policy(prop.name)
for key in keys:
if key.name == prop.name:
key.rotation_policy = policy
key.rotation_policy = KeyRotationPolicy(
id=getattr(policy, "id", ""),
lifetime_actions=[
KeyRotationLifetimeAction(action=action.action)
for action in getattr(policy, "lifetime_actions", [])
],
)
# TODO: handle different errors here since we are catching all HTTP Errors here
except HttpResponseError:
logger.error(
logger.warning(
f"Subscription name: {subscription} -- has no access policy configured for keyvault {keyvault_name}"
)
return keys
@@ -115,7 +146,20 @@ class KeyVault(AzureService):
name=getattr(secret, "name", ""),
enabled=getattr(secret.properties.attributes, "enabled", False),
location=getattr(secret, "location", ""),
attributes=getattr(secret.properties, "attributes", None),
attributes=SecretAttributes(
enabled=getattr(
secret.properties.attributes, "enabled", False
),
created=getattr(
secret.properties.attributes, "created", None
),
updated=getattr(
secret.properties.attributes, "updated", None
),
expires=getattr(
secret.properties.attributes, "expires", None
),
),
)
)
except Exception as error:
@@ -142,6 +186,25 @@ class KeyVault(AzureService):
return monitor_diagnostics_settings
@dataclass
class KeyAttributes:
enabled: bool
created: int
updated: int
expires: int
@dataclass
class KeyRotationLifetimeAction:
action: str
@dataclass
class KeyRotationPolicy:
id: str
lifetime_actions: list[KeyRotationLifetimeAction]
@dataclass
class Key:
id: str
@@ -149,7 +212,15 @@ class Key:
enabled: bool
location: str
attributes: KeyAttributes
rotation_policy: str = None
rotation_policy: Optional[KeyRotationPolicy] = None
@dataclass
class SecretAttributes:
enabled: bool
created: Union[datetime, None]
updated: Union[datetime, None]
expires: Union[datetime, None]
@dataclass
@@ -161,6 +232,20 @@ class Secret:
attributes: SecretAttributes
@dataclass
class PrivateEndpointConnection:
id: str
@dataclass
class VaultProperties:
tenant_id: str
enable_rbac_authorization: bool
private_endpoint_connections: List[PrivateEndpointConnection]
enable_soft_delete: bool
enable_purge_protection: bool
@dataclass
class KeyVaultInfo:
id: str
@@ -1,7 +1,7 @@
from dataclasses import dataclass
from typing import List
from azure.mgmt.monitor import MonitorManagementClient
from azure.mgmt.monitor.models import AlertRuleAllOfCondition, LogSettings
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
@@ -47,7 +47,14 @@ class Monitor(AzureService):
if getattr(setting, "storage_account_id", None)
else None
),
logs=setting.logs,
logs=[
LogSettings(
category=log_settings.category,
category_group=log_settings.category_group,
enabled=log_settings.enabled,
)
for log_settings in getattr(setting, "logs", [])
],
storage_account_id=setting.storage_account_id,
)
)
@@ -69,7 +76,17 @@ class Monitor(AzureService):
AlertRule(
id=rule.id,
name=rule.name,
condition=rule.condition,
condition=AlertRuleAllOfCondition(
all_of=[
AlertRuleAnyOfOrLeafCondition(
field=condition.field,
equals=condition.equals,
)
for condition in getattr(
getattr(rule, "condition", None), "all_of", []
)
]
),
enabled=rule.enabled,
description=rule.description,
)
@@ -81,15 +98,33 @@ class Monitor(AzureService):
return alert_rules
@dataclass
class LogSettings:
category: str
category_group: str
enabled: bool
@dataclass
class DiagnosticSetting:
id: str
storage_account_id: str
storage_account_name: str
logs: LogSettings
logs: List[LogSettings]
name: str
@dataclass
class AlertRuleAnyOfOrLeafCondition:
field: str
equals: str
@dataclass
class AlertRuleAllOfCondition:
all_of: List[AlertRuleAnyOfOrLeafCondition]
@dataclass
class AlertRule:
id: str
@@ -1,4 +1,5 @@
from dataclasses import dataclass
from typing import List
from azure.mgmt.network import NetworkManagementClient
@@ -28,7 +29,24 @@ class Network(AzureService):
id=security_group.id,
name=security_group.name,
location=security_group.location,
security_rules=security_group.security_rules,
security_rules=[
SecurityRule(
id=rule.id,
name=rule.name,
destination_port_range=getattr(
rule, "destination_port_range", ""
),
protocol=getattr(rule, "protocol", ""),
source_address_prefix=getattr(
rule, "source_address_prefix", ""
),
access=getattr(rule, "access", "Allow"),
direction=getattr(rule, "direction", "Inbound"),
)
for rule in getattr(
security_group, "security_rules", []
)
],
)
)
@@ -52,7 +70,9 @@ class Network(AzureService):
id=network_watcher.id,
name=network_watcher.name,
location=network_watcher.location,
flow_logs=flow_logs,
flow_logs=[
FlowLog(id=flow_log.id) for flow_log in flow_logs
],
)
)
@@ -122,12 +142,37 @@ class BastionHost:
location: str
@dataclass
class RetentionPolicy:
enabled: bool = False
days: int = 0
@dataclass
class FlowLog:
id: str
name: str
enabled: bool
retention_policy: RetentionPolicy
@dataclass
class NetworkWatcher:
id: str
name: str
location: str
flow_logs: list
flow_logs: List[FlowLog]
@dataclass
class SecurityRule:
id: str
name: str
destination_port_range: str
protocol: str
source_address_prefix: str
access: str
direction: str
@dataclass
@@ -135,7 +180,7 @@ class SecurityGroup:
id: str
name: str
location: str
security_rules: list
security_rules: List[SecurityRule]
@dataclass
@@ -1,15 +1,7 @@
from dataclasses import dataclass
from typing import List, Optional
from azure.mgmt.sql import SqlManagementClient
from azure.mgmt.sql.models import (
EncryptionProtector,
FirewallRule,
ServerBlobAuditingPolicy,
ServerExternalAdministrator,
ServerSecurityAlertPolicy,
ServerVulnerabilityAssessment,
TransparentDataEncryption,
)
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
@@ -55,7 +47,18 @@ class SQLServer(AzureService):
name=sql_server.name,
public_network_access=sql_server.public_network_access,
minimal_tls_version=sql_server.minimal_tls_version,
administrators=sql_server.administrators,
administrators=ServerExternalAdministrator(
sid=getattr(
getattr(sql_server, "administrators", None),
"sid",
"",
),
administrator_type=getattr(
getattr(sql_server, "administrators", None),
"administrator_type",
"",
),
),
auditing_policies=auditing_policies,
firewall_rules=firewall_rules,
encryption_protector=encryption_protector,
@@ -96,7 +99,16 @@ class SQLServer(AzureService):
server_name=server_name,
encryption_protector_name="current",
)
return encryption_protectors
current_encryption_protector = EncryptionProtector(
id=encryption_protectors.id,
name=encryption_protectors.name,
type=encryption_protectors.type,
server_key_name=encryption_protectors.server_key_name,
server_key_type=encryption_protectors.server_key_type,
)
return current_encryption_protector
def _get_databases(self, subscription, resource_group, server_name):
logger.info("SQL Server - Getting server databases...")
@@ -118,7 +130,13 @@ class SQLServer(AzureService):
type=database.type,
location=database.location,
managed_by=database.managed_by,
tde_encryption=tde_encrypted,
tde_encryption=TransparentDataEncryption(
id=tde_encrypted.id,
name=tde_encrypted.name,
type=tde_encrypted.type,
location=tde_encrypted.location,
status=tde_encrypted.status,
),
)
)
except Exception as error:
@@ -134,7 +152,17 @@ class SQLServer(AzureService):
server_name=server_name,
vulnerability_assessment_name="default",
)
return vulnerability_assessment
return ServerVulnerabilityAssessment(
id=vulnerability_assessment.id,
name=vulnerability_assessment.name,
type=vulnerability_assessment.type,
storage_container_path=vulnerability_assessment.storage_container_path,
recurring_scans=VulnerabilityAssessmentRecurringScans(
is_enabled=vulnerability_assessment.recurring_scans.is_enabled,
emails=vulnerability_assessment.recurring_scans.emails,
email_subscription_admins=vulnerability_assessment.recurring_scans.email_subscription_admins,
),
)
def _get_server_blob_auditing_policies(
self, subscription, resource_group, server_name
@@ -144,14 +172,34 @@ class SQLServer(AzureService):
resource_group_name=resource_group,
server_name=server_name,
)
return auditing_policies
auditing_policies_objects = []
for policy in auditing_policies:
auditing_policies_objects.append(
ServerBlobAuditingPolicy(
id=policy.id,
name=policy.name,
type=policy.type,
state=policy.state,
retention_days=policy.retention_days,
)
)
return auditing_policies_objects
def _get_firewall_rules(self, subscription, resource_group, server_name):
client = self.clients[subscription]
firewall_rules = client.firewall_rules.list_by_server(
resource_group_name=resource_group, server_name=server_name
)
return firewall_rules
firewall_rules_objects = []
for rule in firewall_rules:
firewall_rules_objects.append(
FirewallRule(
name=rule.name,
start_ip_address=rule.start_ip_address,
end_ip_address=rule.end_ip_address,
)
)
return firewall_rules_objects
def _get_server_security_alert_policies(
self, subscription, resource_group, server_name
@@ -162,7 +210,12 @@ class SQLServer(AzureService):
server_name=server_name,
security_alert_policy_name="default",
)
return security_alert_policies
return ServerSecurityAlertPolicy(
id=security_alert_policies.id,
name=security_alert_policies.name,
type=security_alert_policies.type,
state=security_alert_policies.state,
)
def _get_location(self, subscription, resouce_group_name, server_name):
client = self.clients[subscription]
@@ -171,6 +224,15 @@ class SQLServer(AzureService):
return location
@dataclass
class TransparentDataEncryption:
id: str
name: str
type: str
location: str
status: str
@dataclass
class Database:
id: str
@@ -181,6 +243,61 @@ class Database:
tde_encryption: TransparentDataEncryption
@dataclass
class ServerExternalAdministrator:
sid: str
administrator_type: str
@dataclass
class ServerBlobAuditingPolicy:
id: str
name: str
type: str
state: str
retention_days: int
@dataclass
class FirewallRule:
name: str
start_ip_address: str
end_ip_address: str
@dataclass
class EncryptionProtector:
id: str
name: str
type: str
server_key_name: str
server_key_type: str
@dataclass
class VulnerabilityAssessmentRecurringScans:
is_enabled: bool
emails: List[str]
email_subscription_admins: bool
@dataclass
class ServerVulnerabilityAssessment:
id: str
name: str
type: str
storage_container_path: str
recurring_scans: VulnerabilityAssessmentRecurringScans
@dataclass
class ServerSecurityAlertPolicy:
id: str
name: str
type: str
state: str
@dataclass
class Server:
id: str
@@ -188,10 +305,10 @@ class Server:
public_network_access: str
minimal_tls_version: str
administrators: ServerExternalAdministrator
auditing_policies: ServerBlobAuditingPolicy
firewall_rules: FirewallRule
auditing_policies: List[ServerBlobAuditingPolicy]
firewall_rules: List[FirewallRule]
location: str
encryption_protector: EncryptionProtector = None
encryption_protector: Optional[EncryptionProtector] = None
vulnerability_assessment: Optional[ServerVulnerabilityAssessment] = None
security_alert_policies: Optional[ServerSecurityAlertPolicy] = None
databases: list[Database] = None
vulnerability_assessment: ServerVulnerabilityAssessment = None
security_alert_policies: ServerSecurityAlertPolicy = None
@@ -1,11 +1,7 @@
from dataclasses import dataclass
from typing import List, Optional
from azure.mgmt.storage import StorageManagementClient
from azure.mgmt.storage.v2022_09_01.models import (
DeleteRetentionPolicy,
NetworkRuleSet,
PrivateEndpointConnection,
)
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
@@ -45,10 +41,30 @@ class Storage(AzureService):
enable_https_traffic_only=storage_account.enable_https_traffic_only,
infrastructure_encryption=storage_account.encryption.require_infrastructure_encryption,
allow_blob_public_access=storage_account.allow_blob_public_access,
network_rule_set=storage_account.network_rule_set,
network_rule_set=NetworkRuleSet(
bypass=getattr(
storage_account.network_rule_set,
"bypass",
"AzureServices",
),
default_action=getattr(
storage_account.network_rule_set,
"default_action",
"Allow",
),
),
encryption_type=storage_account.encryption.key_source,
minimum_tls_version=storage_account.minimum_tls_version,
private_endpoint_connections=storage_account.private_endpoint_connections,
private_endpoint_connections=[
PrivateEndpointConnection(
id=pec.id,
name=pec.name,
type=pec.type,
)
for pec in getattr(
storage_account, "private_endpoint_connections", []
)
],
key_expiration_period_in_days=key_expiration_period_in_days,
location=storage_account.location,
)
@@ -68,12 +84,22 @@ class Storage(AzureService):
properties = client.blob_services.get_service_properties(
account.resouce_group_name, account.name
)
container_delete_retention_policy = getattr(
properties, "container_delete_retention_policy", None
)
account.blob_properties = BlobProperties(
id=properties.id,
name=properties.name,
type=properties.type,
default_service_version=properties.default_service_version,
container_delete_retention_policy=properties.container_delete_retention_policy,
container_delete_retention_policy=DeleteRetentionPolicy(
enabled=getattr(
container_delete_retention_policy,
"enabled",
False,
),
days=getattr(container_delete_retention_policy, "days", 0),
),
)
except Exception as error:
logger.error(
@@ -81,6 +107,12 @@ class Storage(AzureService):
)
@dataclass
class DeleteRetentionPolicy:
enabled: bool
days: int
@dataclass
class BlobProperties:
id: str
@@ -90,6 +122,19 @@ class BlobProperties:
container_delete_retention_policy: DeleteRetentionPolicy
@dataclass
class NetworkRuleSet:
bypass: str
default_action: str
@dataclass
class PrivateEndpointConnection:
id: str
name: str
type: str
@dataclass
class Account:
id: str
@@ -101,7 +146,7 @@ class Account:
network_rule_set: NetworkRuleSet
encryption_type: str
minimum_tls_version: str
private_endpoint_connections: PrivateEndpointConnection
private_endpoint_connections: List[PrivateEndpointConnection]
key_expiration_period_in_days: str
location: str
blob_properties: BlobProperties = None
blob_properties: Optional[BlobProperties] = None
@@ -1,7 +1,7 @@
from dataclasses import dataclass
from typing import List, Optional
from azure.mgmt.compute import ComputeManagementClient
from azure.mgmt.compute.models import StorageProfile
from prowler.lib.logger import logger
from prowler.providers.azure.azure_provider import AzureProvider
@@ -29,9 +29,32 @@ class VirtualMachines(AzureService):
vm.id: VirtualMachine(
resource_id=vm.id,
resource_name=vm.name,
storage_profile=getattr(vm, "storage_profile", None),
storage_profile=(
StorageProfile(
os_disk=OSDisk(
name=vm.storage_profile.os_disk.name,
managed_disk=vm.storage_profile.os_disk.managed_disk,
),
data_disks=[
DataDisk(
lun=data_disk.lun,
name=data_disk.name,
managed_disk=data_disk.managed_disk,
)
for data_disk in getattr(
vm.storage_profile, "data_disks", []
)
],
)
if getattr(vm, "storage_profile", None)
else None
),
location=vm.location,
security_profile=vm.security_profile,
extensions=[
VirtualMachineExtension(id=extension.id)
for extension in getattr(vm, "resources", [])
],
)
}
)
@@ -90,13 +113,38 @@ class SecurityProfile:
uefi_settings: UefiSettings
@dataclass
class OSDisk:
name: str
managed_disk: bool
@dataclass
class DataDisk:
lun: int
name: str
managed_disk: bool
@dataclass
class StorageProfile:
os_disk: OSDisk
data_disks: List[DataDisk]
@dataclass
class VirtualMachineExtension:
id: str
@dataclass
class VirtualMachine:
resource_id: str
resource_name: str
storage_profile: StorageProfile
location: str
security_profile: SecurityProfile
extensions: list[VirtualMachineExtension]
storage_profile: Optional[StorageProfile] = None
@dataclass
@@ -57,7 +57,6 @@ class TestContainerRegistryAdminUserDisabled:
login_server="mock_login_server.azurecr.io",
public_network_access="Enabled",
admin_user_enabled=True,
network_rule_set=None,
monitor_diagnostic_settings=[],
private_endpoint_connections=[],
)
@@ -114,7 +113,6 @@ class TestContainerRegistryAdminUserDisabled:
login_server="mock_login_server.azurecr.io",
public_network_access="Enabled",
admin_user_enabled=False,
network_rule_set=None,
monitor_diagnostic_settings=[],
private_endpoint_connections=[],
)
@@ -2,8 +2,6 @@ from unittest import mock
from unittest.mock import MagicMock
from uuid import uuid4
from azure.mgmt.containerregistry.models import NetworkRuleSet
from tests.providers.azure.azure_fixtures import (
AZURE_SUBSCRIPTION_ID,
set_mocked_azure_provider,
@@ -59,7 +57,6 @@ class Test_containerregistry_not_publicly_accessible:
login_server="mock_login_server.azurecr.io",
public_network_access=True,
admin_user_enabled=True,
network_rule_set=NetworkRuleSet(default_action="Allow"),
private_endpoint_connections=[],
monitor_diagnostic_settings=[
{
@@ -133,7 +130,6 @@ class Test_containerregistry_not_publicly_accessible:
login_server="mock_login_server.azurecr.io",
public_network_access=False,
admin_user_enabled=False,
network_rule_set=NetworkRuleSet(default_action="Deny"),
private_endpoint_connections=[],
monitor_diagnostic_settings=[
{
@@ -34,7 +34,6 @@ class TestContainerRegistryService:
login_server="mock_login_server.azurecr.io",
public_network_access=False,
admin_user_enabled=True,
network_rule_set=None,
private_endpoint_connections=[],
monitor_diagnostic_settings=[
{
@@ -64,7 +64,6 @@ class Test_containerregistry_uses_private_link:
public_network_access="Enabled",
admin_user_enabled=True,
monitor_diagnostic_settings=[],
network_rule_set=[],
private_endpoint_connections=[],
)
}
@@ -121,7 +120,6 @@ class Test_containerregistry_uses_private_link:
public_network_access="Enabled",
admin_user_enabled=False,
monitor_diagnostic_settings=[],
network_rule_set=[],
private_endpoint_connections=[
PrivateEndpointConnection(
id="/subscriptions/AZURE_SUBSCRIPTION_ID/resourceGroups/mock_resource_group/providers/Microsoft.ContainerRegistry/registries/mock_registry/privateEndpointConnections/myConnection",
@@ -43,6 +43,7 @@ class Test_cosmosdb_account_firewall_use_selected_networks:
tags=None,
disable_local_auth=None,
is_virtual_network_filter_enabled=False,
private_endpoint_connections=[],
)
]
}
@@ -86,6 +87,7 @@ class Test_cosmosdb_account_firewall_use_selected_networks:
tags=None,
disable_local_auth=None,
is_virtual_network_filter_enabled=True,
private_endpoint_connections=[],
)
]
}
@@ -19,6 +19,7 @@ def mock_cosmosdb_get_accounts(_):
tags=None,
is_virtual_network_filter_enabled=None,
disable_local_auth=None,
private_endpoint_connections=[],
)
]
}
@@ -63,6 +63,7 @@ class Test_vm_ensure_using_managed_disks:
v_tpm_enabled=True,
),
),
extensions=[],
storage_profile=mock.MagicMock(
os_disk=mock.MagicMock(
create_option="FromImage",
@@ -114,6 +115,7 @@ class Test_vm_ensure_using_managed_disks:
v_tpm_enabled=True,
),
),
extensions=[],
storage_profile=mock.MagicMock(
os_disk=mock.MagicMock(
create_option="FromImage",
@@ -165,6 +167,7 @@ class Test_vm_ensure_using_managed_disks:
v_tpm_enabled=True,
),
),
extensions=[],
storage_profile=mock.MagicMock(
os_disk=mock.MagicMock(
create_option="FromImage",
@@ -28,6 +28,7 @@ def mock_vm_get_virtual_machines(_):
v_tpm_enabled=True,
),
),
extensions=[],
storage_profile=StorageProfile(
os_disk=OSDisk(
create_option="FromImage",
@@ -11,12 +11,15 @@ class Test_vm_trusted_launch_enabled:
def test_vm_no_subscriptions(self):
vm_client = mock.MagicMock
vm_client.virtual_machines = {}
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
), mock.patch(
"prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled.vm_client",
new=vm_client,
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled.vm_client",
new=vm_client,
),
):
from prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled import (
vm_trusted_launch_enabled,
@@ -29,12 +32,15 @@ class Test_vm_trusted_launch_enabled:
def test_vm_no_vm(self):
vm_client = mock.MagicMock
vm_client.virtual_machines = {AZURE_SUBSCRIPTION_ID: {}}
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
), mock.patch(
"prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled.vm_client",
new=vm_client,
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled.vm_client",
new=vm_client,
),
):
from prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled import (
vm_trusted_launch_enabled,
@@ -47,12 +53,15 @@ class Test_vm_trusted_launch_enabled:
def test_vm_trusted_launch_enabled(self):
vm_id = str(uuid4())
vm_client = mock.MagicMock
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
), mock.patch(
"prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled.vm_client",
new=vm_client,
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled.vm_client",
new=vm_client,
),
):
from prowler.providers.azure.services.vm.vm_service import VirtualMachine
from prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled import (
@@ -72,6 +81,7 @@ class Test_vm_trusted_launch_enabled:
v_tpm_enabled=True,
),
),
extensions=[],
storage_profile=mock.MagicMock(
os_disk=mock.MagicMock(
create_option="FromImage",
@@ -97,12 +107,15 @@ class Test_vm_trusted_launch_enabled:
def test_vm_trusted_launch_disabled(self):
vm_id = str(uuid4())
vm_client = mock.MagicMock
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
), mock.patch(
"prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled.vm_client",
new=vm_client,
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled.vm_client",
new=vm_client,
),
):
from prowler.providers.azure.services.vm.vm_service import VirtualMachine
from prowler.providers.azure.services.vm.vm_trusted_launch_enabled.vm_trusted_launch_enabled import (
@@ -122,6 +135,7 @@ class Test_vm_trusted_launch_enabled:
v_tpm_enabled=False,
),
),
extensions=[],
storage_profile=mock.MagicMock(
os_disk=mock.MagicMock(
create_option="FromImage",