mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 06:45:08 +00:00
feat(azure): new check sqlserver_vulnerability_assessment_enabled (#3349)
This commit is contained in:
@@ -6,6 +6,7 @@ from azure.mgmt.sql.models import (
|
||||
FirewallRule,
|
||||
ServerBlobAuditingPolicy,
|
||||
ServerExternalAdministrator,
|
||||
ServerVulnerabilityAssessment,
|
||||
TransparentDataEncryption,
|
||||
)
|
||||
|
||||
@@ -40,6 +41,9 @@ class SQLServer(AzureService):
|
||||
encryption_protector = self.__get_enctyption_protectors__(
|
||||
subscription, resource_group, sql_server.name
|
||||
)
|
||||
vulnerability_assessment = self.__get_vulnerability_assesments__(
|
||||
subscription, resource_group, sql_server.name
|
||||
)
|
||||
sql_servers[subscription].append(
|
||||
SQL_Server(
|
||||
id=sql_server.id,
|
||||
@@ -53,6 +57,7 @@ class SQLServer(AzureService):
|
||||
databases=self.__get_databases__(
|
||||
subscription, resource_group, sql_server.name
|
||||
),
|
||||
vulnerability_assessment=vulnerability_assessment,
|
||||
)
|
||||
)
|
||||
except Exception as error:
|
||||
@@ -115,6 +120,17 @@ class SQLServer(AzureService):
|
||||
)
|
||||
return databases
|
||||
|
||||
def __get_vulnerability_assesments__(
|
||||
self, subscription, resource_group, server_name
|
||||
):
|
||||
client = self.clients[subscription]
|
||||
vulnerability_assessment = client.server_vulnerability_assessments.get(
|
||||
resource_group_name=resource_group,
|
||||
server_name=server_name,
|
||||
vulnerability_assessment_name="default",
|
||||
)
|
||||
return vulnerability_assessment
|
||||
|
||||
|
||||
@dataclass
|
||||
class DatabaseServer:
|
||||
@@ -137,3 +153,4 @@ class SQL_Server:
|
||||
firewall_rules: FirewallRule
|
||||
encryption_protector: EncryptionProtector = None
|
||||
databases: list[DatabaseServer] = None
|
||||
vulnerability_assessment: ServerVulnerabilityAssessment = None
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "sqlserver_vulnerability_assessment_enabled",
|
||||
"CheckTitle": "Ensure that Vulnerability Assessment (VA) is enabled on a SQL server by setting a Storage Account",
|
||||
"CheckType": [],
|
||||
"ServiceName": "sqlserver",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "SQLServer",
|
||||
"Description": "Enable Vulnerability Assessment (VA) service scans for critical SQL servers and corresponding SQL databases.",
|
||||
"Risk": "The Vulnerability Assessment service scans databases for known security vulnerabilities and highlights deviations from best practices, such as misconfigurations, excessive permissions, and unprotected sensitive data. Results of the scan include actionable steps to resolve each issue and provide customized remediation scripts where applicable. Additionally, an assessment report can be customized by setting an acceptable baseline for permission configurations, feature configurations, and database settings.",
|
||||
"RelatedUrl": "https://docs.microsoft.com/en-us/azure/sql-database/sql-vulnerability-assessment",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "Update-AzSqlServerVulnerabilityAssessmentSetting -ResourceGroupName resource_group_name -ServerName Server_Name -StorageAccountName Storage_Name_from_same_subscription_and_same_Location -ScanResultsContainerName vulnerability-assessment -RecurringScansInterval Weekly -EmailSubscriptionAdmins $true -NotificationEmail @('mail1@mail.com' , 'mail2@mail.com')",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/Sql/vulnerability-assessment-sql-servers.html#",
|
||||
"Terraform": "https://docs.bridgecrew.io/docs/ensure-that-vulnerability-assessment-va-is-enabled-on-a-sql-server-by-setting-a-storage-account"
|
||||
},
|
||||
"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, Click Select Storage account 6. Choose Storage Account (Existing or Create New). Click Ok 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."
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.sqlserver.sqlserver_client import sqlserver_client
|
||||
|
||||
|
||||
class sqlserver_vulnerability_assessment_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
|
||||
is not None
|
||||
):
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has vulnerability assessment enabled."
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -115,6 +115,20 @@ expected_packages = [
|
||||
name="prowler.providers.azure.services.sqlserver.sqlserver_auditing_retention_90_days.sqlserver_auditing_retention_90_days",
|
||||
ispkg=False,
|
||||
),
|
||||
ModuleInfo(
|
||||
module_finder=FileFinder(
|
||||
"/root_dir/prowler/providers/azure/services/sqlserver"
|
||||
),
|
||||
name="prowler.providers.azure.services.sqlserver.sqlserver_vulnerability_assessment_enabled",
|
||||
ispkg=True,
|
||||
),
|
||||
ModuleInfo(
|
||||
module_finder=FileFinder(
|
||||
"/root_dir/prowler/providers/azure/services/sqlserver/sqlserver_vulnerability_assessment_enabled"
|
||||
),
|
||||
name="prowler.providers.azure.services.sqlserver.sqlserver_vulnerability_assessment_enabled.sqlserver_vulnerability_assessment_enabled",
|
||||
ispkg=False,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -208,6 +222,20 @@ def mock_list_modules(*_):
|
||||
name="prowler.providers.azure.services.sqlserver.sqlserver_auditing_retention_90_days.sqlserver_auditing_retention_90_days",
|
||||
ispkg=False,
|
||||
),
|
||||
ModuleInfo(
|
||||
module_finder=FileFinder(
|
||||
"/root_dir/prowler/providers/azure/services/sqlserver"
|
||||
),
|
||||
name="prowler.providers.azure.services.sqlserver.sqlserver_vulnerability_assessment_enabled",
|
||||
ispkg=True,
|
||||
),
|
||||
ModuleInfo(
|
||||
module_finder=FileFinder(
|
||||
"/root_dir/prowler/providers/azure/services/sqlserver/sqlserver_vulnerability_assessment_enabled"
|
||||
),
|
||||
name="prowler.providers.azure.services.sqlserver.sqlserver_vulnerability_assessment_enabled.sqlserver_vulnerability_assessment_enabled",
|
||||
ispkg=False,
|
||||
),
|
||||
]
|
||||
return modules
|
||||
|
||||
@@ -601,6 +629,10 @@ class Test_Check:
|
||||
"sqlserver_auditing_retention_90_days",
|
||||
"/root_dir/prowler/providers/azure/services/sqlserver/sqlserver_auditing_retention_90_days",
|
||||
),
|
||||
(
|
||||
"sqlserver_vulnerability_assessment_enabled",
|
||||
"/root_dir/prowler/providers/azure/services/sqlserver/sqlserver_vulnerability_assessment_enabled",
|
||||
),
|
||||
]
|
||||
returned_checks = recover_checks_from_provider(provider, service)
|
||||
assert returned_checks == expected_checks
|
||||
|
||||
@@ -8,8 +8,7 @@ from azure.mgmt.sql.models import (
|
||||
)
|
||||
|
||||
from prowler.providers.azure.services.sqlserver.sqlserver_service import SQL_Server
|
||||
|
||||
AZURE_SUSCRIPTION = str(uuid4())
|
||||
from tests.providers.azure.azure_fixtures import AZURE_SUSCRIPTION
|
||||
|
||||
|
||||
class Test_sqlserver_auditing_enabled:
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
from unittest.mock import patch
|
||||
|
||||
from azure.mgmt.sql.models import EncryptionProtector, TransparentDataEncryption
|
||||
from azure.mgmt.sql.models import (
|
||||
EncryptionProtector,
|
||||
ServerVulnerabilityAssessment,
|
||||
TransparentDataEncryption,
|
||||
)
|
||||
|
||||
from prowler.providers.azure.services.sqlserver.sqlserver_service import (
|
||||
DatabaseServer,
|
||||
@@ -36,6 +40,9 @@ def mock_sqlserver_get_sql_servers(_):
|
||||
server_key_type="AzureKeyVault"
|
||||
),
|
||||
databases=[database],
|
||||
vulnerability_assessment=ServerVulnerabilityAssessment(
|
||||
storage_container_path="/subcription_id/resource_group/sql_server"
|
||||
),
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -87,6 +94,12 @@ class Test_SqlServer_Service:
|
||||
== "EncryptionProtector"
|
||||
)
|
||||
assert sql_server.sql_servers[AZURE_SUSCRIPTION][0].databases == [database]
|
||||
assert (
|
||||
sql_server.sql_servers[AZURE_SUSCRIPTION][
|
||||
0
|
||||
].vulnerability_assessment.__class__.__name__
|
||||
== "ServerVulnerabilityAssessment"
|
||||
)
|
||||
|
||||
def test__get_databases__(self):
|
||||
sql_server = SQLServer(set_mocked_azure_audit_info())
|
||||
@@ -146,3 +159,19 @@ class Test_SqlServer_Service:
|
||||
id = "/subscriptions/subscription_id/resourceGroups/resource_group/providers/Microsoft.Sql/servers/sql_server"
|
||||
sql_server = SQLServer(set_mocked_azure_audit_info())
|
||||
assert sql_server.__get_resource_group__(id) == "resource_group"
|
||||
|
||||
def test__get_vulnerability_assessment__(self):
|
||||
sql_server = SQLServer(set_mocked_azure_audit_info())
|
||||
storage_container_path = "/subcription_id/resource_group/sql_server"
|
||||
assert (
|
||||
sql_server.sql_servers[AZURE_SUSCRIPTION][
|
||||
0
|
||||
].vulnerability_assessment.__class__.__name__
|
||||
== "ServerVulnerabilityAssessment"
|
||||
)
|
||||
assert (
|
||||
sql_server.sql_servers[AZURE_SUSCRIPTION][
|
||||
0
|
||||
].vulnerability_assessment.storage_container_path
|
||||
== storage_container_path
|
||||
)
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from azure.mgmt.sql.models import (
|
||||
EncryptionProtector,
|
||||
ServerVulnerabilityAssessment,
|
||||
TransparentDataEncryption,
|
||||
)
|
||||
|
||||
from prowler.providers.azure.services.sqlserver.sqlserver_service import (
|
||||
DatabaseServer,
|
||||
SQL_Server,
|
||||
)
|
||||
|
||||
AZURE_SUSCRIPTION = str(uuid4())
|
||||
|
||||
|
||||
class Test_sqlserver_vulnerability_assessment_enabled:
|
||||
def test_no_sql_servers(self):
|
||||
sqlserver_client = mock.MagicMock
|
||||
sqlserver_client.sql_servers = {}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.sqlserver.sqlserver_vulnerability_assessment_enabled.sqlserver_vulnerability_assessment_enabled.sqlserver_client",
|
||||
new=sqlserver_client,
|
||||
):
|
||||
from prowler.providers.azure.services.sqlserver.sqlserver_vulnerability_assessment_enabled.sqlserver_vulnerability_assessment_enabled import (
|
||||
sqlserver_vulnerability_assessment_enabled,
|
||||
)
|
||||
|
||||
check = sqlserver_vulnerability_assessment_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())
|
||||
database = DatabaseServer(
|
||||
id="id",
|
||||
name="name",
|
||||
type="type",
|
||||
location="location",
|
||||
managed_by="managed_by",
|
||||
tde_encryption=None,
|
||||
)
|
||||
sqlserver_client.sql_servers = {
|
||||
AZURE_SUSCRIPTION: [
|
||||
SQL_Server(
|
||||
id=sql_server_id,
|
||||
name=sql_server_name,
|
||||
public_network_access="",
|
||||
minimal_tls_version="",
|
||||
administrators=None,
|
||||
auditing_policies=None,
|
||||
firewall_rules=None,
|
||||
databases=[database],
|
||||
encryption_protector=EncryptionProtector(
|
||||
server_key_type="ServiceManaged"
|
||||
),
|
||||
vulnerability_assessment=None,
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.sqlserver.sqlserver_vulnerability_assessment_enabled.sqlserver_vulnerability_assessment_enabled.sqlserver_client",
|
||||
new=sqlserver_client,
|
||||
):
|
||||
from prowler.providers.azure.services.sqlserver.sqlserver_vulnerability_assessment_enabled.sqlserver_vulnerability_assessment_enabled import (
|
||||
sqlserver_vulnerability_assessment_enabled,
|
||||
)
|
||||
|
||||
check = sqlserver_vulnerability_assessment_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_SUSCRIPTION} has vulnerability assessment disabled."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUSCRIPTION
|
||||
assert result[0].resource_name == sql_server_name
|
||||
assert result[0].resource_id == sql_server_id
|
||||
|
||||
def test_sql_servers_no_vulnerability_assessment_path(self):
|
||||
sqlserver_client = mock.MagicMock
|
||||
sql_server_name = "SQL Server Name"
|
||||
sql_server_id = str(uuid4())
|
||||
database = DatabaseServer(
|
||||
id="id",
|
||||
name="name",
|
||||
type="type",
|
||||
location="location",
|
||||
managed_by="managed_by",
|
||||
tde_encryption=TransparentDataEncryption(status="Disabled"),
|
||||
)
|
||||
sqlserver_client.sql_servers = {
|
||||
AZURE_SUSCRIPTION: [
|
||||
SQL_Server(
|
||||
id=sql_server_id,
|
||||
name=sql_server_name,
|
||||
public_network_access="",
|
||||
minimal_tls_version="",
|
||||
administrators=None,
|
||||
auditing_policies=None,
|
||||
firewall_rules=None,
|
||||
databases=[database],
|
||||
encryption_protector=EncryptionProtector(
|
||||
server_key_type="AzureKeyVault"
|
||||
),
|
||||
vulnerability_assessment=ServerVulnerabilityAssessment(
|
||||
storage_container_path=None
|
||||
),
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.sqlserver.sqlserver_vulnerability_assessment_enabled.sqlserver_vulnerability_assessment_enabled.sqlserver_client",
|
||||
new=sqlserver_client,
|
||||
):
|
||||
from prowler.providers.azure.services.sqlserver.sqlserver_vulnerability_assessment_enabled.sqlserver_vulnerability_assessment_enabled import (
|
||||
sqlserver_vulnerability_assessment_enabled,
|
||||
)
|
||||
|
||||
check = sqlserver_vulnerability_assessment_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_SUSCRIPTION} has vulnerability assessment disabled."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUSCRIPTION
|
||||
assert result[0].resource_name == sql_server_name
|
||||
assert result[0].resource_id == sql_server_id
|
||||
|
||||
def test_sql_servers_vulnerability_assessment_enabled(self):
|
||||
sqlserver_client = mock.MagicMock
|
||||
sql_server_name = "SQL Server Name"
|
||||
sql_server_id = str(uuid4())
|
||||
database = DatabaseServer(
|
||||
id="id",
|
||||
name="name",
|
||||
type="type",
|
||||
location="location",
|
||||
managed_by="managed_by",
|
||||
tde_encryption=TransparentDataEncryption(status="Enabled"),
|
||||
)
|
||||
sqlserver_client.sql_servers = {
|
||||
AZURE_SUSCRIPTION: [
|
||||
SQL_Server(
|
||||
id=sql_server_id,
|
||||
name=sql_server_name,
|
||||
public_network_access="",
|
||||
minimal_tls_version="",
|
||||
administrators=None,
|
||||
auditing_policies=None,
|
||||
firewall_rules=None,
|
||||
databases=[database],
|
||||
encryption_protector=EncryptionProtector(
|
||||
server_key_type="AzureKeyVault"
|
||||
),
|
||||
vulnerability_assessment=ServerVulnerabilityAssessment(
|
||||
storage_container_path="/subcription_id/resource_group/sql_server"
|
||||
),
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.azure.services.sqlserver.sqlserver_vulnerability_assessment_enabled.sqlserver_vulnerability_assessment_enabled.sqlserver_client",
|
||||
new=sqlserver_client,
|
||||
):
|
||||
from prowler.providers.azure.services.sqlserver.sqlserver_vulnerability_assessment_enabled.sqlserver_vulnerability_assessment_enabled import (
|
||||
sqlserver_vulnerability_assessment_enabled,
|
||||
)
|
||||
|
||||
check = sqlserver_vulnerability_assessment_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_SUSCRIPTION} has vulnerability assessment enabled."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUSCRIPTION
|
||||
assert result[0].resource_name == sql_server_name
|
||||
assert result[0].resource_id == sql_server_id
|
||||
Reference in New Issue
Block a user