feat(azure): new monitoring check ensuring storage account with logs private (#3453)

Co-authored-by: Hugo Gálvez Ureña <hugogalvezu96@gmail.com>
This commit is contained in:
Hugo966
2024-03-01 13:38:33 +01:00
committed by GitHub
parent d431877114
commit b4a05f4be0
7 changed files with 228 additions and 1 deletions

View File

@@ -27,6 +27,9 @@ class Monitor(AzureService):
diagnostics_settings[subscription].append(
DiagnosticSetting(
id=setting.id,
storage_account_name=setting.storage_account_id.split("/")[
-1
],
logs=setting.logs,
storage_account_id=setting.storage_account_id,
)
@@ -43,4 +46,5 @@ class Monitor(AzureService):
class DiagnosticSetting:
id: str
storage_account_id: str
storage_account_name: str
logs: LogSettings

View File

@@ -0,0 +1,30 @@
{
"Provider": "azure",
"CheckID": "monitor_storage_container_with_activity_logs_is_private",
"CheckTitle": "Ensure the Storage Container Storing the Activity Logs is not Publicly Accessible",
"CheckType": [],
"ServiceName": "monitor",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "Monitor",
"Description": "The storage account container containing the activity log export should not be publicly accessible.",
"Risk": "Allowing public access to activity log content may aid an adversary in identifying weaknesses in the affected account's use or configuration.",
"RelatedUrl": "https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings",
"Remediation": {
"Code": {
"CLI": "az storage container set-permission --name insights-activity-logs --account-name <Storage Account Name> --public-access off",
"NativeIaC": "",
"Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/Monitor/check-for-publicly-accessible-activity-log-storage-container.html",
"Terraform": "https://docs.bridgecrew.io/docs/ensure-the-storage-container-storing-the-activity-logs-is-not-publicly-accessible#terraform"
},
"Recommendation": {
"Text": "1. From Azure Home select the Portal Menu 2. Search for Storage Accounts to access Storage account blade 3. Click on the storage account name 4. Click on Configuration under settings 5. Select Enabled under 'Allow Blob public access'",
"Url": "https://docs.microsoft.com/en-us/security/benchmark/azure/security-controls-v3-network-security#ns-2-secure-cloud-services-with-network-controls"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": "Configuring container Access policy to private will remove access from the container for everyone except owners of the storage account. Access policy needs to be set explicitly in order to allow access to other desired users."
}

View File

@@ -0,0 +1,32 @@
from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.monitor.monitor_client import monitor_client
from prowler.providers.azure.services.storage.storage_client import storage_client
class monitor_storage_account_with_activity_logs_is_private(Check):
def execute(self) -> Check_Report_Azure:
findings = []
for (
subscription_name,
diagnostic_settings,
) in monitor_client.diagnostics_settings.items():
for diagnostic_setting in diagnostic_settings:
for storage_account in storage_client.storage_accounts[
subscription_name
]:
if storage_account.name == diagnostic_setting.storage_account_name:
report = Check_Report_Azure(self.metadata())
report.subscription = subscription_name
report.resource_name = storage_account.name
report.resource_id = storage_account.id
if storage_account.allow_blob_public_access:
report.status = "FAIL"
report.status_extended = f"Blob public access enabled in storage account {storage_account.name} storing activity logs in subscription {subscription_name}."
else:
report.status = "PASS"
report.status_extended = f"Blob public access disabled in storage account {storage_account.name} storing activity logs in subscription {subscription_name}."
findings.append(report)
return findings

View File

@@ -64,6 +64,7 @@ class Test_monitor_diagnostic_setting_with_appropriate_categories:
mock.MagicMock(category="ResourceHealth", enabled=False),
],
storage_account_id="/subscriptions/1234a5-123a-123a-123a-1234567890ab/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/storageaccountname",
storage_account_name="storageaccountname",
),
DiagnosticSetting(
id="id2",
@@ -77,7 +78,8 @@ class Test_monitor_diagnostic_setting_with_appropriate_categories:
mock.MagicMock(category="Autoscale", enabled=False),
mock.MagicMock(category="ResourceHealth", enabled=False),
],
storage_account_id="/subscriptions/1224a5-123a-123a-123a-1234567890ab/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/storageaccountname",
storage_account_id="/subscriptions/1224a5-123a-123a-123a-1234567890ab/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/storageaccountname2",
storage_account_name="storageaccountname2",
),
]
}

View File

@@ -27,6 +27,7 @@ def mock_monitor_get_diagnostics_settings(_):
mock.MagicMock(category="ResourceHealth", enabled=False),
],
storage_account_id="/subscriptions/1234a5-123a-123a-123a-1234567890ab/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/storageaccountname",
storage_account_name="storageaccountname",
)
]
}

View File

@@ -0,0 +1,158 @@
from unittest import mock
from prowler.providers.azure.services.monitor.monitor_service import DiagnosticSetting
from prowler.providers.azure.services.storage.storage_service import Account
from tests.providers.azure.azure_fixtures import AZURE_SUBSCRIPTION
class Test_monitor_storage_account_with_activity_logs_is_private:
def test_monitor_storage_account_with_activity_logs_is_private_no_subscriptions(
self,
):
monitor_client = mock.MagicMock
monitor_client.diagnostics_settings = {}
with mock.patch(
"prowler.providers.azure.services.monitor.monitor_storage_account_with_activity_logs_is_private.monitor_storage_account_with_activity_logs_is_private.monitor_client",
new=monitor_client,
):
from prowler.providers.azure.services.monitor.monitor_storage_account_with_activity_logs_is_private.monitor_storage_account_with_activity_logs_is_private import (
monitor_storage_account_with_activity_logs_is_private,
)
check = monitor_storage_account_with_activity_logs_is_private()
result = check.execute()
assert len(result) == 0
def test_no_diagnostic_settings(self):
monitor_client = mock.MagicMock
monitor_client.diagnostics_settings = {AZURE_SUBSCRIPTION: []}
with mock.patch(
"prowler.providers.azure.services.monitor.monitor_storage_account_with_activity_logs_is_private.monitor_storage_account_with_activity_logs_is_private.monitor_client",
new=monitor_client,
):
from prowler.providers.azure.services.monitor.monitor_storage_account_with_activity_logs_is_private.monitor_storage_account_with_activity_logs_is_private import (
monitor_storage_account_with_activity_logs_is_private,
)
check = monitor_storage_account_with_activity_logs_is_private()
result = check.execute()
assert len(result) == 0
def test_diagnostic_settings_configured(self):
monitor_client = mock.MagicMock
storage_client = mock.MagicMock
monitor_client.diagnostics_settings = {
AZURE_SUBSCRIPTION: [
DiagnosticSetting(
id="id",
logs=[
mock.MagicMock(category="Administrative", enabled=True),
mock.MagicMock(category="Security", enabled=True),
mock.MagicMock(category="ServiceHealth", enabled=False),
mock.MagicMock(category="Alert", enabled=True),
mock.MagicMock(category="Recommendation", enabled=False),
mock.MagicMock(category="Policy", enabled=True),
mock.MagicMock(category="Autoscale", enabled=False),
],
storage_account_id="/subscriptions/1234a5-123a-123a-123a-1234567890ab/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/storageaccountname1",
storage_account_name="storageaccountname1",
),
DiagnosticSetting(
id="id2",
logs=[
mock.MagicMock(category="Administrative", enabled=True),
mock.MagicMock(category="Security", enabled=True),
mock.MagicMock(category="ServiceHealth", enabled=False),
mock.MagicMock(category="Alert", enabled=True),
mock.MagicMock(category="Recommendation", enabled=False),
mock.MagicMock(category="Policy", enabled=True),
mock.MagicMock(category="Autoscale", enabled=False),
],
storage_account_id="/subscriptions/1224a5-123a-123a-123a-1234567890ab/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/storageaccountname2",
storage_account_name="storageaccountname2",
),
]
}
storage_client.storage_accounts = {
AZURE_SUBSCRIPTION: [
Account(
id="/subscriptions/1234a5-123a-123a-123a-1234567890ab/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/storageaccountname1",
name="storageaccountname1",
resouce_group_name="rg",
enable_https_traffic_only=True,
infrastructure_encryption="Enabled",
allow_blob_public_access=True,
network_rule_set="AllowAll",
encryption_type="Microsoft.Storage",
minimum_tls_version="TLS1_2",
private_endpoint_connections=[],
key_expiration_period_in_days=365,
blob_properties=mock.MagicMock(
id="id",
name="name",
type="type",
default_service_version="default_service_version",
container_delete_retention_policy="container_delete_retention_policy",
),
),
Account(
id="/subscriptions/1224a5-123a-123a-123a-1234567890ab/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/storageaccountname2",
name="storageaccountname2",
resouce_group_name="rg",
enable_https_traffic_only=False,
infrastructure_encryption="Enabled",
allow_blob_public_access=False,
network_rule_set="AllowAll",
encryption_type="Microsoft.Storage",
minimum_tls_version="TLS1_2",
private_endpoint_connections=[],
key_expiration_period_in_days=365,
blob_properties=mock.MagicMock(
id="id",
name="name",
type="type",
default_service_version="default_service_version",
container_delete_retention_policy="container_delete_retention_policy",
),
),
]
}
with mock.patch(
"prowler.providers.azure.services.monitor.monitor_storage_account_with_activity_logs_is_private.monitor_storage_account_with_activity_logs_is_private.monitor_client",
new=monitor_client,
):
with mock.patch(
"prowler.providers.azure.services.monitor.monitor_storage_account_with_activity_logs_is_private.monitor_storage_account_with_activity_logs_is_private.storage_client",
new=storage_client,
):
from prowler.providers.azure.services.monitor.monitor_storage_account_with_activity_logs_is_private.monitor_storage_account_with_activity_logs_is_private import (
monitor_storage_account_with_activity_logs_is_private,
)
check = monitor_storage_account_with_activity_logs_is_private()
result = check.execute()
assert len(result) == 2
assert result[0].subscription == AZURE_SUBSCRIPTION
assert result[0].status == "FAIL"
assert (
result[0].resource_id
== "/subscriptions/1234a5-123a-123a-123a-1234567890ab/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/storageaccountname1"
)
assert result[0].resource_name == "storageaccountname1"
assert (
result[0].status_extended
== f"Blob public access enabled in storage account {storage_client.storage_accounts[AZURE_SUBSCRIPTION][0].name} storing activity logs in subscription {AZURE_SUBSCRIPTION}."
)
assert result[1].subscription == AZURE_SUBSCRIPTION
assert result[1].status == "PASS"
assert (
result[1].resource_id
== "/subscriptions/1224a5-123a-123a-123a-1234567890ab/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/storageaccountname2"
)
assert result[1].resource_name == "storageaccountname2"
assert (
result[1].status_extended
== f"Blob public access disabled in storage account {storage_client.storage_accounts[AZURE_SUBSCRIPTION][1].name} storing activity logs in subscription {AZURE_SUBSCRIPTION}."
)