mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 06:45:08 +00:00
feat(azure): add Azure SQL Server service and 3 checks (#2665)
Co-authored-by: Pepe Fagoaga <pepe@verica.io> Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
This commit is contained in:
18
poetry.lock
generated
18
poetry.lock
generated
@@ -168,6 +168,22 @@ azure-common = ">=1.1,<2.0"
|
||||
azure-mgmt-core = ">=1.3.2,<2.0.0"
|
||||
isodate = ">=0.6.1,<1.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "azure-mgmt-sql"
|
||||
version = "3.0.1"
|
||||
description = "Microsoft Azure SQL Management Client Library for Python"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "azure-mgmt-sql-3.0.1.zip", hash = "sha256:129042cc011225e27aee6ef2697d585fa5722e5d1aeb0038af6ad2451a285457"},
|
||||
{file = "azure_mgmt_sql-3.0.1-py2.py3-none-any.whl", hash = "sha256:1d1dd940d4d41be4ee319aad626341251572a5bf4a2addec71779432d9a1381f"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
azure-common = ">=1.1,<2.0"
|
||||
azure-mgmt-core = ">=1.2.0,<2.0.0"
|
||||
msrest = ">=0.6.21"
|
||||
|
||||
[[package]]
|
||||
name = "azure-mgmt-storage"
|
||||
version = "21.0.0"
|
||||
@@ -2875,4 +2891,4 @@ docs = ["mkdocs", "mkdocs-material"]
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.9"
|
||||
content-hash = "2e4af8e15db5d10b860a960d9fa3f4511182f858121e326f98aeca4a1bd75c86"
|
||||
content-hash = "af1b95fa997c6e4eb7f6764a69c00cb89aac5cfce77c130e1722f6322f495755"
|
||||
|
||||
@@ -15,7 +15,6 @@ class IAM(AzureService):
|
||||
audit_info.identity.subscriptions, audit_info.credentials
|
||||
)
|
||||
self.roles = self.__get_roles__()
|
||||
self.region = "azure"
|
||||
|
||||
def __set_clients__(self, subscriptions, credentials):
|
||||
clients = {}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "sqlserver_auditing_enabled",
|
||||
"CheckTitle": "Ensure that SQL Servers have an audit policy configured",
|
||||
"CheckType": [],
|
||||
"ServiceName": "sqlserver",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "SQLServer",
|
||||
"Description": "Ensure that there is an audit policy configured",
|
||||
"Risk": "Audit policies are used to store logs associated to the SLQ server (for instance, successful/unsuccesful log in attempts). These logs may be useful to detect anomalies or to perform an investigation in case a security incident is detected",
|
||||
"RelatedUrl": "https://docs.microsoft.com/en-us/azure/sql-database/sql-database-auditing",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "https://docs.bridgecrew.io/docs/bc_azr_logging_2#cli-command",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/azure/Sql/auditing.html",
|
||||
"Terraform": "https://docs.bridgecrew.io/docs/bc_azr_logging_2#terraform"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Create an audit policy for the SQL server",
|
||||
"Url": ""
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
@@ -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_auditing_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.status = "PASS"
|
||||
report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has a auditing policy configured"
|
||||
report.resource_name = sql_server.name
|
||||
report.resource_id = sql_server.id
|
||||
|
||||
for auditing_policy in sql_server.auditing_policies:
|
||||
if auditing_policy.state == "Disabled":
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} does not have any auditing policy configured"
|
||||
break
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "sqlserver_azuread_administrator_enabled",
|
||||
"CheckTitle": "Ensure that SQL Servers have an Azure Active Directory administrator",
|
||||
"CheckType": [],
|
||||
"ServiceName": "sqlserver",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "SQLServer",
|
||||
"Description": "Ensure that there is an Azure Active Directory administrator configured",
|
||||
"Risk": "Azure Active Directory provides a centralized way of managing identities. Using local SQL administrator identites makes it more difficult to manage user accounts. In addition, from Azure Active Directory, security policies can be enforced to users in centralized way.",
|
||||
"RelatedUrl": "https://docs.microsoft.com/en-us/azure/sql-database/sql-database-aad-authentication",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "az sql server ad-admin create --resource-group resource_group_name --server server_name --display-name display_name --object-id user_object_id",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/azure/Sql/active-directory-admin.html",
|
||||
"Terraform": "https://docs.bridgecrew.io/docs/ensure-that-azure-active-directory-admin-is-configured#terraform"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Enable an Azure Active Directory administrator",
|
||||
"Url": ""
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.sqlserver.sqlserver_client import sqlserver_client
|
||||
|
||||
|
||||
class sqlserver_azuread_administrator_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.status = "PASS"
|
||||
report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has an Active Directory administrator"
|
||||
report.resource_name = sql_server.name
|
||||
report.resource_id = sql_server.id
|
||||
|
||||
if (
|
||||
sql_server.administrators is None
|
||||
or sql_server.administrators.administrator_type != "ActiveDirectory"
|
||||
):
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} does not have an Active Directory administrator"
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,4 @@
|
||||
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
|
||||
from prowler.providers.azure.services.sqlserver.sqlserver_service import SQLServer
|
||||
|
||||
sqlserver_client = SQLServer(azure_audit_info)
|
||||
108
prowler/providers/azure/services/sqlserver/sqlserver_service.py
Normal file
108
prowler/providers/azure/services/sqlserver/sqlserver_service.py
Normal file
@@ -0,0 +1,108 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from azure.mgmt.sql import SqlManagementClient
|
||||
from azure.mgmt.sql.models import (
|
||||
FirewallRule,
|
||||
ServerBlobAuditingPolicy,
|
||||
ServerExternalAdministrator,
|
||||
)
|
||||
|
||||
from prowler.lib.logger import logger
|
||||
from prowler.providers.azure.lib.service.service import AzureService
|
||||
|
||||
|
||||
########################## SQLServer
|
||||
class SQLServer(AzureService):
|
||||
def __init__(self, audit_info):
|
||||
super().__init__(__class__.__name__, audit_info)
|
||||
self.clients = self.__set_clients__(
|
||||
audit_info.identity.subscriptions, audit_info.credentials
|
||||
)
|
||||
self.sql_servers = self.__get_sql_servers__()
|
||||
|
||||
def __set_clients__(self, subscriptions, credentials):
|
||||
clients = {}
|
||||
try:
|
||||
for display_name, id in subscriptions.items():
|
||||
clients.update(
|
||||
{
|
||||
display_name: SqlManagementClient(
|
||||
credential=credentials, subscription_id=id
|
||||
)
|
||||
}
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
else:
|
||||
return clients
|
||||
|
||||
def __get_sql_servers__(self):
|
||||
logger.info("SQL Server - Getting SQL servers...")
|
||||
sql_servers = {}
|
||||
for subscription, client in self.clients.items():
|
||||
try:
|
||||
sql_servers.update({subscription: []})
|
||||
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,
|
||||
)
|
||||
)
|
||||
firewall_rules = client.firewall_rules.list_by_server(
|
||||
resource_group_name=resource_group, server_name=sql_server.name
|
||||
)
|
||||
sql_servers[subscription].append(
|
||||
SQL_Server(
|
||||
id=sql_server.id,
|
||||
name=sql_server.name,
|
||||
public_network_access=sql_server.public_network_access,
|
||||
minimal_tls_version=sql_server.minimal_tls_version,
|
||||
administrators=sql_server.administrators,
|
||||
auditing_policies=auditing_policies,
|
||||
firewall_rules=firewall_rules,
|
||||
)
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(f"Subscription name: {subscription}")
|
||||
logger.error(
|
||||
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
return sql_servers
|
||||
|
||||
def __get_resource_group__(self, id):
|
||||
resource_group = id.split("/")[4]
|
||||
return resource_group
|
||||
|
||||
|
||||
@dataclass
|
||||
class SQL_Server:
|
||||
id: str
|
||||
name: str
|
||||
public_network_access: str
|
||||
minimal_tls_version: str
|
||||
administrators: ServerExternalAdministrator
|
||||
auditing_policies: ServerBlobAuditingPolicy
|
||||
firewall_rules: FirewallRule
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
id,
|
||||
name,
|
||||
public_network_access,
|
||||
minimal_tls_version,
|
||||
administrators,
|
||||
auditing_policies,
|
||||
firewall_rules,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.public_network_access = public_network_access
|
||||
self.minimal_tls_version = minimal_tls_version
|
||||
self.administrators = administrators
|
||||
self.auditing_policies = auditing_policies
|
||||
self.firewall_rules = firewall_rules
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "sqlserver_unrestricted_inbound_access",
|
||||
"CheckTitle": "Ensure that there are no firewall rules allowing traffic from 0.0.0.0-255.255.255.255",
|
||||
"CheckType": [],
|
||||
"ServiceName": "sqlserver",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "critical",
|
||||
"ResourceType": "SQLServer",
|
||||
"Description": "Ensure that there are no firewall rules allowing traffic from 0.0.0.0-255.255.255.255",
|
||||
"Risk": "Azure SQL servers provide a firewall that, by default, blocks all Internet connections. When the rule (0.0.0.0-255.255.255.255) is used, the server can be accessed by any source from the Internet, incrementing significantly the attack surface of the SQL Server. It is recommended to use more granular firewall rules.",
|
||||
"RelatedUrl": "https://docs.microsoft.com/en-us/azure/sql-database/sql-database-vnet-service-endpoint-rule-overview",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "az sql server firewall-rule delete --resource-group resource_group_name --server sql_server_name --name rule_name",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/azure/Sql/unrestricted-sql-database-access.html",
|
||||
"Terraform": "https://docs.bridgecrew.io/docs/bc_azr_networking_4#terraform"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Remove firewall rules allowing all sources and, instead, use more granular rules",
|
||||
"Url": ""
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.sqlserver.sqlserver_client import sqlserver_client
|
||||
|
||||
|
||||
class sqlserver_unrestricted_inbound_access(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.status = "PASS"
|
||||
report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} does not have firewall rules allowing 0.0.0.0-255.255.255.255"
|
||||
report.resource_name = sql_server.name
|
||||
report.resource_id = sql_server.id
|
||||
|
||||
for firewall_rule in sql_server.firewall_rules:
|
||||
if (
|
||||
firewall_rule.start_ip_address == "0.0.0.0"
|
||||
and firewall_rule.end_ip_address == "255.255.255.255"
|
||||
):
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"SQL Server {sql_server.name} from subscription {subscription} has firewall rules allowing 0.0.0.0-255.255.255.255"
|
||||
break
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -15,7 +15,6 @@ class Storage(AzureService):
|
||||
audit_info.identity.subscriptions, audit_info.credentials
|
||||
)
|
||||
self.storage_accounts = self.__get_storage_accounts__()
|
||||
self.region = "azure"
|
||||
|
||||
def __set_clients__(self, subscriptions, credentials):
|
||||
clients = {}
|
||||
|
||||
@@ -30,6 +30,7 @@ awsipranges = "0.3.3"
|
||||
azure-identity = "1.13.0"
|
||||
azure-mgmt-authorization = "4.0.0"
|
||||
azure-mgmt-security = "5.0.0"
|
||||
azure-mgmt-sql = "3.0.1"
|
||||
azure-mgmt-storage = "21.0.0"
|
||||
azure-mgmt-subscription = "3.1.1"
|
||||
azure-storage-blob = "12.17.0"
|
||||
|
||||
Reference in New Issue
Block a user