From b60b48b948b59a6a81764e38e95f8d0731fd91ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Wed, 7 Feb 2024 16:01:52 +0100 Subject: [PATCH] feat(Azure): Add 4 new checks related to SQLServer and Vulnerability Assessment (#3372) --- .../__init__.py | 0 ...r_microsoft_defender_enabled.metadata.json | 30 +++ .../sqlserver_microsoft_defender_enabled.py | 22 ++ .../services/sqlserver/sqlserver_service.py | 47 +++- ...erver_tde_encryption_enabled.metadata.json | 2 +- .../__init__.py | 0 ...notifications_admins_enabled.metadata.json | 30 +++ ..._va_emails_notifications_admins_enabled.py | 29 ++ .../__init__.py | 0 ...odic_recurring_scans_enabled.metadata.json | 30 +++ ...ver_va_periodic_recurring_scans_enabled.py | 29 ++ .../__init__.py | 0 ...r_va_scan_reports_configured.metadata.json | 30 +++ .../sqlserver_va_scan_reports_configured.py | 37 +++ tests/lib/check/check_test.py | 96 +++++++ ...lserver_microsoft_defender_enabled_test.py | 135 ++++++++++ .../sqlserver/sqlserver_service_test.py | 68 ++++- ...mails_notifications_admins_enabled_test.py | 208 ++++++++++++++ ...a_periodic_recurring_scans_enabled_test.py | 205 ++++++++++++++ ...lserver_va_scan_reports_configured_test.py | 254 ++++++++++++++++++ 20 files changed, 1240 insertions(+), 12 deletions(-) create mode 100644 prowler/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/__init__.py create mode 100644 prowler/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled.metadata.json create mode 100644 prowler/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled.py create mode 100644 prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/__init__.py create mode 100644 prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled.metadata.json create mode 100644 prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled.py create mode 100644 prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/__init__.py create mode 100644 prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled.metadata.json create mode 100644 prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled.py create mode 100644 prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/__init__.py create mode 100644 prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured.metadata.json create mode 100644 prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured.py create mode 100644 tests/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled_test.py create mode 100644 tests/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled_test.py create mode 100644 tests/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled_test.py create mode 100644 tests/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured_test.py diff --git a/prowler/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/__init__.py b/prowler/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/prowler/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled.metadata.json b/prowler/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled.metadata.json new file mode 100644 index 00000000..45e44a1e --- /dev/null +++ b/prowler/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "azure", + "CheckID": "sqlserver_microsoft_defender_enabled", + "CheckTitle": "Ensure that Microsoft Defender for SQL is set to 'On' for critical SQL Servers", + "CheckType": [], + "ServiceName": "sqlserver", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "SQLServer", + "Description": "Ensure that Microsoft Defender for SQL is set to 'On' for critical SQL Servers", + "Risk": "Microsoft Defender for SQL is a unified package for advanced SQL security capabilities. Microsoft Defender is available for Azure SQL Database, Azure SQL Managed classifying sensitive data, surfacing and mitigating potential database vulnerabilities, and detecting anomalous activities that could indicate a threat to your database. It provides a single go-to location for enabling and managing these capabilities.", + "RelatedUrl": "https://docs.microsoft.com/en-us/azure/azure-sql/database/azure-defender-for-sql?view=azuresql", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/SecurityCenter/defender-azure-sql.html", + "Terraform": "" + }, + "Recommendation": { + "Text": "1. Go to SQL servers For each production SQL server instance: 2. Click Microsoft Defender for Cloud 3. Click Enable Microsoft Defender for SQL", + "Url": "https://learn.microsoft.com/en-us/azure/defender-for-cloud/defender-for-sql-usage" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "Microsoft Defender for SQL is a paid feature and will incur additional cost for each SQL server." +} diff --git a/prowler/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled.py b/prowler/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled.py new file mode 100644 index 00000000..69682946 --- /dev/null +++ b/prowler/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled.py @@ -0,0 +1,22 @@ +from prowler.lib.check.models import Check, Check_Report_Azure +from prowler.providers.azure.services.sqlserver.sqlserver_client import sqlserver_client + + +class sqlserver_microsoft_defender_enabled(Check): + def execute(self) -> Check_Report_Azure: + findings = [] + for subscription, sql_servers in sqlserver_client.sql_servers.items(): + for sql_server in sql_servers: + if sql_server.security_alert_policies: + report = Check_Report_Azure(self.metadata()) + report.subscription = subscription + report.resource_name = sql_server.name + report.resource_id = sql_server.id + report.status = "FAIL" + report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has microsoft defender disabled." + if sql_server.security_alert_policies.state == "Enabled": + report.status = "PASS" + report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has microsoft defender enabled." + findings.append(report) + + return findings diff --git a/prowler/providers/azure/services/sqlserver/sqlserver_service.py b/prowler/providers/azure/services/sqlserver/sqlserver_service.py index 5ec264e2..e2dbec89 100644 --- a/prowler/providers/azure/services/sqlserver/sqlserver_service.py +++ b/prowler/providers/azure/services/sqlserver/sqlserver_service.py @@ -6,6 +6,7 @@ from azure.mgmt.sql.models import ( FirewallRule, ServerBlobAuditingPolicy, ServerExternalAdministrator, + ServerSecurityAlertPolicy, ServerVulnerabilityAssessment, TransparentDataEncryption, ) @@ -29,14 +30,11 @@ class SQLServer(AzureService): sql_servers_list = client.servers.list() for sql_server in sql_servers_list: resource_group = self.__get_resource_group__(sql_server.id) - auditing_policies = ( - client.server_blob_auditing_policies.list_by_server( - resource_group_name=resource_group, - server_name=sql_server.name, - ) + auditing_policies = self.__get_server_blob_auditing_policies__( + subscription, resource_group, sql_server.name ) - firewall_rules = client.firewall_rules.list_by_server( - resource_group_name=resource_group, server_name=sql_server.name + firewall_rules = self.__get_firewall_rules__( + subscription, resource_group, sql_server.name ) encryption_protector = self.__get_enctyption_protectors__( subscription, resource_group, sql_server.name @@ -44,6 +42,11 @@ class SQLServer(AzureService): vulnerability_assessment = self.__get_vulnerability_assesments__( subscription, resource_group, sql_server.name ) + security_alert_policies = ( + self.__get_server_security_alert_policies__( + subscription, resource_group, sql_server.name + ) + ) sql_servers[subscription].append( Server( id=sql_server.id, @@ -58,6 +61,7 @@ class SQLServer(AzureService): subscription, resource_group, sql_server.name ), vulnerability_assessment=vulnerability_assessment, + security_alert_policies=security_alert_policies, ) ) except Exception as error: @@ -131,6 +135,34 @@ class SQLServer(AzureService): ) return vulnerability_assessment + def __get_server_blob_auditing_policies__( + self, subscription, resource_group, server_name + ): + client = self.clients[subscription] + auditing_policies = client.server_blob_auditing_policies.list_by_server( + resource_group_name=resource_group, + server_name=server_name, + ) + return auditing_policies + + 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 + + def __get_server_security_alert_policies__( + self, subscription, resource_group, server_name + ): + client = self.clients[subscription] + security_alert_policies = client.server_security_alert_policies.get( + resource_group_name=resource_group, + server_name=server_name, + security_alert_policy_name="default", + ) + return security_alert_policies + @dataclass class Database: @@ -154,3 +186,4 @@ class Server: encryption_protector: EncryptionProtector = None databases: list[Database] = None vulnerability_assessment: ServerVulnerabilityAssessment = None + security_alert_policies: ServerSecurityAlertPolicy = None diff --git a/prowler/providers/azure/services/sqlserver/sqlserver_tde_encryption_enabled/sqlserver_tde_encryption_enabled.metadata.json b/prowler/providers/azure/services/sqlserver/sqlserver_tde_encryption_enabled/sqlserver_tde_encryption_enabled.metadata.json index 4b3b71ec..63be7b0c 100644 --- a/prowler/providers/azure/services/sqlserver/sqlserver_tde_encryption_enabled/sqlserver_tde_encryption_enabled.metadata.json +++ b/prowler/providers/azure/services/sqlserver/sqlserver_tde_encryption_enabled/sqlserver_tde_encryption_enabled.metadata.json @@ -1,6 +1,6 @@ { "Provider": "azure", - "CheckID": "sqlserver_tde_encrypted", + "CheckID": "sqlserver_tde_encryption_enabled", "CheckTitle": "Ensure SQL server's Transparent Data Encryption (TDE) protector is encrypted", "CheckType": [], "ServiceName": "sqlserver", diff --git a/prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/__init__.py b/prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled.metadata.json b/prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled.metadata.json new file mode 100644 index 00000000..23ea66bf --- /dev/null +++ b/prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "azure", + "CheckID": "sqlserver_va_emails_notifications_admins_enabled", + "CheckTitle": "Ensure that Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners' is set for each SQL Server", + "CheckType": [], + "ServiceName": "sqlserver", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "SQLServer", + "Description": "Enable Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners'.", + "Risk": "VA scan reports and alerts will be sent to admins and subscription owners by enabling setting 'Also send email notifications to admins and subscription owners'. This may help in reducing time required for identifying risks and taking corrective measures.", + "RelatedUrl": "https://docs.microsoft.com/en-us/azure/sql-database/sql-vulnerability-assessment", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "https://docs.bridgecrew.io/docs/ensure-that-va-setting-also-send-email-notifications-to-admins-and-subscription-owners-is-set-for-an-sql-server#terraform" + }, + "Recommendation": { + "Text": "1. Go to SQL servers 2. Select a server instance 3. Click on Security Center 4. Select Configure next to Enabled at subscription-level 5. In Section Vulnerability Assessment Settings, configure Storage Accounts if not already 6. Check/enable 'Also send email notifications to admins and subscription owners' 7. Click Save", + "Url": "https://learn.microsoft.com/en-us/azure/defender-for-cloud/sql-azure-vulnerability-assessment-enable" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "Enabling the Microsoft Defender for SQL features will incur additional costs for each SQL server." +} diff --git a/prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled.py b/prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled.py new file mode 100644 index 00000000..304905fd --- /dev/null +++ b/prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled.py @@ -0,0 +1,29 @@ +from prowler.lib.check.models import Check, Check_Report_Azure +from prowler.providers.azure.services.sqlserver.sqlserver_client import sqlserver_client + + +class sqlserver_va_emails_notifications_admins_enabled(Check): + def execute(self) -> Check_Report_Azure: + findings = [] + for subscription, sql_servers in sqlserver_client.sql_servers.items(): + for sql_server in sql_servers: + report = Check_Report_Azure(self.metadata()) + report.subscription = subscription + report.resource_name = sql_server.name + report.resource_id = sql_server.id + report.status = "FAIL" + report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has vulnerability assessment disabled." + if ( + sql_server.vulnerability_assessment + and sql_server.vulnerability_assessment.storage_container_path + ): + report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has vulnerability assessment enabled but no scan reports configured for subscription admins." + if ( + sql_server.vulnerability_assessment.recurring_scans + and sql_server.vulnerability_assessment.recurring_scans.email_subscription_admins + ): + report.status = "PASS" + report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has vulnerability assessment enabled and scan reports configured for subscription admins." + findings.append(report) + + return findings diff --git a/prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/__init__.py b/prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled.metadata.json b/prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled.metadata.json new file mode 100644 index 00000000..3768c575 --- /dev/null +++ b/prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "azure", + "CheckID": "sqlserver_va_periodic_recurring_scans_enabled", + "CheckTitle": "Ensure that Vulnerability Assessment (VA) setting 'Periodic recurring scans' is set to 'on' for each SQL server", + "CheckType": [], + "ServiceName": "sqlserver", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "SQLServer", + "Description": "Enable Vulnerability Assessment (VA) Periodic recurring scans for critical SQL servers and corresponding SQL databases.", + "Risk": "VA setting 'Periodic recurring scans' schedules periodic (weekly) vulnerability scanning for the SQL server and corresponding Databases. Periodic and regular vulnerability scanning provides risk visibility based on updated known vulnerability signatures and best practices.", + "RelatedUrl": "https://docs.microsoft.com/en-us/azure/sql-database/sql-vulnerability-assessment", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/Sql/periodic-vulnerability-scans.html#", + "Terraform": "https://docs.bridgecrew.io/docs/ensure-that-va-setting-periodic-recurring-scans-is-enabled-on-a-sql-server#terraform" + }, + "Recommendation": { + "Text": "1. Go to SQL servers 2. For each server instance 3. Click on Security Center 4. In Section Vulnerability Assessment Settings, set Storage Account if not already 5. Toggle 'Periodic recurring scans' to ON. 6. Click Save", + "Url": "https://learn.microsoft.com/en-us/azure/defender-for-cloud/sql-azure-vulnerability-assessment-enable" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "Enabling the Azure Defender for SQL feature will incur additional costs for each SQL server." +} diff --git a/prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled.py b/prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled.py new file mode 100644 index 00000000..12948248 --- /dev/null +++ b/prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled.py @@ -0,0 +1,29 @@ +from prowler.lib.check.models import Check, Check_Report_Azure +from prowler.providers.azure.services.sqlserver.sqlserver_client import sqlserver_client + + +class sqlserver_va_periodic_recurring_scans_enabled(Check): + def execute(self) -> Check_Report_Azure: + findings = [] + for subscription, sql_servers in sqlserver_client.sql_servers.items(): + for sql_server in sql_servers: + report = Check_Report_Azure(self.metadata()) + report.subscription = subscription + report.resource_name = sql_server.name + report.resource_id = sql_server.id + report.status = "FAIL" + report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has vulnerability assessment disabled." + if ( + sql_server.vulnerability_assessment + and sql_server.vulnerability_assessment.storage_container_path + ): + report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has vulnerability assessment enabled but no recurring scans." + if ( + sql_server.vulnerability_assessment.recurring_scans + and sql_server.vulnerability_assessment.recurring_scans.is_enabled + ): + report.status = "PASS" + report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has periodic recurring scans enabled." + findings.append(report) + + return findings diff --git a/prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/__init__.py b/prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured.metadata.json b/prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured.metadata.json new file mode 100644 index 00000000..0b258db4 --- /dev/null +++ b/prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "azure", + "CheckID": "sqlserver_va_scan_reports_configured", + "CheckTitle": "Ensure that Vulnerability Assessment (VA) setting 'Send scan reports to' is configured for a SQL server", + "CheckType": [], + "ServiceName": "sqlserver", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "SQLServer", + "Description": "Configure 'Send scan reports to' with email addresses of concerned data owners/stakeholders for a critical SQL servers.", + "Risk": "Vulnerability Assessment (VA) scan reports and alerts will be sent to email addresses configured at 'Send scan reports to'. This may help in reducing time required for identifying risks and taking corrective measures", + "RelatedUrl": "https://docs.microsoft.com/en-us/azure/sql-database/sql-vulnerability-assessment", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "https://docs.bridgecrew.io/docs/ensure-that-va-setting-send-scan-reports-to-is-configured-for-a-sql-server#terraform" + }, + "Recommendation": { + "Text": "1. Go to SQL servers 2. Select a server instance 3. Select Microsoft Defender for Cloud 4. Select Configure next to Enablement status 5. Set Microsoft Defender for SQL to On 6. Under Vulnerability Assessment Settings, select a Storage Account 7. Set Periodic recurring scans to On 8. Under Send scan reports to, provide email addresses for data owners and stakeholders 9. Click Save", + "Url": "https://learn.microsoft.com/en-us/azure/defender-for-cloud/sql-azure-vulnerability-assessment-enable" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "Enabling the Microsoft Defender for SQL features will incur additional costs for each SQL server." +} diff --git a/prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured.py b/prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured.py new file mode 100644 index 00000000..0c0ee5a8 --- /dev/null +++ b/prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured.py @@ -0,0 +1,37 @@ +from prowler.lib.check.models import Check, Check_Report_Azure +from prowler.providers.azure.services.sqlserver.sqlserver_client import sqlserver_client + + +class sqlserver_va_scan_reports_configured(Check): + def execute(self) -> Check_Report_Azure: + findings = [] + for subscription, sql_servers in sqlserver_client.sql_servers.items(): + for sql_server in sql_servers: + report = Check_Report_Azure(self.metadata()) + report.subscription = subscription + report.resource_name = sql_server.name + report.resource_id = sql_server.id + report.status = "FAIL" + report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has vulnerability assessment disabled." + if ( + sql_server.vulnerability_assessment + and sql_server.vulnerability_assessment.storage_container_path + ): + report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has vulnerability assessment enabled but no scan reports configured." + if sql_server.vulnerability_assessment.recurring_scans and ( + ( + sql_server.vulnerability_assessment.recurring_scans.email_subscription_admins + ) + or ( + sql_server.vulnerability_assessment.recurring_scans.emails + and len( + sql_server.vulnerability_assessment.recurring_scans.emails + ) + > 0 + ) + ): + report.status = "PASS" + report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has vulnerability assessment enabled and scan reports configured." + findings.append(report) + + return findings diff --git a/tests/lib/check/check_test.py b/tests/lib/check/check_test.py index bfa1d88a..44051753 100644 --- a/tests/lib/check/check_test.py +++ b/tests/lib/check/check_test.py @@ -129,6 +129,48 @@ expected_packages = [ name="prowler.providers.azure.services.sqlserver.sqlserver_vulnerability_assessment_enabled.sqlserver_vulnerability_assessment_enabled", ispkg=False, ), + ModuleInfo( + module_finder=FileFinder( + "/root_dir/prowler/providers/azure/services/sqlserver" + ), + name="prowler.providers.azure.services.sqlserver.sqlserver_va_periodic_recurring_scans_enabled", + ispkg=True, + ), + ModuleInfo( + module_finder=FileFinder( + "/root_dir/prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled" + ), + name="prowler.providers.azure.services.sqlserver.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_va_periodic_recurring_scans_enabled", + ispkg=False, + ), + ModuleInfo( + module_finder=FileFinder( + "/root_dir/prowler/providers/azure/services/sqlserver" + ), + name="prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured", + ispkg=True, + ), + ModuleInfo( + module_finder=FileFinder( + "/root_dir/prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured" + ), + name="prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured.sqlserver_va_scan_reports_configured", + ispkg=False, + ), + ModuleInfo( + module_finder=FileFinder( + "/root_dir/prowler/providers/azure/services/sqlserver" + ), + name="prowler.providers.azure.services.sqlserver.sqlserver_va_emails_notifications_admins_enabled", + ispkg=True, + ), + ModuleInfo( + module_finder=FileFinder( + "/root_dir/prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled" + ), + name="prowler.providers.azure.services.sqlserver.sqlserver_va_emails_notifications_admins_enabled.sqlserver_va_emails_notifications_admins_enabled", + ispkg=False, + ), ] @@ -236,6 +278,48 @@ def mock_list_modules(*_): name="prowler.providers.azure.services.sqlserver.sqlserver_vulnerability_assessment_enabled.sqlserver_vulnerability_assessment_enabled", ispkg=False, ), + ModuleInfo( + module_finder=FileFinder( + "/root_dir/prowler/providers/azure/services/sqlserver" + ), + name="prowler.providers.azure.services.sqlserver.sqlserver_va_periodic_recurring_scans_enabled", + ispkg=True, + ), + ModuleInfo( + module_finder=FileFinder( + "/root_dir/prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled" + ), + name="prowler.providers.azure.services.sqlserver.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_va_periodic_recurring_scans_enabled", + ispkg=False, + ), + ModuleInfo( + module_finder=FileFinder( + "/root_dir/prowler/providers/azure/services/sqlserver" + ), + name="prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured", + ispkg=True, + ), + ModuleInfo( + module_finder=FileFinder( + "/root_dir/prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured" + ), + name="prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured.sqlserver_va_scan_reports_configured", + ispkg=False, + ), + ModuleInfo( + module_finder=FileFinder( + "/root_dir/prowler/providers/azure/services/sqlserver" + ), + name="prowler.providers.azure.services.sqlserver.sqlserver_va_emails_notifications_admins_enabled", + ispkg=True, + ), + ModuleInfo( + module_finder=FileFinder( + "/root_dir/prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled" + ), + name="prowler.providers.azure.services.sqlserver.sqlserver_va_emails_notifications_admins_enabled.sqlserver_va_emails_notifications_admins_enabled", + ispkg=False, + ), ] return modules @@ -633,6 +717,18 @@ class Test_Check: "sqlserver_vulnerability_assessment_enabled", "/root_dir/prowler/providers/azure/services/sqlserver/sqlserver_vulnerability_assessment_enabled", ), + ( + "sqlserver_va_periodic_recurring_scans_enabled", + "/root_dir/prowler/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled", + ), + ( + "sqlserver_va_scan_reports_configured", + "/root_dir/prowler/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured", + ), + ( + "sqlserver_va_emails_notifications_admins_enabled", + "/root_dir/prowler/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled", + ), ] returned_checks = recover_checks_from_provider(provider, service) assert returned_checks == expected_checks diff --git a/tests/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled_test.py b/tests/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled_test.py new file mode 100644 index 00000000..605e3df8 --- /dev/null +++ b/tests/providers/azure/services/sqlserver/sqlserver_microsoft_defender_enabled/sqlserver_microsoft_defender_enabled_test.py @@ -0,0 +1,135 @@ +from unittest import mock +from uuid import uuid4 + +from azure.mgmt.sql.models import ServerSecurityAlertPolicy + +from prowler.providers.azure.services.sqlserver.sqlserver_service import Server + +AZURE_SUBSCRIPTION = str(uuid4()) + + +class Test_sqlserver_microsoft_defender_enabled: + def test_no_sql_servers(self): + sqlserver_client = mock.MagicMock + sqlserver_client.sql_servers = {} + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_microsoft_defender_enabled.sqlserver_microsoft_defender_enabled.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_microsoft_defender_enabled.sqlserver_microsoft_defender_enabled import ( + sqlserver_microsoft_defender_enabled, + ) + + check = sqlserver_microsoft_defender_enabled() + result = check.execute() + assert len(result) == 0 + + def test_sql_servers_no_security_alert_policies(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=[], + firewall_rules=None, + security_alert_policies=None, + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_microsoft_defender_enabled.sqlserver_microsoft_defender_enabled.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_microsoft_defender_enabled.sqlserver_microsoft_defender_enabled import ( + sqlserver_microsoft_defender_enabled, + ) + + check = sqlserver_microsoft_defender_enabled() + result = check.execute() + assert len(result) == 0 + + def test_sql_servers_microsoft_defender_disabled(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=[], + firewall_rules=None, + security_alert_policies=ServerSecurityAlertPolicy(state="Disabled"), + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_microsoft_defender_enabled.sqlserver_microsoft_defender_enabled.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_microsoft_defender_enabled.sqlserver_microsoft_defender_enabled import ( + sqlserver_microsoft_defender_enabled, + ) + + check = sqlserver_microsoft_defender_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has microsoft defender disabled." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id + + def test_sql_servers_microsoft_defender_enabled(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=[], + firewall_rules=None, + security_alert_policies=ServerSecurityAlertPolicy(state="Enabled"), + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_microsoft_defender_enabled.sqlserver_microsoft_defender_enabled.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_microsoft_defender_enabled.sqlserver_microsoft_defender_enabled import ( + sqlserver_microsoft_defender_enabled, + ) + + check = sqlserver_microsoft_defender_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has microsoft defender enabled." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id diff --git a/tests/providers/azure/services/sqlserver/sqlserver_service_test.py b/tests/providers/azure/services/sqlserver/sqlserver_service_test.py index d3d66efc..6cee6fd4 100644 --- a/tests/providers/azure/services/sqlserver/sqlserver_service_test.py +++ b/tests/providers/azure/services/sqlserver/sqlserver_service_test.py @@ -2,6 +2,9 @@ from unittest.mock import patch from azure.mgmt.sql.models import ( EncryptionProtector, + FirewallRule, + ServerBlobAuditingPolicy, + ServerSecurityAlertPolicy, ServerVulnerabilityAssessment, TransparentDataEncryption, ) @@ -34,8 +37,8 @@ def mock_sqlserver_get_sql_servers(_): public_network_access="public_network_access", minimal_tls_version="minimal_tls_version", administrators=None, - auditing_policies=None, - firewall_rules=None, + auditing_policies=ServerBlobAuditingPolicy(state="Disabled"), + firewall_rules=FirewallRule(name="name"), encryption_protector=EncryptionProtector( server_key_type="AzureKeyVault" ), @@ -43,6 +46,7 @@ def mock_sqlserver_get_sql_servers(_): vulnerability_assessment=ServerVulnerabilityAssessment( storage_container_path="/subcription_id/resource_group/sql_server" ), + security_alert_policies=ServerSecurityAlertPolicy(state="Disabled"), ) ] } @@ -84,8 +88,18 @@ class Test_SqlServer_Service: == "minimal_tls_version" ) assert sql_server.sql_servers[AZURE_SUBSCRIPTION][0].administrators is None - assert sql_server.sql_servers[AZURE_SUBSCRIPTION][0].auditing_policies is None - assert sql_server.sql_servers[AZURE_SUBSCRIPTION][0].firewall_rules is None + assert ( + sql_server.sql_servers[AZURE_SUBSCRIPTION][ + 0 + ].auditing_policies.__class__.__name__ + == "ServerBlobAuditingPolicy" + ) + assert ( + sql_server.sql_servers[AZURE_SUBSCRIPTION][ + 0 + ].firewall_rules.__class__.__name__ + == "FirewallRule" + ) assert ( sql_server.sql_servers[AZURE_SUBSCRIPTION][ 0 @@ -176,3 +190,49 @@ class Test_SqlServer_Service: ].vulnerability_assessment.storage_container_path == storage_container_path ) + + def test__get_server_blob_auditing_policies__(self): + sql_server = SQLServer(set_mocked_azure_audit_info()) + auditing_policies = ServerBlobAuditingPolicy(state="Disabled") + assert ( + sql_server.sql_servers[AZURE_SUBSCRIPTION][ + 0 + ].auditing_policies.__class__.__name__ + == "ServerBlobAuditingPolicy" + ) + assert ( + sql_server.sql_servers[AZURE_SUBSCRIPTION][0].auditing_policies + == auditing_policies + ) + + def test__get_firewall_rules__(self): + sql_server = SQLServer(set_mocked_azure_audit_info()) + firewall_rules = FirewallRule(name="name") + assert ( + sql_server.sql_servers[AZURE_SUBSCRIPTION][ + 0 + ].firewall_rules.__class__.__name__ + == "FirewallRule" + ) + assert ( + sql_server.sql_servers[AZURE_SUBSCRIPTION][0].firewall_rules + == firewall_rules + ) + + def test__get_server_security_alert_policies__(self): + sql_server = SQLServer(set_mocked_azure_audit_info()) + security_alert_policies = ServerSecurityAlertPolicy(state="Disabled") + assert ( + sql_server.sql_servers[AZURE_SUBSCRIPTION][ + 0 + ].security_alert_policies.__class__.__name__ + == "ServerSecurityAlertPolicy" + ) + assert ( + sql_server.sql_servers[AZURE_SUBSCRIPTION][0].security_alert_policies + == security_alert_policies + ) + assert ( + sql_server.sql_servers[AZURE_SUBSCRIPTION][0].security_alert_policies.state + == "Disabled" + ) diff --git a/tests/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled_test.py b/tests/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled_test.py new file mode 100644 index 00000000..a86e1764 --- /dev/null +++ b/tests/providers/azure/services/sqlserver/sqlserver_va_emails_notifications_admins_enabled/sqlserver_va_emails_notifications_admins_enabled_test.py @@ -0,0 +1,208 @@ +from unittest import mock +from uuid import uuid4 + +from azure.mgmt.sql.models import ( + ServerVulnerabilityAssessment, + VulnerabilityAssessmentRecurringScansProperties, +) + +from prowler.providers.azure.services.sqlserver.sqlserver_service import Server + +AZURE_SUBSCRIPTION = str(uuid4()) + + +class Test_sqlserver_va_emails_notifications_admins_enabled: + def test_no_sql_servers(self): + sqlserver_client = mock.MagicMock + sqlserver_client.sql_servers = {} + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_emails_notifications_admins_enabled.sqlserver_va_emails_notifications_admins_enabled.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_emails_notifications_admins_enabled.sqlserver_va_emails_notifications_admins_enabled import ( + sqlserver_va_emails_notifications_admins_enabled, + ) + + check = sqlserver_va_emails_notifications_admins_enabled() + result = check.execute() + assert len(result) == 0 + + def test_sql_servers_no_vulnerability_assessment(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=None, + firewall_rules=None, + databases=None, + encryption_protector=None, + vulnerability_assessment=None, + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_emails_notifications_admins_enabled.sqlserver_va_emails_notifications_admins_enabled.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_emails_notifications_admins_enabled.sqlserver_va_emails_notifications_admins_enabled import ( + sqlserver_va_emails_notifications_admins_enabled, + ) + + check = sqlserver_va_emails_notifications_admins_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has vulnerability assessment disabled." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id + + def test_sql_servers_no_vulnerability_assessment_no_admin_emails(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=None, + firewall_rules=None, + databases=None, + encryption_protector=None, + vulnerability_assessment=ServerVulnerabilityAssessment( + storage_container_path="/subcription_id/resource_group/sql_server", + recurring_scans=VulnerabilityAssessmentRecurringScansProperties( + email_subscription_admins=None + ), + ), + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_emails_notifications_admins_enabled.sqlserver_va_emails_notifications_admins_enabled.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_emails_notifications_admins_enabled.sqlserver_va_emails_notifications_admins_enabled import ( + sqlserver_va_emails_notifications_admins_enabled, + ) + + check = sqlserver_va_emails_notifications_admins_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has vulnerability assessment enabled but no scan reports configured for subscription admins." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id + + def test_sql_servers_vulnerability_assessment_admin_emails_false(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=None, + firewall_rules=None, + databases=None, + encryption_protector=None, + vulnerability_assessment=ServerVulnerabilityAssessment( + storage_container_path="/subcription_id/resource_group/sql_server", + recurring_scans=VulnerabilityAssessmentRecurringScansProperties( + email_subscription_admins=False + ), + ), + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_emails_notifications_admins_enabled.sqlserver_va_emails_notifications_admins_enabled.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_emails_notifications_admins_enabled.sqlserver_va_emails_notifications_admins_enabled import ( + sqlserver_va_emails_notifications_admins_enabled, + ) + + check = sqlserver_va_emails_notifications_admins_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has vulnerability assessment enabled but no scan reports configured for subscription admins." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id + + def test_sql_servers_vulnerability_assessment_no_email_subscription_admins(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=None, + firewall_rules=None, + databases=None, + encryption_protector=None, + vulnerability_assessment=ServerVulnerabilityAssessment( + storage_container_path="/subcription_id/resource_group/sql_server", + recurring_scans=VulnerabilityAssessmentRecurringScansProperties( + email_subscription_admins=True + ), + ), + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_emails_notifications_admins_enabled.sqlserver_va_emails_notifications_admins_enabled.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_emails_notifications_admins_enabled.sqlserver_va_emails_notifications_admins_enabled import ( + sqlserver_va_emails_notifications_admins_enabled, + ) + + check = sqlserver_va_emails_notifications_admins_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has vulnerability assessment enabled and scan reports configured for subscription admins." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id diff --git a/tests/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled_test.py b/tests/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled_test.py new file mode 100644 index 00000000..07918929 --- /dev/null +++ b/tests/providers/azure/services/sqlserver/sqlserver_va_periodic_recurring_scans_enabled/sqlserver_va_periodic_recurring_scans_enabled_test.py @@ -0,0 +1,205 @@ +from unittest import mock +from uuid import uuid4 + +from azure.mgmt.sql.models import ( + ServerVulnerabilityAssessment, + VulnerabilityAssessmentRecurringScansProperties, +) + +from prowler.providers.azure.services.sqlserver.sqlserver_service import Server + +AZURE_SUBSCRIPTION = str(uuid4()) + + +class Test_sqlserver_va_periodic_recurring_scans_enabled: + def test_no_sql_servers(self): + sqlserver_client = mock.MagicMock + sqlserver_client.sql_servers = {} + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_va_periodic_recurring_scans_enabled import ( + sqlserver_va_periodic_recurring_scans_enabled, + ) + + check = sqlserver_va_periodic_recurring_scans_enabled() + result = check.execute() + assert len(result) == 0 + + def test_sql_servers_no_vulnerability_assessment(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=None, + firewall_rules=None, + databases=None, + encryption_protector=None, + vulnerability_assessment=None, + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_va_periodic_recurring_scans_enabled import ( + sqlserver_va_periodic_recurring_scans_enabled, + ) + + check = sqlserver_va_periodic_recurring_scans_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has vulnerability assessment disabled." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id + + def test_sql_servers_no_vulnerability_assessment_storage_container_path(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=None, + firewall_rules=None, + databases=None, + encryption_protector=None, + vulnerability_assessment=ServerVulnerabilityAssessment( + storage_container_path=None + ), + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_va_periodic_recurring_scans_enabled import ( + sqlserver_va_periodic_recurring_scans_enabled, + ) + + check = sqlserver_va_periodic_recurring_scans_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has vulnerability assessment disabled." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id + + def test_sql_servers_vulnerability_assessment_recuring_scans_disabled(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=None, + firewall_rules=None, + databases=None, + encryption_protector=None, + vulnerability_assessment=ServerVulnerabilityAssessment( + storage_container_path="/subcription_id/resource_group/sql_server", + recurring_scans=VulnerabilityAssessmentRecurringScansProperties( + is_enabled=False + ), + ), + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_va_periodic_recurring_scans_enabled import ( + sqlserver_va_periodic_recurring_scans_enabled, + ) + + check = sqlserver_va_periodic_recurring_scans_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has vulnerability assessment enabled but no recurring scans." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id + + def test_sql_servers_vulnerability_assessment_recuring_scans_enabled(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=None, + firewall_rules=None, + databases=None, + encryption_protector=None, + vulnerability_assessment=ServerVulnerabilityAssessment( + storage_container_path="/subcription_id/resource_group/sql_server", + recurring_scans=VulnerabilityAssessmentRecurringScansProperties( + is_enabled=True + ), + ), + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_periodic_recurring_scans_enabled.sqlserver_va_periodic_recurring_scans_enabled import ( + sqlserver_va_periodic_recurring_scans_enabled, + ) + + check = sqlserver_va_periodic_recurring_scans_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has periodic recurring scans enabled." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id diff --git a/tests/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured_test.py b/tests/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured_test.py new file mode 100644 index 00000000..5b364bf4 --- /dev/null +++ b/tests/providers/azure/services/sqlserver/sqlserver_va_scan_reports_configured/sqlserver_va_scan_reports_configured_test.py @@ -0,0 +1,254 @@ +from unittest import mock +from uuid import uuid4 + +from azure.mgmt.sql.models import ( + ServerVulnerabilityAssessment, + VulnerabilityAssessmentRecurringScansProperties, +) + +from prowler.providers.azure.services.sqlserver.sqlserver_service import Server + +AZURE_SUBSCRIPTION = str(uuid4()) + + +class Test_sqlserver_va_scan_reports_configured: + def test_no_sql_servers(self): + sqlserver_client = mock.MagicMock + sqlserver_client.sql_servers = {} + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured.sqlserver_va_scan_reports_configured.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured.sqlserver_va_scan_reports_configured import ( + sqlserver_va_scan_reports_configured, + ) + + check = sqlserver_va_scan_reports_configured() + result = check.execute() + assert len(result) == 0 + + def test_sql_servers_no_vulnerability_assessment(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=None, + firewall_rules=None, + databases=None, + encryption_protector=None, + vulnerability_assessment=None, + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured.sqlserver_va_scan_reports_configured.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured.sqlserver_va_scan_reports_configured import ( + sqlserver_va_scan_reports_configured, + ) + + check = sqlserver_va_scan_reports_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has vulnerability assessment disabled." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id + + def test_sql_servers_no_vulnerability_assessment_emails(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=None, + firewall_rules=None, + databases=None, + encryption_protector=None, + vulnerability_assessment=ServerVulnerabilityAssessment( + storage_container_path="/subcription_id/resource_group/sql_server", + recurring_scans=VulnerabilityAssessmentRecurringScansProperties( + emails=None, email_subscription_admins=False + ), + ), + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured.sqlserver_va_scan_reports_configured.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured.sqlserver_va_scan_reports_configured import ( + sqlserver_va_scan_reports_configured, + ) + + check = sqlserver_va_scan_reports_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has vulnerability assessment enabled but no scan reports configured." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id + + def test_sql_servers_vulnerability_assessment_emails_none(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=None, + firewall_rules=None, + databases=None, + encryption_protector=None, + vulnerability_assessment=ServerVulnerabilityAssessment( + storage_container_path="/subcription_id/resource_group/sql_server", + recurring_scans=VulnerabilityAssessmentRecurringScansProperties( + emails=None, email_subscription_admins=True + ), + ), + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured.sqlserver_va_scan_reports_configured.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured.sqlserver_va_scan_reports_configured import ( + sqlserver_va_scan_reports_configured, + ) + + check = sqlserver_va_scan_reports_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has vulnerability assessment enabled and scan reports configured." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id + + def test_sql_servers_vulnerability_assessment_no_email_subscription_admins(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=None, + firewall_rules=None, + databases=None, + encryption_protector=None, + vulnerability_assessment=ServerVulnerabilityAssessment( + storage_container_path="/subcription_id/resource_group/sql_server", + recurring_scans=VulnerabilityAssessmentRecurringScansProperties( + emails=["email@email.com"], email_subscription_admins=False + ), + ), + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured.sqlserver_va_scan_reports_configured.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured.sqlserver_va_scan_reports_configured import ( + sqlserver_va_scan_reports_configured, + ) + + check = sqlserver_va_scan_reports_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has vulnerability assessment enabled and scan reports configured." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id + + def test_sql_servers_vulnerability_assessment_both_emails(self): + sqlserver_client = mock.MagicMock + sql_server_name = "SQL Server Name" + sql_server_id = str(uuid4()) + sqlserver_client.sql_servers = { + AZURE_SUBSCRIPTION: [ + Server( + id=sql_server_id, + name=sql_server_name, + public_network_access="", + minimal_tls_version="", + administrators=None, + auditing_policies=None, + firewall_rules=None, + databases=None, + encryption_protector=None, + vulnerability_assessment=ServerVulnerabilityAssessment( + storage_container_path="/subcription_id/resource_group/sql_server", + recurring_scans=VulnerabilityAssessmentRecurringScansProperties( + emails=["email@email.com"], email_subscription_admins=True + ), + ), + ) + ] + } + + with mock.patch( + "prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured.sqlserver_va_scan_reports_configured.sqlserver_client", + new=sqlserver_client, + ): + from prowler.providers.azure.services.sqlserver.sqlserver_va_scan_reports_configured.sqlserver_va_scan_reports_configured import ( + sqlserver_va_scan_reports_configured, + ) + + check = sqlserver_va_scan_reports_configured() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"SQL Server {sql_server_name} from subscription {AZURE_SUBSCRIPTION} has vulnerability assessment enabled and scan reports configured." + ) + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].resource_name == sql_server_name + assert result[0].resource_id == sql_server_id