Virtual Machine has a backup policy with a daily retention period meeting the configured minimum
Azure virtual machines are evaluated for a backup policy in a Recovery Services vault with a daily retention period that meets the configured minimum. VMs lacking protection or using a shorter retention window are identified for review.
Risk
Insufficient or missing VM backups weaken availability and integrity. Short retention reduces recovery points, limiting rollback after ransomware, accidental deletion, or faulty changes. This increases RPO, extends RTO, and can force rebuilds, causing data loss and downtime.
Run this check with Prowler
Run in Prowler Cloudprowler azure --checks vm_sufficient_daily_backup_retention_periodRecommendation
Enforce backup policies that provide daily retention aligned to business RPO/RTO for every VM. Apply defense in depth: isolate backups in a vault, enable immutability/soft delete, limit changes with least privilege and MFA, and regularly test restores. Use tiered retention (daily/weekly/monthly/yearly) based on data criticality.
Remediation
Terraform
# Backup policy with sufficient daily retention
resource "azurerm_backup_policy_vm" "<example_resource_name>" {
name = "<example_resource_name>"
resource_group_name = "<example_resource_name>"
recovery_vault_name = "<example_resource_name>"
backup {
frequency = "Daily"
time = "23:00"
}
retention_daily {
count = 7 # CRITICAL: ensures daily retention meets minimum required days
}
}
# Protect the VM with the compliant policy
resource "azurerm_backup_protected_vm" "<example_resource_name>" {
resource_group_name = "<example_resource_name>"
recovery_vault_name = "<example_resource_name>"
source_vm_id = "<example_resource_id>"
backup_policy_id = azurerm_backup_policy_vm.<example_resource_name>.id # CRITICAL: applies the policy to the VM
}NativeIaC
// Create/ensure a VM backup policy with daily retention >= minimum
resource rv 'Microsoft.RecoveryServices/vaults@2023-01-01' existing = {
name: '<example_resource_name>'
}
resource vmPolicy 'Microsoft.RecoveryServices/vaults/backupPolicies@2023-02-01' = {
name: '${rv.name}/<example_resource_name>'
properties: {
backupManagementType: 'AzureIaasVM'
schedulePolicy: {
schedulePolicyType: 'SimpleSchedulePolicyV2'
scheduleRunFrequency: 'Daily'
scheduleRunTimes: ['2020-01-01T23:00:00Z']
}
retentionPolicy: {
retentionPolicyType: 'LongTermRetentionPolicy'
dailySchedule: {
retentionTimes: ['2020-01-01T23:00:00Z']
retentionDuration: {
count: 7 // CRITICAL: sets daily retention to at least the minimum required days
durationType: 'Days' // explains the unit
}
}
}
}
}Other
Check Code
from azure.mgmt.recoveryservicesbackup.activestamp.models import DataSourceType
from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.recovery.recovery_client import recovery_client
from prowler.providers.azure.services.vm.vm_client import vm_client
class vm_sufficient_daily_backup_retention_period(Check):
"""
Ensure there is a sufficient daily backup retention period configured for Azure virtual machines.
- PASS: The VM has a backup policy with sufficient daily retention period.
- FAIL: The VM does not have a backup policy or the retention period is insufficient.
"""
def execute(self) -> list[Check_Report_Azure]:
findings = []
min_retention_days = getattr(vm_client, "audit_config", {}).get(
"vm_backup_min_daily_retention_days", 7
)
for subscription, vms in vm_client.virtual_machines.items():
subscription_name = recovery_client.subscriptions.get(
subscription, subscription
)
vaults = recovery_client.vaults.get(subscription, {})
for vm in vms.values():
backup_found = False
retention_days = None
for vault in vaults.values():
for backup_item in vault.backup_protected_items.values():
if (
backup_item.workload_type == DataSourceType.VM
and backup_item.name.split(";")[-1].lower()
== vm.resource_name.lower()
):
backup_found = True
policy_id = backup_item.backup_policy_id
if policy_id and policy_id in vault.backup_policies:
retention_days = vault.backup_policies[
policy_id
].retention_days
break
if backup_found:
break
if backup_found and retention_days:
report = Check_Report_Azure(metadata=self.metadata(), resource=vm)
report.subscription = subscription
if retention_days >= min_retention_days:
report.status = "PASS"
report.status_extended = f"VM {vm.resource_name} in subscription {subscription_name} ({subscription}) has a daily backup retention period of {retention_days} days (minimum required: {min_retention_days})."
else:
report.status = "FAIL"
report.status_extended = f"VM {vm.resource_name} in subscription {subscription_name} ({subscription}) has insufficient daily backup retention period of {retention_days} days (minimum required: {min_retention_days})."
findings.append(report)
return findings