mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 13:01:56 +00:00
feat(azure): add new check databricks_workspace_cmk_encryption_enabled (#8017)
This commit is contained in:
committed by
GitHub
parent
facc0627d7
commit
f9aed36d0b
@@ -35,6 +35,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- `codebuild_project_uses_allowed_github_organizations` check for AWS provider [(#7595)](https://github.com/prowler-cloud/prowler/pull/7595)
|
||||
- IaC provider [(#7852)](https://github.com/prowler-cloud/prowler/pull/7852)
|
||||
- Azure Databricks service integration for Azure provider, including the `databricks_workspace_vnet_injection_enabled` check [(#8008)](https://github.com/prowler-cloud/prowler/pull/8008)
|
||||
- Azure Databricks check `databricks_workspace_cmk_encryption_enabled` to ensure workspaces use customer-managed keys (CMK) for encryption at rest [(#8017)](https://github.com/prowler-cloud/prowler/pull/8017)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -41,6 +41,26 @@ class Databricks(AzureService):
|
||||
|
||||
for workspace in client.workspaces.list_by_subscription():
|
||||
workspace_parameters = getattr(workspace, "parameters", None)
|
||||
workspace_managed_disk_encryption = getattr(
|
||||
getattr(
|
||||
getattr(workspace, "encryption", None), "entities", None
|
||||
),
|
||||
"managed_disk",
|
||||
None,
|
||||
)
|
||||
|
||||
key_vault_properties = getattr(
|
||||
workspace_managed_disk_encryption, "key_vault_properties", None
|
||||
)
|
||||
|
||||
if key_vault_properties:
|
||||
managed_disk_encryption = ManagedDiskEncryption(
|
||||
key_name=key_vault_properties.key_name,
|
||||
key_version=key_vault_properties.key_version,
|
||||
key_vault_uri=key_vault_properties.key_vault_uri,
|
||||
)
|
||||
else:
|
||||
managed_disk_encryption = None
|
||||
|
||||
workspaces[subscription][workspace.id] = DatabricksWorkspace(
|
||||
id=workspace.id,
|
||||
@@ -55,6 +75,7 @@ class Databricks(AzureService):
|
||||
)
|
||||
else None
|
||||
),
|
||||
managed_disk_encryption=managed_disk_encryption,
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
@@ -63,6 +84,21 @@ class Databricks(AzureService):
|
||||
return workspaces
|
||||
|
||||
|
||||
class ManagedDiskEncryption(BaseModel):
|
||||
"""
|
||||
Pydantic model representing the encryption settings for a workspace's managed disks.
|
||||
|
||||
Attributes:
|
||||
key_name: The name of the key used for encryption.
|
||||
key_version: The version of the key used for encryption.
|
||||
key_vault_uri: The URI of the key vault containing the key used for encryption.
|
||||
"""
|
||||
|
||||
key_name: str
|
||||
key_version: str
|
||||
key_vault_uri: str
|
||||
|
||||
|
||||
class DatabricksWorkspace(BaseModel):
|
||||
"""
|
||||
Pydantic model representing an Azure Databricks workspace.
|
||||
@@ -72,9 +108,11 @@ class DatabricksWorkspace(BaseModel):
|
||||
name: The name of the workspace.
|
||||
location: The Azure region where the workspace is deployed.
|
||||
custom_managed_vnet_id: The ID of the custom managed virtual network, if configured.
|
||||
managed_disk_encryption: The encryption settings for the workspace's managed disks.
|
||||
"""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
location: str
|
||||
custom_managed_vnet_id: Optional[str]
|
||||
custom_managed_vnet_id: Optional[str] = None
|
||||
managed_disk_encryption: Optional[ManagedDiskEncryption] = None
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "azure",
|
||||
"CheckID": "databricks_workspace_cmk_encryption_enabled",
|
||||
"CheckTitle": "Ensure Azure Databricks workspaces use customer-managed keys (CMK) for encryption at rest",
|
||||
"CheckType": [],
|
||||
"ServiceName": "databricks",
|
||||
"SubServiceName": "workspace",
|
||||
"ResourceIdTemplate": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Databricks/workspaces/{workspaceName}",
|
||||
"Severity": "high",
|
||||
"ResourceType": "AzureDatabricksWorkspace",
|
||||
"Description": "Checks whether Azure Databricks workspaces are configured to use customer-managed keys (CMK) for encryption at rest, providing greater control over data encryption and compliance.",
|
||||
"Risk": "Without CMK, organizations have less control over encryption keys, which may impact regulatory compliance and increase risk of unauthorized data access.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/azure/databricks/security/keys/customer-managed-keys",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "az databricks workspace update --name <databricks-workspace-name> --resource-group <resource-group-name> --prepare-encryption && databricks workspace update --name <databricks-workspace-name> --resource-group <resource-group-name> --key-source 'Microsoft.KeyVault' --key-name <key-name> --key-vault <key-vault-uri> --key-version <key-version>",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Enable customer-managed keys (CMK) for Databricks workspaces using Azure Key Vault to enhance control over data encryption, auditing, and compliance.",
|
||||
"Url": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/azure/Databricks/enable-encryption-with-cmk.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Customer-managed key (CMK) encryption is only available for Databricks workspaces on the Premium tier."
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_Azure
|
||||
from prowler.providers.azure.services.databricks.databricks_client import (
|
||||
databricks_client,
|
||||
)
|
||||
|
||||
|
||||
class databricks_workspace_cmk_encryption_enabled(Check):
|
||||
"""
|
||||
Ensure Azure Databricks workspaces use customer-managed keys (CMK) for encryption at rest.
|
||||
|
||||
This check evaluates whether each Azure Databricks workspace in the subscription is configured to use a customer-managed key (CMK) for encrypting data at rest.
|
||||
|
||||
- PASS: The workspace has CMK encryption enabled (managed_disk_encryption is set).
|
||||
- FAIL: The workspace does not have CMK encryption enabled.
|
||||
"""
|
||||
|
||||
def execute(self):
|
||||
findings = []
|
||||
for subscription, workspaces in databricks_client.workspaces.items():
|
||||
for workspace in workspaces.values():
|
||||
report = Check_Report_Azure(
|
||||
metadata=self.metadata(), resource=workspace
|
||||
)
|
||||
report.subscription = subscription
|
||||
enc = workspace.managed_disk_encryption
|
||||
if enc:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Databricks workspace {workspace.name} in subscription {subscription} has customer-managed key (CMK) encryption enabled with key {enc.key_vault_uri}/{enc.key_name}/{enc.key_version}."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Databricks workspace {workspace.name} in subscription {subscription} does not have customer-managed key (CMK) encryption enabled."
|
||||
findings.append(report)
|
||||
return findings
|
||||
@@ -3,6 +3,7 @@ from unittest.mock import patch
|
||||
from prowler.providers.azure.services.databricks.databricks_service import (
|
||||
Databricks,
|
||||
DatabricksWorkspace,
|
||||
ManagedDiskEncryption,
|
||||
)
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
AZURE_SUBSCRIPTION_ID,
|
||||
@@ -18,6 +19,11 @@ def mock_databricks_get_workspaces(_):
|
||||
name="test-workspace",
|
||||
location="eastus",
|
||||
custom_managed_vnet_id="test-vnet-id",
|
||||
managed_disk_encryption=ManagedDiskEncryption(
|
||||
key_name="test-key",
|
||||
key_version="test-version",
|
||||
key_vault_uri="test-vault-uri",
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -48,3 +54,39 @@ class Test_Databricks_Service:
|
||||
assert workspace.name == "test-workspace"
|
||||
assert workspace.location == "eastus"
|
||||
assert workspace.custom_managed_vnet_id == "test-vnet-id"
|
||||
assert (
|
||||
workspace.managed_disk_encryption.__class__.__name__
|
||||
== "ManagedDiskEncryption"
|
||||
)
|
||||
assert workspace.managed_disk_encryption.key_name == "test-key"
|
||||
assert workspace.managed_disk_encryption.key_version == "test-version"
|
||||
assert workspace.managed_disk_encryption.key_vault_uri == "test-vault-uri"
|
||||
|
||||
|
||||
def mock_databricks_get_workspaces_no_encryption(_):
|
||||
return {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
"test-workspace-id": DatabricksWorkspace(
|
||||
id="test-workspace-id",
|
||||
name="test-workspace",
|
||||
location="eastus",
|
||||
custom_managed_vnet_id="test-vnet-id",
|
||||
managed_disk_encryption=None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@patch(
|
||||
"prowler.providers.azure.services.databricks.databricks_service.Databricks._get_workspaces",
|
||||
new=mock_databricks_get_workspaces_no_encryption,
|
||||
)
|
||||
class Test_Databricks_Service_No_Encryption:
|
||||
def test_get_workspaces_no_encryption(self):
|
||||
databricks = Databricks(set_mocked_azure_provider())
|
||||
workspace = databricks.workspaces[AZURE_SUBSCRIPTION_ID]["test-workspace-id"]
|
||||
assert workspace.id == "test-workspace-id"
|
||||
assert workspace.name == "test-workspace"
|
||||
assert workspace.location == "eastus"
|
||||
assert workspace.custom_managed_vnet_id == "test-vnet-id"
|
||||
assert workspace.managed_disk_encryption is None
|
||||
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from prowler.providers.azure.services.databricks.databricks_service import (
|
||||
DatabricksWorkspace,
|
||||
ManagedDiskEncryption,
|
||||
)
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
AZURE_SUBSCRIPTION_ID,
|
||||
set_mocked_azure_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_databricks_workspace_cmk_encryption_enabled:
|
||||
def test_no_databricks_workspaces(self):
|
||||
databricks_client = mock.MagicMock
|
||||
databricks_client.workspaces = {}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.databricks.databricks_workspace_cmk_encryption_enabled.databricks_workspace_cmk_encryption_enabled.databricks_client",
|
||||
new=databricks_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.databricks.databricks_workspace_cmk_encryption_enabled.databricks_workspace_cmk_encryption_enabled import (
|
||||
databricks_workspace_cmk_encryption_enabled,
|
||||
)
|
||||
|
||||
check = databricks_workspace_cmk_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_databricks_workspace_cmk_encryption_disabled(self):
|
||||
workspace_id = str(uuid4())
|
||||
workspace_name = "test-workspace"
|
||||
|
||||
databricks_client = mock.MagicMock
|
||||
databricks_client.workspaces = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
workspace_id: DatabricksWorkspace(
|
||||
id=workspace_id,
|
||||
name=workspace_name,
|
||||
location="eastus",
|
||||
custom_managed_vnet_id=None,
|
||||
managed_disk_encryption=None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.databricks.databricks_workspace_cmk_encryption_enabled.databricks_workspace_cmk_encryption_enabled.databricks_client",
|
||||
new=databricks_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.databricks.databricks_workspace_cmk_encryption_enabled.databricks_workspace_cmk_encryption_enabled import (
|
||||
databricks_workspace_cmk_encryption_enabled,
|
||||
)
|
||||
|
||||
check = databricks_workspace_cmk_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Databricks workspace {workspace_name} in subscription {AZURE_SUBSCRIPTION_ID} does not have customer-managed key (CMK) encryption enabled."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == workspace_name
|
||||
assert result[0].resource_id == workspace_id
|
||||
assert result[0].location == "eastus"
|
||||
|
||||
def test_databricks_workspace_cmk_encryption_enabled(self):
|
||||
workspace_id = str(uuid4())
|
||||
workspace_name = "test-workspace"
|
||||
key_name = "test-key"
|
||||
key_version = "test-version"
|
||||
key_vault_uri = "test-vault-uri"
|
||||
|
||||
databricks_client = mock.MagicMock
|
||||
databricks_client.workspaces = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
workspace_id: DatabricksWorkspace(
|
||||
id=workspace_id,
|
||||
name=workspace_name,
|
||||
location="eastus",
|
||||
custom_managed_vnet_id=None,
|
||||
managed_disk_encryption=ManagedDiskEncryption(
|
||||
key_name=key_name,
|
||||
key_version=key_version,
|
||||
key_vault_uri=key_vault_uri,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.databricks.databricks_workspace_cmk_encryption_enabled.databricks_workspace_cmk_encryption_enabled.databricks_client",
|
||||
new=databricks_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.databricks.databricks_workspace_cmk_encryption_enabled.databricks_workspace_cmk_encryption_enabled import (
|
||||
databricks_workspace_cmk_encryption_enabled,
|
||||
)
|
||||
|
||||
check = databricks_workspace_cmk_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Databricks workspace {workspace_name} in subscription {AZURE_SUBSCRIPTION_ID} has customer-managed key (CMK) encryption enabled with key {key_vault_uri}/{key_name}/{key_version}."
|
||||
)
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].resource_name == workspace_name
|
||||
assert result[0].resource_id == workspace_id
|
||||
assert result[0].location == "eastus"
|
||||
Reference in New Issue
Block a user