Home / Azure

AzureHow-toBeginner

Introduction to Azure resource locks: CanNotDelete vs ReadOnly, and the side effects nobody mentions

What Azure resource locks do, how CanNotDelete and ReadOnly differ, how to add, list and remove them with az CLI and PowerShell, and which day-to-day operations a ReadOnly lock quietly breaks.

Deepak Bhardwaj5 min read

Applies toAzure Resource Manager locks on subscriptions, resource groups and resources; Azure CLI 2.x, Az PowerShell

What a lock is

A resource lock is a guard rail on the Azure Resource Manager (ARM) control plane. It stops people (and pipelines) from deleting or changing a resource, even if their RBAC role allows it. An Owner can still be blocked by a lock until the lock is removed.

There are two levels:

Lock level Portal name Blocks Allows
CanNotDelete Delete Delete of the resource (and the resource group / subscription if applied there) Read, update, scale, restart
ReadOnly Read-only Delete and any write (PUT/PATCH/POST) through ARM Read (GET) only

Locks are inherited. A lock on a resource group applies to every resource in it, including resources created later.

Tip

Use CanNotDelete for production resource groups, shared networking, Key Vaults and Log Analytics workspaces. Use ReadOnly rarely and on purpose; it breaks more than people expect (see below).

Add a lock

Azure CLI

# Lock a whole resource group against deletion
az lock create \
  --name rg-prod-nodelete \
  --resource-group rg-prod-app \
  --lock-type CanNotDelete \
  --notes "Production. Raise a change before removing."

# Lock one resource
az lock create \
  --name kv-nodelete \
  --resource-group rg-prod-app \
  --resource-name kv-prod-app01 \
  --resource-type Microsoft.KeyVault/vaults \
  --lock-type CanNotDelete

PowerShell

New-AzResourceLock -LockName "rg-prod-nodelete" -LockLevel CanNotDelete `
  -ResourceGroupName "rg-prod-app" -LockNotes "Production" -Force

Bicep

resource rgLock 'Microsoft.Authorization/locks@2020-05-01' = {
  name: 'rg-prod-nodelete'
  properties: {
    level: 'CanNotDelete'
    notes: 'Production. Raise a change before removing.'
  }
}

Deploy that at resource-group scope and every resource in the group is covered.

Who can create and remove locks

You need Microsoft.Authorization/locks/* permissions. Built-in roles that have them: Owner and User Access Administrator. Contributor does not, which is the point: a Contributor can manage resources but cannot remove the guard rail.

List and find locks

# All locks in a subscription
az lock list --output table

# Locks that apply to one resource group (including inherited)
az lock list --resource-group rg-prod-app --output table

Resource Graph query to see every lock across subscriptions you can read:

resources
| where type =~ 'microsoft.authorization/locks'
| project name, level = properties.level, notes = properties.notes, id

Run it with az graph query -q "<query>" (needs the resource-graph extension).

Remove a lock

az lock delete --name rg-prod-nodelete --resource-group rg-prod-app

When someone gets "The scope ... cannot perform delete operation because following scope(s) are locked", the error text names the lock scope. Check there first.

Side effects of ReadOnly (read before you use it)

A ReadOnly lock blocks every ARM write, and many things that look like reads are actually POST operations.

Operation Why it fails under ReadOnly
Storage account: list keys, portal Storage Browser listKeys is a POST
App Service: view publishing profile, some config blades POST / write calls
VM: start, stop, restart Write actions on the VM
AKS: scale, upgrade, node pool changes, sometimes even az aks get-credentials Write / POST (listClusterUserCredential)
Azure Backup: protecting a VM in a locked resource group Backup service creates restore point collections
Resource group: creating any new resource PUT on the group scope

Data-plane operations (reading a blob with a SAS, querying a SQL database) are not blocked, because locks only apply to ARM.

Side effects of CanNotDelete

CanNotDelete is safer but still has gotchas:

  • Azure Backup cleans up old restore points by deleting RestorePointCollections resources. A delete lock on the VM's resource group can make backups fail after the collection limit is reached. Keep restore point collections in a separate, unlocked resource group if you lock the VM's group.
  • AKS node resource group (MC_*): don't lock it. AKS needs to delete and recreate VMSS instances, disks and load balancer rules.
  • Databricks managed resource group: same rule; it is managed by the service.
  • Terraform: terraform destroy or a replacement (-/+) of a locked resource fails halfway through. Manage the lock in the same Terraform code, or exclude locked resources from destroy plans.

Warning

Don't put locks on resource groups owned by a service (AKS MC_*, Databricks managed RG, Synapse managed RG). Use Azure Policy or deny assignments for those instead.

A simple standard to adopt

  1. CanNotDelete on every production resource group, created by the landing zone pipeline.
  2. No ReadOnly locks except on frozen resources (for example, a decommissioned storage account kept for legal hold).
  3. Only Owner / User Access Administrator (ideally through PIM) can remove locks.
  4. Lock notes say who to ask and why it exists.
  5. Weekly Resource Graph report of production resource groups without a lock.

Prevent it next time

  • Enforce locks with Azure Policy (deployIfNotExists on resource groups tagged env=prod) so new groups get one automatically.
  • Alert on lock deletion: in Azure Monitor, create an Activity Log alert on the operation Microsoft.Authorization/locks/delete.
  • Document the service-managed resource groups that must stay unlocked, so nobody "helpfully" locks them later.