# Azure VM Missing Deletion Protection

> A CanNotDelete lock is the last guardrail between a production Azure VM and one wrong az vm delete by anyone holding delete permissions. RC-266 flags running, production-classified VMs whose lock state is an explicit false, taken from the Microsoft.Authorization/locks lookup or a deletion_protection=false tag, and abstains when no signal exists.

Source: https://zop.dev/integrations/azure/recommendations/azure-vm-missing-deletion-protection
Updated: 2026-08-19

---

## The blast radius of a mistyped delete

Deleting an Azure VM is fast, silent, and final for the compute resource itself. Disks may
survive depending on their delete options, but the machine, its NIC associations, and its
runtime state are gone, and if backups were never configured the recovery path is a rebuild. A
`CanNotDelete` lock converts that scenario into a failed API call: the delete is refused until
someone with lock-management rights consciously removes the lock first, which is exactly the
deliberate two-step you want in front of production.

## Only production VMs are held to this bar

Dev and test machines are disposable by design, so the rule first requires production
classification: a production naming pattern or an explicit env=prod tag, whichever matched is
named in the finding. The tag is treated as the authoritative signal and the name match as a
guess. That ordering matters, since name-only classification had previously pulled ordinary
VMs into scope. Deallocated machines are also skipped; only running production workloads
generate findings.

## From fail-open to fail-closed

The instructive part of this rule is its history. The original gate fired when the lock signal
was absent or false, which meant every unlabelled production VM was flagged, an evidence-free
default. The current logic reads the discoverer's `deletion_protection` metadata (derived from
the Microsoft.Authorization/locks lookup set) first and fires only on an explicit `"false"`;
if that key is absent it falls back to requiring a literal `deletion_protection=false`
customer tag. No signal at all now means no finding.

## Audit lock coverage yourself

```bash
az lock list --resource-group <rg> \
  --query "[?level=='CanNotDelete'].{name:name, scope:id}" -o table
```

Compare against the resource group's production VMs; anything unlisted is unprotected.

## Cheap insurance

Locks cost nothing, apply in seconds (`az lock create --lock-type CanNotDelete ...`), and are
reversible by anyone with `Microsoft.Authorization/locks/*` rights, typically Owner or User
Access Administrator, which is the point: routine contributors can't delete around them.
Consider ReadOnly locks for the most critical machines, noting they also block writes like
resizes. Reader reproduces the detection; ZopNight places no locks itself.
