Key Vault has soft delete and purge protection enabled
Azure Key Vault recoverability requires both enable_soft_delete and enable_purge_protection. With these enabled, vault objects remain recoverable after deletion and cannot be permanently purged during the retention period.
Risk
Absent these protections, deleted vaults or objects can be permanently removed, cutting access to keys, secrets, and certificates. This can render data unreadable, break app authentication, and halt signing/verification, degrading availability and integrity. Malicious insiders can purge to block recovery.
Run this check with Prowler
Run in Prowler Cloudprowler azure --checks keyvault_recoverableRecommendation
Enable both enable_soft_delete and enable_purge_protection on all vaults. Enforce with policy, restrict purge/recover to least privilege and apply separation of duties. Keep backups and test recovery. Monitor delete/purge with alerts. Adjust retention to business needs to strengthen defense in depth.
Remediation
CLI
az keyvault update -g <resourceGroupName> -n <keyVaultName> --enable-soft-delete true --enable-purge-protection trueTerraform
resource "azurerm_key_vault" "<example_resource_name>" {
name = "<example_resource_name>"
location = "<location>"
resource_group_name = "<resource_group_name>"
tenant_id = "<tenant_id>"
sku_name = "standard"
soft_delete_enabled = true # Critical: enables soft delete
purge_protection_enabled = true # Critical: enables purge protection
}NativeIaC
// Enable soft delete and purge protection on an existing/new Key Vault
resource kv 'Microsoft.KeyVault/vaults@2023-07-01' = {
name: '<example_resource_name>'
location: '<location>'
properties: {
tenantId: '<tenant_id>'
sku: { name: 'standard' }
enableSoftDelete: true // Critical: ensures soft delete is enabled
enablePurgeProtection: true // Critical: prevents permanent purge during retention
}
}Other
Check Code
from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.keyvault.keyvault_client import keyvault_client
class keyvault_recoverable(Check):
def execute(self) -> Check_Report_Azure:
findings = []
for subscription, key_vaults in keyvault_client.key_vaults.items():
subscription_name = keyvault_client.subscriptions.get(
subscription, subscription
)
for keyvault in key_vaults:
report = Check_Report_Azure(metadata=self.metadata(), resource=keyvault)
report.subscription = subscription
report.status = "FAIL"
report.status_extended = f"Keyvault {keyvault.name} from subscription {subscription_name} ({subscription}) is not recoverable."
if (
keyvault.properties.enable_soft_delete
and keyvault.properties.enable_purge_protection
):
report.status = "PASS"
report.status_extended = f"Keyvault {keyvault.name} from subscription {subscription_name} ({subscription}) is recoverable."
findings.append(report)
return findings