diff --git a/prowler/providers/azure/services/monitor/monitor_diagnostic_settings_exists/__init__.py b/prowler/providers/azure/services/monitor/monitor_diagnostic_settings_exists/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists.metadata.json b/prowler/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists.metadata.json new file mode 100644 index 0000000000..933be943c4 --- /dev/null +++ b/prowler/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "azure", + "CheckID": "monitor_diagnostic_settings_exists", + "CheckTitle": "Ensure that a 'Diagnostic Setting' exists for Subscription Activity Logs ", + "CheckType": [], + "ServiceName": "monitor", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "Monitor", + "Description": "Enable Diagnostic settings for exporting activity logs. Diagnostic settings are available for each individual resource within a subscription. Settings should be configured for all appropriate resources for your environment.", + "Risk": "A diagnostic setting controls how a diagnostic log is exported. By default, logs are retained only for 90 days. Diagnostic settings should be defined so that logs can be exported and stored for a longer duration in order to analyze security activities within an Azure subscription.", + "RelatedUrl": "https://learn.microsoft.com/en-us/cli/azure/monitor/diagnostic-settings?view=azure-cli-latest", + "Remediation": { + "Code": { + "CLI": "az monitor diagnostic-settings subscription create --subscription --name --location <[- -event-hub --event-hub-auth-rule ] [-- storage-account ] [--workspace ] --logs '' (e.g. [{category:Security,enabled:true},{category:Administrative,enabled:true},{cat egory:Alert,enabled:true},{category:Policy,enabled:true}])", + "NativeIaC": "", + "Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/azure/Monitor/subscription-activity-log-diagnostic-settings.html#trendmicro", + "Terraform": "" + }, + "Recommendation": { + "Text": "To enable Diagnostic Settings on a Subscription: 1. Go to Monitor 2. Click on Activity Log 3. Click on Export Activity Logs 4. Click + Add diagnostic setting 5. Enter a Diagnostic setting name 6. Select Categories for the diagnostic settings 7. Select the appropriate Destination details (this may be Log Analytics, Storage Account, Event Hub, or Partner solution) 8. Click Save To enable Diagnostic Settings on a specific resource: 1. Go to Monitor 2. Click Diagnostic settings 3. Click on the resource that has a diagnostics status of disabled 4. Select Add Diagnostic Setting 5. Enter a Diagnostic setting name 6. Select the appropriate log, metric, and destination. (this may be Log Analytics, Storage Account, Event Hub, or Partner solution) 7. Click save Repeat these step for all resources as needed.", + "Url": "https://docs.microsoft.com/en-us/azure/monitoring-and-diagnostics/monitoring-overview-activity-logs#export-the-activity-log-with-a-log-profile" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "By default, diagnostic setting is not set." +} diff --git a/prowler/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists.py b/prowler/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists.py new file mode 100644 index 0000000000..e26d834868 --- /dev/null +++ b/prowler/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists.py @@ -0,0 +1,27 @@ +from prowler.lib.check.models import Check, Check_Report_Azure +from prowler.providers.azure.services.monitor.monitor_client import monitor_client + + +class monitor_diagnostic_settings_exists(Check): + def execute(self) -> Check_Report_Azure: + findings = [] + + for ( + subscription_name, + diagnostic_settings, + ) in monitor_client.diagnostics_settings.items(): + report = Check_Report_Azure(self.metadata()) + report.subscription = subscription_name + report.status = "FAIL" + report.status_extended = ( + f"No diagnostic settings found in subscription {subscription_name}." + ) + if diagnostic_settings: + report.status = "PASS" + report.status_extended = ( + f"Diagnostic settings found in subscription {subscription_name}." + ) + + findings.append(report) + + return findings diff --git a/tests/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists_test.py b/tests/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists_test.py new file mode 100644 index 0000000000..a4033ce8d5 --- /dev/null +++ b/tests/providers/azure/services/monitor/monitor_diagnostic_settings_exists/monitor_diagnostic_settings_exists_test.py @@ -0,0 +1,149 @@ +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_diagnostic_settings_exists: + + def test_monitor_diagnostic_settings_exists_no_subscriptions( + self, + ): + monitor_client = mock.MagicMock + monitor_client.diagnostics_settings = {} + + with mock.patch( + "prowler.providers.azure.services.monitor.monitor_diagnostic_settings_exists.monitor_diagnostic_settings_exists.monitor_client", + new=monitor_client, + ): + from prowler.providers.azure.services.monitor.monitor_diagnostic_settings_exists.monitor_diagnostic_settings_exists import ( + monitor_diagnostic_settings_exists, + ) + + check = monitor_diagnostic_settings_exists() + 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_diagnostic_settings_exists.monitor_diagnostic_settings_exists.monitor_client", + new=monitor_client, + ): + from prowler.providers.azure.services.monitor.monitor_diagnostic_settings_exists.monitor_diagnostic_settings_exists import ( + monitor_diagnostic_settings_exists, + ) + + check = monitor_diagnostic_settings_exists() + result = check.execute() + assert len(result) == 1 + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"No diagnostic settings found in subscription {AZURE_SUBSCRIPTION}." + ) + + 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.CustomerManagedKeyVault", + 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_diagnostic_settings_exists.monitor_diagnostic_settings_exists.monitor_client", + new=monitor_client, + ): + with mock.patch( + "prowler.providers.azure.services.monitor.monitor_diagnostic_settings_exists.monitor_diagnostic_settings_exists.monitor_client", + new=monitor_client, + ): + from prowler.providers.azure.services.monitor.monitor_diagnostic_settings_exists.monitor_diagnostic_settings_exists import ( + monitor_diagnostic_settings_exists, + ) + + check = monitor_diagnostic_settings_exists() + result = check.execute() + assert len(result) == 1 + assert result[0].subscription == AZURE_SUBSCRIPTION + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Diagnostic settings found in subscription {AZURE_SUBSCRIPTION}." + )