fix(azure): accept AuditEvent key vault diagnostics (#11660)

Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
This commit is contained in:
Davlet Dzhakishev
2026-06-29 14:05:12 +02:00
committed by GitHub
parent 58eb0fa095
commit cd56985480
4 changed files with 165 additions and 12 deletions
+1 -3
View File
@@ -22,10 +22,8 @@ All notable changes to the **Prowler SDK** are documented in this file.
### 🐞 Fixed
- Compliance frameworks contributed by several external packages under the same provider are now merged instead of overwritten, so every entry-point directory a provider contributes is discovered [(#11578)](https://github.com/prowler-cloud/prowler/pull/11578)
### 🐞 Fixed
- Azure PostgreSQL flexible server collection no longer drops the remaining servers in a subscription when one server fails to collect; the `connection_throttle.enable` parameter (removed in PostgreSQL 16+) is treated as absent only when the Azure SDK reports it as not found, so unexpected lookup failures are not silently reported as throttling disabled [(#11595)](https://github.com/prowler-cloud/prowler/pull/11595)
- Azure `keyvault_logging_enabled` now accepts Key Vault diagnostic settings that enable the explicit `AuditEvent` category, avoiding false failures when Azure returns category-based logs without category groups [(#11660)](https://github.com/prowler-cloud/prowler/pull/11660)
---
@@ -9,7 +9,7 @@
"Severity": "high",
"ResourceType": "microsoft.keyvault/vaults",
"ResourceGroup": "security",
"Description": "**Azure Key Vault** diagnostic settings capture **audit logs** (`AuditEvent`) when category groups `audit` and `allLogs` are enabled and routed to a supported destination. Logged events include management and data-plane operations on vaults, keys, secrets, and certificates.",
"Description": "**Azure Key Vault** diagnostic settings capture **audit logs** (`AuditEvent`) when the `AuditEvent` category is enabled, or when category groups `audit` and `allLogs` are enabled, and routed to a supported destination. Logged events include management and data-plane operations on vaults, keys, secrets, and certificates.",
"Risk": "Without **Key Vault audit logging**, access and changes to keys, secrets, and certificates are untracked.\n\nAttackers can misuse keys to decrypt data, alter or delete crypto material, and evade detection-eroding **confidentiality** and **integrity** and delaying **incident response**.",
"RelatedUrl": "",
"AdditionalURLs": [
@@ -20,13 +20,13 @@
],
"Remediation": {
"Code": {
"CLI": "az monitor diagnostic-settings create --name <example_resource_name> --resource <example_resource_id> --workspace <example_resource_id> --logs '[{\"categoryGroup\":\"audit\",\"enabled\":true},{\"categoryGroup\":\"allLogs\",\"enabled\":true}]'",
"NativeIaC": "```bicep\n// Enable Key Vault diagnostic settings with audit + allLogs\nparam keyVaultName string\nparam workspaceId string\n\nresource kv 'Microsoft.KeyVault/vaults@2023-07-01' existing = {\n name: keyVaultName\n}\n\nresource diag 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {\n name: '<example_resource_name>'\n scope: kv\n properties: {\n workspaceId: workspaceId\n logs: [\n {\n categoryGroup: 'audit' // critical: enables audit logs\n enabled: true // required to pass the check\n }\n {\n categoryGroup: 'allLogs' // critical: enables allLogs group\n enabled: true // required to pass the check\n }\n ]\n }\n}\n```",
"Other": "1. In Azure Portal, go to your Key Vault > Monitoring > Diagnostic settings\n2. Click Add diagnostic setting\n3. Under Category groups, select audit and allLogs\n4. Choose a destination (e.g., Send to Log Analytics workspace) and select the workspace\n5. Click Save",
"Terraform": "```hcl\n# Enable diagnostic settings on Key Vault with audit + allLogs\nresource \"azurerm_monitor_diagnostic_setting\" \"<example_resource_name>\" {\n name = \"<example_resource_name>\"\n target_resource_id = \"<example_resource_id>\" # Key Vault resource ID\n log_analytics_workspace_id = \"<example_resource_id>\" # Destination workspace ID\n\n enabled_log { # critical: audit category group\n category_group = \"audit\" # enables audit logs\n }\n enabled_log { # critical: allLogs category group\n category_group = \"allLogs\" # enables all logs\n }\n}\n```"
"CLI": "az monitor diagnostic-settings create --name <example_resource_name> --resource <example_resource_id> --workspace <example_resource_id> --logs '[{\"category\":\"AuditEvent\",\"enabled\":true}]'",
"NativeIaC": "```bicep\n// Enable Key Vault AuditEvent diagnostic logs\nparam keyVaultName string\nparam workspaceId string\n\nresource kv 'Microsoft.KeyVault/vaults@2023-07-01' existing = {\n name: keyVaultName\n}\n\nresource diag 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {\n name: '<example_resource_name>'\n scope: kv\n properties: {\n workspaceId: workspaceId\n logs: [\n {\n category: 'AuditEvent'\n enabled: true\n }\n ]\n }\n}\n```",
"Other": "1. In Azure Portal, go to your Key Vault > Monitoring > Diagnostic settings\n2. Click Add diagnostic setting\n3. Enable AuditEvent audit logs, or select the audit and allLogs category groups\n4. Choose a destination (e.g., Send to Log Analytics workspace) and select the workspace\n5. Click Save",
"Terraform": "```hcl\n# Enable AuditEvent diagnostic logs on Key Vault\nresource \"azurerm_monitor_diagnostic_setting\" \"<example_resource_name>\" {\n name = \"<example_resource_name>\"\n target_resource_id = \"<example_resource_id>\"\n log_analytics_workspace_id = \"<example_resource_id>\"\n\n enabled_log {\n category = \"AuditEvent\"\n }\n}\n```"
},
"Recommendation": {
"Text": "Enable **diagnostic settings** to collect `AuditEvent` logs-covering category groups `audit` and `allLogs`-and send them to a central sink. Apply **least privilege** to log access, enforce secure **retention/immutability**, monitor with alerts for anomalous operations, and use **separation of duties** to prevent logging bypass.",
"Text": "Enable **diagnostic settings** to collect `AuditEvent` logs and send them to a central sink. Apply **least privilege** to log access, enforce secure **retention/immutability**, monitor with alerts for anomalous operations, and use **separation of duties** to prevent logging bypass.",
"Url": "https://hub.prowler.com/check/keyvault_logging_enabled"
}
},
@@ -16,14 +16,17 @@ class keyvault_logging_enabled(Check):
report.status = "FAIL"
report.status_extended = f"Key Vault {keyvault.name} in subscription {subscription_name} ({subscription_id}) does not have a diagnostic setting with audit logging."
for diagnostic_setting in keyvault.monitor_diagnostic_settings or []:
has_audit = False
has_audit_category = False
has_audit_group = False
has_all_logs = False
for log in diagnostic_setting.logs:
if log.category == "AuditEvent" and log.enabled:
has_audit_category = True
if log.category_group == "audit" and log.enabled:
has_audit = True
has_audit_group = True
if log.category_group == "allLogs" and log.enabled:
has_all_logs = True
if has_audit and has_all_logs:
if has_audit_category or (has_audit_group and has_all_logs):
report.status = "PASS"
report.status_extended = f"Key Vault {keyvault.name} in subscription {subscription_name} ({subscription_id}) has a diagnostic setting with audit logging."
break
@@ -244,6 +244,158 @@ class Test_keyvault_logging_enabled:
assert result[0].resource_name == "name_keyvault"
assert result[0].resource_id == "id"
def test_diagnostic_setting_with_audit_event_category_logging(self):
keyvault_client = mock.MagicMock
keyvault_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.monitor.monitor_service.Monitor",
new=mock.MagicMock(),
),
mock.patch(
"prowler.providers.azure.services.keyvault.keyvault_logging_enabled.keyvault_logging_enabled.keyvault_client",
new=keyvault_client,
),
):
from prowler.providers.azure.services.keyvault.keyvault_logging_enabled.keyvault_logging_enabled import (
keyvault_logging_enabled,
)
from prowler.providers.azure.services.keyvault.keyvault_service import (
KeyVaultInfo,
)
from prowler.providers.azure.services.monitor.monitor_service import (
DiagnosticSetting,
)
keyvault_client.key_vaults = {
AZURE_SUBSCRIPTION_ID: [
KeyVaultInfo(
id="id",
name="name_keyvault",
location="westeurope",
resource_group="resource_group",
properties=VaultProperties(
tenant_id="tenantid",
sku="sku",
enable_rbac_authorization=False,
),
keys=[],
secrets=[],
monitor_diagnostic_settings=[
DiagnosticSetting(
id="id/ds1",
logs=[
mock.MagicMock(
category_group=None,
category="AuditEvent",
enabled=True,
),
mock.MagicMock(
category_group=None,
category="AzurePolicyEvaluationDetails",
enabled=False,
),
],
storage_account_name="sa1",
storage_account_id="sa_id1",
name="ds_audit_event",
),
],
),
]
}
check = keyvault_logging_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Key Vault name_keyvault in subscription {AZURE_SUBSCRIPTION_DISPLAY} has a diagnostic setting with audit logging."
)
assert result[0].resource_name == "name_keyvault"
assert result[0].resource_id == "id"
def test_diagnostic_setting_with_audit_event_category_disabled(self):
keyvault_client = mock.MagicMock
keyvault_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.monitor.monitor_service.Monitor",
new=mock.MagicMock(),
),
mock.patch(
"prowler.providers.azure.services.keyvault.keyvault_logging_enabled.keyvault_logging_enabled.keyvault_client",
new=keyvault_client,
),
):
from prowler.providers.azure.services.keyvault.keyvault_logging_enabled.keyvault_logging_enabled import (
keyvault_logging_enabled,
)
from prowler.providers.azure.services.keyvault.keyvault_service import (
KeyVaultInfo,
)
from prowler.providers.azure.services.monitor.monitor_service import (
DiagnosticSetting,
)
keyvault_client.key_vaults = {
AZURE_SUBSCRIPTION_ID: [
KeyVaultInfo(
id="id",
name="name_keyvault",
location="westeurope",
resource_group="resource_group",
properties=VaultProperties(
tenant_id="tenantid",
sku="sku",
enable_rbac_authorization=False,
),
keys=[],
secrets=[],
monitor_diagnostic_settings=[
DiagnosticSetting(
id="id/ds1",
logs=[
mock.MagicMock(
category_group=None,
category="AuditEvent",
enabled=False,
),
mock.MagicMock(
category_group=None,
category="AzurePolicyEvaluationDetails",
enabled=False,
),
],
storage_account_name="sa1",
storage_account_id="sa_id1",
name="ds_audit_event_disabled",
),
],
),
]
}
check = keyvault_logging_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Key Vault name_keyvault in subscription {AZURE_SUBSCRIPTION_DISPLAY} does not have a diagnostic setting with audit logging."
)
assert result[0].resource_name == "name_keyvault"
assert result[0].resource_id == "id"
def test_multiple_diagnostic_settings_one_compliant(self):
keyvault_client = mock.MagicMock
keyvault_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}