feat(azure): Azure new check policy_ensure_asc_enforcement_enabled (#3452)

Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
This commit is contained in:
Rubén De la Torre Vico
2024-02-27 13:34:28 +01:00
committed by GitHub
parent bd05aaa4f9
commit 73733f674c
10 changed files with 290 additions and 2 deletions

18
poetry.lock generated
View File

@@ -485,6 +485,22 @@ azure-common = ">=1.1,<2.0"
azure-mgmt-core = ">=1.3.0,<2.0.0" azure-mgmt-core = ">=1.3.0,<2.0.0"
msrest = ">=0.6.21" msrest = ">=0.6.21"
[[package]]
name = "azure-mgmt-resource"
version = "23.0.1"
description = "Microsoft Azure Resource Management Client Library for Python"
optional = false
python-versions = ">=3.7"
files = [
{file = "azure-mgmt-resource-23.0.1.zip", hash = "sha256:c2ba6cfd99df95f55f36eadc4245e3dc713257302a1fd0277756d94bd8cb28e0"},
{file = "azure_mgmt_resource-23.0.1-py3-none-any.whl", hash = "sha256:f185eec72bbc39f42bcb83ae6f1bad744f0e3f20a12d9b2b3e70d16c74ad9cc0"},
]
[package.dependencies]
azure-common = ">=1.1,<2.0"
azure-mgmt-core = ">=1.3.2,<2.0.0"
isodate = ">=0.6.1,<1.0.0"
[[package]] [[package]]
name = "azure-mgmt-security" name = "azure-mgmt-security"
version = "6.0.0" version = "6.0.0"
@@ -4393,4 +4409,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = ">=3.9,<3.13" python-versions = ">=3.9,<3.13"
content-hash = "ab8c8f47bee7e9efdfcb3c736ccd97ea74cd8c601168541e64e3c2c486b9ae58" content-hash = "266ed59973207ca74ea393dfeed3ce27bb4b7244214cefb7260758803ca938fb"

View File

@@ -0,0 +1,4 @@
from prowler.providers.azure.lib.audit_info.audit_info import azure_audit_info
from prowler.providers.azure.services.policy.policy_service import Policy
policy_client = Policy(azure_audit_info)

View File

@@ -0,0 +1,30 @@
{
"Provider": "azure",
"CheckID": "policy_ensure_asc_enforcement_enabled",
"CheckTitle": "Ensure Any of the ASC Default Policy Settings are Not Set to 'Disabled'",
"CheckType": [],
"ServiceName": "policy",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "Microsoft.Authorization/policyAssignments",
"Description": "None of the settings offered by ASC Default policy should be set to effect Disabled.",
"Risk": "A security policy defines the desired configuration of your workloads and helps ensure compliance with company or regulatory security requirements. ASC Default policy is associated with every subscription by default. ASC default policy assignment is a set of security recommendations based on best practices. Enabling recommendations in ASC default policy ensures that Azure security center provides the ability to monitor all of the supported recommendations and optionally allow automated action for a few of the supported recommendations.",
"RelatedUrl": "https://learn.microsoft.com/en-us/azure/defender-for-cloud/security-policy-concept",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "1. From Azure Home select the Portal Menu 2. Select Policy 3. Select ASC Default for each subscription 4. Click on 'view Assignment' 5. Click on 'Edit assignment' 6. Ensure Policy Enforcement is Enabled 7. Click 'Review + Save'",
"Url": "https://learn.microsoft.com/en-us/azure/defender-for-cloud/implement-security-recommendations"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}

View File

@@ -0,0 +1,24 @@
from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.policy.policy_client import policy_client
class policy_ensure_asc_enforcement_enabled(Check):
def execute(self) -> Check_Report_Azure:
findings = []
for subscription_name, policies in policy_client.policy_assigments.items():
if "SecurityCenterBuiltIn" in policies:
report = Check_Report_Azure(self.metadata())
report.status = "PASS"
report.subscription = subscription_name
report.resource_name = "SecurityCenterBuiltIn"
report.resource_id = policies["SecurityCenterBuiltIn"].id
report.status_extended = f"Policy assigment '{policies['SecurityCenterBuiltIn'].id}' is configured with enforcement mode '{policies['SecurityCenterBuiltIn'].enforcement_mode}'."
if policies["SecurityCenterBuiltIn"].enforcement_mode != "Default":
report.status = "FAIL"
report.status_extended = f"Policy assigment '{policies['SecurityCenterBuiltIn'].id}' is not configured with enforcement mode Default."
findings.append(report)
return findings

View File

@@ -0,0 +1,45 @@
from dataclasses import dataclass
from azure.mgmt.resource.policy import PolicyClient
from prowler.lib.logger import logger
from prowler.providers.azure.lib.audit_info.models import Azure_Audit_Info
from prowler.providers.azure.lib.service.service import AzureService
########################## Policy
class Policy(AzureService):
def __init__(self, audit_info: Azure_Audit_Info):
super().__init__(PolicyClient, audit_info)
self.policy_assigments = self.__get_policy_assigments__()
def __get_policy_assigments__(self):
logger.info("Policy - Getting policy assigments...")
policy_assigments = {}
for subscription_name, client in self.clients.items():
try:
policy_assigments_list = client.policy_assignments.list()
policy_assigments.update({subscription_name: {}})
for policy_assigment in policy_assigments_list:
policy_assigments[subscription_name].update(
{
policy_assigment.name: PolicyAssigment(
id=policy_assigment.id,
enforcement_mode=policy_assigment.enforcement_mode,
)
}
)
except Exception as error:
logger.error(
f"Subscription name: {subscription_name} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return policy_assigments
@dataclass
class PolicyAssigment:
id: str
enforcement_mode: str

View File

@@ -33,10 +33,11 @@ azure-mgmt-applicationinsights = "4.0.0"
azure-mgmt-authorization = "4.0.0" azure-mgmt-authorization = "4.0.0"
azure-mgmt-compute = "30.5.0" azure-mgmt-compute = "30.5.0"
azure-mgmt-cosmosdb = "9.4.0" azure-mgmt-cosmosdb = "9.4.0"
azure-mgmt-monitor = "6.0.2"
azure-mgmt-keyvault = "10.3.0" azure-mgmt-keyvault = "10.3.0"
azure-mgmt-monitor = "6.0.2"
azure-mgmt-network = "25.3.0" azure-mgmt-network = "25.3.0"
azure-mgmt-rdbms = "10.1.0" azure-mgmt-rdbms = "10.1.0"
azure-mgmt-resource = "23.0.1"
azure-mgmt-security = "6.0.0" azure-mgmt-security = "6.0.0"
azure-mgmt-sql = "3.0.1" azure-mgmt-sql = "3.0.1"
azure-mgmt-storage = "21.1.0" azure-mgmt-storage = "21.1.0"

View File

@@ -0,0 +1,122 @@
from unittest import mock
from uuid import uuid4
from prowler.providers.azure.services.policy.policy_service import PolicyAssigment
from tests.providers.azure.azure_fixtures import AZURE_SUBSCRIPTION
class Test_policy_ensure_asc_enforcement_enabled:
def test_policy_no_subscriptions(self):
policy_client = mock.MagicMock
policy_client.policy_assigments = {}
with mock.patch(
"prowler.providers.azure.services.policy.policy_ensure_asc_enforcement_enabled.policy_ensure_asc_enforcement_enabled.policy_client",
new=policy_client,
):
from prowler.providers.azure.services.policy.policy_ensure_asc_enforcement_enabled.policy_ensure_asc_enforcement_enabled import (
policy_ensure_asc_enforcement_enabled,
)
check = policy_ensure_asc_enforcement_enabled()
result = check.execute()
assert len(result) == 0
def test_policy_subscription_empty(self):
policy_client = mock.MagicMock
policy_client.policy_assigments = {AZURE_SUBSCRIPTION: {}}
with mock.patch(
"prowler.providers.azure.services.policy.policy_ensure_asc_enforcement_enabled.policy_ensure_asc_enforcement_enabled.policy_client",
new=policy_client,
):
from prowler.providers.azure.services.policy.policy_ensure_asc_enforcement_enabled.policy_ensure_asc_enforcement_enabled import (
policy_ensure_asc_enforcement_enabled,
)
check = policy_ensure_asc_enforcement_enabled()
result = check.execute()
assert len(result) == 0
def test_policy_subscription_no_asc(self):
policy_client = mock.MagicMock
resource_id = uuid4()
policy_client.policy_assigments = {
AZURE_SUBSCRIPTION: {
"policy-1": PolicyAssigment(id=resource_id, enforcement_mode="Default")
}
}
with mock.patch(
"prowler.providers.azure.services.policy.policy_ensure_asc_enforcement_enabled.policy_ensure_asc_enforcement_enabled.policy_client",
new=policy_client,
):
from prowler.providers.azure.services.policy.policy_ensure_asc_enforcement_enabled.policy_ensure_asc_enforcement_enabled import (
policy_ensure_asc_enforcement_enabled,
)
check = policy_ensure_asc_enforcement_enabled()
result = check.execute()
assert len(result) == 0
def test_policy_subscription_asc_default(self):
policy_client = mock.MagicMock
resource_id = uuid4()
policy_client.policy_assigments = {
AZURE_SUBSCRIPTION: {
"SecurityCenterBuiltIn": PolicyAssigment(
id=resource_id, enforcement_mode="Default"
)
}
}
with mock.patch(
"prowler.providers.azure.services.policy.policy_ensure_asc_enforcement_enabled.policy_ensure_asc_enforcement_enabled.policy_client",
new=policy_client,
):
from prowler.providers.azure.services.policy.policy_ensure_asc_enforcement_enabled.policy_ensure_asc_enforcement_enabled import (
policy_ensure_asc_enforcement_enabled,
)
check = policy_ensure_asc_enforcement_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Policy assigment '{resource_id}' is configured with enforcement mode 'Default'."
)
assert result[0].resource_id == resource_id
assert result[0].resource_name == "SecurityCenterBuiltIn"
assert result[0].subscription == AZURE_SUBSCRIPTION
def test_policy_subscription_asc_not_default(self):
policy_client = mock.MagicMock
resource_id = uuid4()
policy_client.policy_assigments = {
AZURE_SUBSCRIPTION: {
"SecurityCenterBuiltIn": PolicyAssigment(
id=resource_id, enforcement_mode="DoNotEnforce"
)
}
}
with mock.patch(
"prowler.providers.azure.services.policy.policy_ensure_asc_enforcement_enabled.policy_ensure_asc_enforcement_enabled.policy_client",
new=policy_client,
):
from prowler.providers.azure.services.policy.policy_ensure_asc_enforcement_enabled.policy_ensure_asc_enforcement_enabled import (
policy_ensure_asc_enforcement_enabled,
)
check = policy_ensure_asc_enforcement_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Policy assigment '{resource_id}' is not configured with enforcement mode Default."
)
assert result[0].resource_id == resource_id
assert result[0].resource_name == "SecurityCenterBuiltIn"
assert result[0].subscription == AZURE_SUBSCRIPTION

View File

@@ -0,0 +1,46 @@
from unittest.mock import patch
from prowler.providers.azure.services.policy.policy_service import (
Policy,
PolicyAssigment,
)
from tests.providers.azure.azure_fixtures import (
AZURE_SUBSCRIPTION,
set_mocked_azure_audit_info,
)
def mock_policy_assigments(_):
return {
AZURE_SUBSCRIPTION: {
"policy-1": PolicyAssigment(id="id-1", enforcement_mode="Default")
}
}
@patch(
"prowler.providers.azure.services.policy.policy_service.Policy.__get_policy_assigments__",
new=mock_policy_assigments,
)
class Test_AppInsights_Service:
def test__get_client__(self):
policy = Policy(set_mocked_azure_audit_info())
assert policy.clients[AZURE_SUBSCRIPTION].__class__.__name__ == "PolicyClient"
def test__get_subscriptions__(self):
policy = Policy(set_mocked_azure_audit_info())
assert policy.subscriptions.__class__.__name__ == "dict"
def test__get_policy_assigments__(self):
policy = Policy(set_mocked_azure_audit_info())
assert policy.policy_assigments.__class__.__name__ == "dict"
assert policy.policy_assigments[AZURE_SUBSCRIPTION].__class__.__name__ == "dict"
assert (
policy.policy_assigments[AZURE_SUBSCRIPTION]["policy-1"].__class__.__name__
== "PolicyAssigment"
)
assert policy.policy_assigments[AZURE_SUBSCRIPTION]["policy-1"].id == "id-1"
assert (
policy.policy_assigments[AZURE_SUBSCRIPTION]["policy-1"].enforcement_mode
== "Default"
)