Skip to main content

Theoretical Foundation: Configure Resource Locks


1. Initial Intuition​

Imagine you have a critical production database server. You know that any accidental deletion of this server would cause a business catastrophe. RBAC controls who can act, but a legitimate administrator with Contributor permissions could still delete this server by mistake.

What you need is a physical lock on the resource, regardless of who is trying to act on it. Something that says: "no matter who you are or what permissions you have, this resource cannot be deleted."

This is a Resource Lock: a protection that acts at the resource level itself, blocking deletion or modification operations, regardless of the user's RBAC permissions. It's the equivalent of putting a security padlock on critical equipment, where even the department manager needs a special key to remove it.


2. Context​

Where Resource Locks fit in Azure governance​

Resource Locks are a distinct protection layer from the others:

100%
Scroll para zoom Β· Arraste para mover Β· πŸ“± Pinch para zoom no celular

Resource Locks exist because the previous layers are not sufficient for protection against accidents or malicious actions by privileged users. An Owner can delete any resource by RBAC definition. A Resource Lock prevents this without needing to revoke Owner permissions.

What Resource Locks protect​

  • Critical production resources against accidental deletion
  • Central network infrastructure (VNets, gateways) against modification
  • Storage accounts with critical data
  • Key Vaults with production secrets
  • Any resource whose unavailability or loss would cause severe impact

3. Building the Concepts​

3.1 The two types of locks​

There are exactly two types of Resource Lock, and understanding the difference between them is fundamental:

TypePortal nameBlocked operationsAllowed operations
CanNotDeleteDeleteDELETERead and modification
ReadOnlyRead-onlyDELETE and PUT/PATCHOnly GET (read)

CanNotDelete protects against deletion, but still allows the resource to be modified. A user can change configurations, but not delete.

ReadOnly is much more restrictive: it blocks any operation that changes the resource state, including creation of child resources. It transforms the resource into read-only for everyone, regardless of permissions.

3.2 Who can create and remove locks​

Managing Resource Locks requires one of the following roles:

RoleCan create locksCan remove locks
OwnerYesYes
User Access AdministratorYesYes
ContributorNoNo
ReaderNoNo

This is a critical and counterintuitive point: Contributor cannot manage locks. A Contributor has broad power to create and modify resources, but cannot place or remove a lock. This is intentional: the protection cannot be removed by someone with common operational access.

To manage locks specifically without granting full Owner, there's the built-in role Microsoft.Authorization/locks/* that covers lock operations.

3.3 Lock inheritance​

Locks behave similarly to RBAC regarding inheritance: a lock applied at a higher level affects all resources below.

100%
Scroll para zoom Β· Arraste para mover Β· πŸ“± Pinch para zoom no celular

If you apply ReadOnly to the Resource Group, all resources within it become ReadOnly, regardless of individual locks on the resources. A lock on the RG is more comprehensive and harder to "forget" than locks on individual resources.

3.4 Locks and child resources​

A fundamental and non-obvious behavior: a lock on a Resource Group does not appear as a lock on individual resources within the RG. If you access Access Control or the Locks tab of a VM within an RG with a lock, the VM might not show any lock in its own list. The lock is on the RG, not on the VM.

To see all effective locks on a resource, you need to check the resource itself and all its ancestor scopes (RG and Subscription).


4. Structural View​

Flow of evaluating an operation with locks​

100%
Scroll para zoom Β· Arraste para mover Β· πŸ“± Pinch para zoom no celular

When an operation is blocked by a lock, ARM returns the HTTP error 409 Conflict with the code ScopeLocked. This error is distinct from a 403 RBAC error (which indicates lack of permission) and clearly informs that the blocking is due to a lock, not insufficient permission.

Locks vs. RBAC vs. Policy: structural comparison​

100%
Scroll para zoom Β· Arraste para mover Β· πŸ“± Pinch para zoom no celular

5. Practical Operation​

Non-obvious ReadOnly behaviors​

The ReadOnly lock has implications that go far beyond "cannot modify". Some surprising behaviors:

1. Storage Account with ReadOnly doesn't allow listing access keys. The list keys operation (listKeys) is classified as a POST action that modifies state (generates a credential resource). With ReadOnly, it's blocked. Applications that depend on listing keys to access storage will stop working.

2. VMs with ReadOnly cannot be started or stopped. Starting a VM is a write operation on the resource state. With a ReadOnly lock on the Resource Group containing the VM, no start/stop/restart operations will work.

3. Cannot create resources within a Resource Group with ReadOnly. If the RG has ReadOnly, no new resources can be created in it, as creation is a write operation.

4. App Services with ReadOnly on the RG may have execution problems. Some internal App Service runtime operations write state. A ReadOnly on the RG can break running services, not just management operations.

Practical conclusion: Use ReadOnly with extreme caution on resources that need to operate normally. It's suitable primarily for static infrastructure that doesn't need day-to-day management.

CanNotDelete behavior with child resources​

When you try to delete a Resource Group with a CanNotDelete lock, the operation fails even if there are no locks on individual resources within the RG. The lock on the RG protects against deleting the RG itself and implicitly protects all resources within (since deleting the RG would delete everything).

However, a CanNotDelete lock on the RG does not prevent deletion of individual resources within it. For complete protection of individual resources, you need to apply locks on the resources or on the RG with ReadOnly.

Multiple locks on the same scope​

It's possible to have multiple locks on the same resource or scope. The most restrictive lock prevails. If a resource has both a CanNotDelete and a ReadOnly (unlikely, but possible), ReadOnly prevails as it's more restrictive.


6. Implementation Methods​

Azure Portal​

When to use: manual protection of individual critical resources, quick visual verification

To create a lock:

  1. Navigate to the resource, Resource Group, or Subscription
  2. In the side menu, click Locks (under Settings)
  3. Click + Add
  4. Define the name, type (CanNotDelete or ReadOnly), and optional notes
  5. Click OK

To remove a lock:

  1. Access the same Locks screen
  2. Click the delete icon next to the lock
  3. Confirm removal

Advantage: quick, visual, easy for verification Limitation: doesn't scale, not reproducible, no version control


Azure CLI​

# Create CanNotDelete lock on a Resource Group
az lock create \
--name "rg-prod-nodelete" \
--resource-group "rg-producao" \
--lock-type CanNotDelete \
--notes "Protection against accidental deletion - Approved by: CTO"

# Create ReadOnly lock on a Resource Group
az lock create \
--name "rg-network-readonly" \
--resource-group "rg-networking" \
--lock-type ReadOnly \
--notes "Production network - do not modify without Change Request"

# Create lock on a specific resource
az lock create \
--name "keyvault-prod-lock" \
--resource-group "rg-seguranca" \
--resource-type "Microsoft.KeyVault/vaults" \
--resource "kv-prod-001" \
--lock-type CanNotDelete \
--notes "Production Key Vault - CRITICAL"

# Create lock on an entire Subscription
az lock create \
--name "sub-prod-nodelete" \
--lock-type CanNotDelete \
--scope "/subscriptions/<sub-id>" \
--notes "Production subscription"

# List locks in a Resource Group (including inherited)
az lock list \
--resource-group "rg-producao" \
--output table

# List ALL locks in the subscription
az lock list \
--output table

# Remove a lock (requires Owner or User Access Administrator)
az lock delete \
--name "rg-prod-nodelete" \
--resource-group "rg-producao"

# Check locks on a specific resource
az lock list \
--resource-group "rg-seguranca" \
--resource-type "Microsoft.KeyVault/vaults" \
--resource "kv-prod-001" \
--output table

Warning: the az lock list command with --resource-group shows locks applied to that RG and resources within it, but doesn't show locks inherited from higher levels (Subscription). For complete auditing, also include az lock list without filters to see all.


Azure PowerShell​

# Create CanNotDelete lock on RG
New-AzResourceLock `
-LockName "rg-prod-nodelete" `
-LockLevel CanNotDelete `
-ResourceGroupName "rg-producao" `
-Notes "Protection against accidental deletion"

# Create ReadOnly lock on RG
New-AzResourceLock `
-LockName "rg-network-readonly" `
-LockLevel ReadOnly `
-ResourceGroupName "rg-networking" `
-Notes "Production network - read only"

# Create lock on specific resource
New-AzResourceLock `
-LockName "storage-critical-lock" `
-LockLevel CanNotDelete `
-ResourceGroupName "rg-dados" `
-ResourceName "stgcritico01" `
-ResourceType "Microsoft.Storage/storageAccounts" `
-Notes "Storage with backup data"

# List all locks in an RG
Get-AzResourceLock -ResourceGroupName "rg-producao"

# List locks on a specific resource
Get-AzResourceLock `
-ResourceGroupName "rg-seguranca" `
-ResourceName "kv-prod-001" `
-ResourceType "Microsoft.KeyVault/vaults"

# Remove lock
Remove-AzResourceLock `
-LockName "rg-prod-nodelete" `
-ResourceGroupName "rg-producao" `
-Force

ARM Templates / Bicep​

Locks can be included in templates to ensure that every time an environment is provisioned, locks are created automatically.

Bicep for lock on a resource within the same template:

// Create the Key Vault
resource keyVault 'Microsoft.KeyVault/vaults@2023-02-01' = {
name: 'kv-prod-001'
location: resourceGroup().location
properties: {
sku: { family: 'A', name: 'standard' }
tenantId: subscription().tenantId
enableSoftDelete: true
}
}

// Create lock on the Key Vault
resource kvLock 'Microsoft.Authorization/locks@2020-05-01' = {
name: 'kv-prod-nodelete'
scope: keyVault
properties: {
level: 'CanNotDelete'
notes: 'Production Key Vault - do not delete'
}
}

Bicep for lock on Resource Group (using module with targetScope):

// file: rg-lock.bicep
targetScope = 'resourceGroup'

resource rgLock 'Microsoft.Authorization/locks@2020-05-01' = {
name: 'rg-prod-nodelete'
properties: {
level: 'CanNotDelete'
notes: 'Production Resource Group - protected'
}
}

When to use templates: environments provisioned via IaC where the lock should exist from the beginning and be recreated if the environment is redeployed.


Terraform​

# CanNotDelete lock on Resource Group
resource "azurerm_management_lock" "rg_lock" {
name = "rg-prod-nodelete"
scope = azurerm_resource_group.prod.id
lock_level = "CanNotDelete"
notes = "Protection against accidental deletion"
}

# ReadOnly lock on specific resource
resource "azurerm_management_lock" "kv_lock" {
name = "kv-prod-readonly"
scope = azurerm_key_vault.prod.id
lock_level = "ReadOnly"
notes = "Production Key Vault - read only"
}

Warning with Terraform and locks: if you apply a CanNotDelete lock to an RG via Terraform and then try to do terraform destroy, the destroy will fail because Terraform will try to delete the resources, including the RG itself. You'll need to remove the lock first. This is expected and is exactly the protection the lock provides.


7. Control and Security​

Who can manage locks: permission details​

Lock operations are:

OperationRequired permission
Create lockMicrosoft.Authorization/locks/write
Delete lockMicrosoft.Authorization/locks/delete
Read locksMicrosoft.Authorization/locks/read

The built-in roles that include these permissions are Owner and User Access Administrator. Contributor explicitly does not include Microsoft.Authorization/locks/write.

If you need to delegate only lock management without giving full Owner, you can create a Custom Role with only lock permissions:

{
"Name": "Lock Manager",
"Actions": [
"Microsoft.Authorization/locks/read",
"Microsoft.Authorization/locks/write",
"Microsoft.Authorization/locks/delete"
],
"AssignableScopes": ["/subscriptions/<sub-id>"]
}

Locks and Azure Policy​

Locks and Policy are complementary. A robust strategy uses Policy to ensure locks exist:

There's a built-in initiative in Azure Policy called "Append a lock of type CanNotDelete to resource groups" that uses the Append effect to ensure every new Resource Group created automatically receives a CanNotDelete lock.

This solves the problem of forgetting to apply locks manually to new RGs.


8. Decision Making​

CanNotDelete vs. ReadOnly​

SituationRecommended lockReason
Production database that needs to operateCanNotDeleteReadOnly would block the service's own operations
VNet and network resources that rarely changeCanNotDeleteAllows network maintenance, prevents deletion
Complete production Resource GroupCanNotDelete on RGComprehensive protection without impacting operations
Identity infrastructure (DNS, AD)ReadOnlyShould not be modified; any change must be deliberate and require removing the lock
Key Vault with critical secretsCanNotDeleteReadOnly would prevent secret rotation
Entire production subscriptionCanNotDelete on SubAdditional layer for entire subscription
Lab/dev environmentNoneLocks prevent agility in test environments

Where to apply the lock: resource vs. Resource Group​

ScenarioLock levelReason
Protect a specific resource within an RG with other mutable resourcesResourceNecessary granularity
Protect all production resources in an RGResource GroupOne lock covers everything, simpler to manage
Protect entire network infrastructureNetwork Resource GroupEverything in the network RG is critical
Maximum organizational protectionSubscriptionCovers all RGs, but use with care

9. Best Practices​

Apply locks on production Resource Groups as a default rule. Every production Resource Group should have at least a CanNotDelete lock. This should be a mandatory checklist item in the go-live process for any environment.

Use IaC to ensure locks from provisioning. Include lock creation in your Terraform or Bicep templates. This way, the lock is created together with the environment and doesn't depend on a manual step that can be forgotten.

Document locks with the "Notes" field. The lock notes field should contain: who approved it, why the lock exists, and what should be done before removing it. For example: "Production - Remove only with CTO approval via change ticket".

Combine locks with Azure Policy for automatic coverage. Use Append Policy to ensure new RGs always receive locks. This eliminates the human risk of forgetting.

Prefer CanNotDelete over ReadOnly for operational resources. ReadOnly should be reserved for truly static infrastructure. For most production resources that need to operate normally, CanNotDelete is the right choice.

Review locks periodically. Regularly audit which locks exist, if they still make sense, and if the notes field is updated. "Forgotten" locks without documentation cause operational confusion.

Never use ReadOnly on an entire active production Subscription. The impact is catastrophic: it blocks practically all management operations for all resources. If you need to protect the Subscription, use CanNotDelete.


10. Common Errors​

ErrorWhy it happensHow to avoid
Apply ReadOnly on RG with running VMsNot testing impact beforehandTest in dev environment, document impacts per resource type
Try to remove lock with Contributor accountNot knowing that Contributor doesn't manage locksUse Owner account or create specific lock manager role
Believe that Contributor cannot use resources with CanNotDelete lockConfuse lock with usage restrictionCanNotDelete only prevents DELETE; Contributor can still create, read and modify
Not document the lock reasonRush at creation timeMake "Notes" field mandatory in the process
Create lock on resource without noticing RG already has lockFragmented managementAlways check locks at all ancestor scopes
Forget to create lock on new production RGsManual process subject to human errorUse Azure Policy with Append to automate
Confuse lock with access protectionLock and RBAC are different layersRemember: lock blocks specific operations; RBAC controls who can operate
Try to delete RG via portal and not understand 409 errorNot associating the error with the lockAlways check Locks tab before reporting permission issue

The most costly error: ReadOnly in active environment​

Applying ReadOnly to a Resource Group with running services can bring down services immediately. VMs don't respond to commands, App Services may fail in internal operations, Automation runbooks can stop. The fix (remove the lock) is immediate, but downtime will have already occurred.


11. Operation and Maintenance​

Auditing existing locks​

# List all locks in entire subscription (complete view)
az lock list --output table

# Filter only locks of specific type
az lock list \
--query "[?properties.level=='ReadOnly']" \
--output table

# Check locks in specific RG
az lock list \
--resource-group "rg-producao" \
--output table

# Export all locks to JSON (for auditing)
az lock list --output json > locks-audit-$(date +%Y%m%d).json

Monitor lock creation and removal​

Lock changes are recorded in Activity Log:

# See lock creation and removal in Activity Log
az monitor activity-log list \
--resource-provider "Microsoft.Authorization" \
--query "[?operationName.value=='Microsoft.Authorization/locks/write' || operationName.value=='Microsoft.Authorization/locks/delete']" \
--output table

Configure an Activity Log Alert to be notified when locks are removed on critical scopes:

az monitor activity-log alert create \
--name "Alerta-Lock-Removido-Prod" \
--resource-group "rg-monitoramento" \
--condition category=Administrative \
and operationName=Microsoft.Authorization/locks/delete \
--scope "/subscriptions/<sub-id>/resourceGroups/rg-producao" \
--action-group "/subscriptions/<sub-id>/resourceGroups/rg-monitoramento/providers/microsoft.insights/actionGroups/ag-alertas-criticos"

This alert is especially important: if someone removes a production lock without following the change management process, you'll be notified immediately.

Important limits​

LimitValue
Locks per resource20
Locks per Resource Group20
Locks per Subscription20

In practice, these limits are rarely reached. A well-designed lock strategy uses a single well-documented lock per scope.


12. Integration and Automation​

Production environment protection pipeline​

A common pattern is to include lock creation as the final step of a production deploy pipeline:

100%
Scroll para zoom Β· Arraste para mover Β· πŸ“± Pinch para zoom no celular

Change Management process with locks​

In organizations with mature change management processes, removing a production lock is part of the change process:

100%
Scroll para zoom Β· Arraste para mover Β· πŸ“± Pinch para zoom no celular

The lock removal alert configured in Activity Log serves as evidence and auditing for this process.

Integration with Azure Blueprints​

Azure Blueprints (despite being in deprecation process in favor of Deployment Stacks and Bicep) used locks to protect resources deployed via Blueprint. The concept of Blueprint lock was more restrictive than normal locks: not even Owner could remove it without first removing the Blueprint assignment.

The modern successor is Deployment Stacks, which offers similar capability to lock resources deployed together.


13. Final Summary​

Essential points:

  • Resource Locks are a protection layer independent of RBAC, applied at the resource level by ARM
  • There are exactly two types: CanNotDelete (blocks DELETE) and ReadOnly (blocks DELETE and PUT/PATCH)
  • Contributor cannot create or remove locks; only Owner and User Access Administrator can
  • Locks are inherited top-down: a lock on RG affects all resources within
  • Locks block operations returning HTTP 409 Conflict with code ScopeLocked
  • A lock on an RG doesn't appear in the locks list of individual resources within the RG

Critical differences:

  • CanNotDelete vs. ReadOnly: CanNotDelete allows normal operations except deletion; ReadOnly blocks any modification, including VM start/stop and storage key listing
  • Lock vs. RBAC: Lock acts independent of permissions; even Owner has operations blocked by a lock (but can remove it)
  • Lock on resource vs. on RG: lock on RG protects everything inside, but doesn't appear in the Locks tab of individual resources; need to check ancestor scopes
  • Remove lock vs. not having lock: removing a lock requires Owner/UAA; a Contributor can use a resource with CanNotDelete lock normally (except delete)

What needs to be remembered for AZ-104:

  • The lock limit per scope is 20
  • The Locks tab is in Settings of any resource, RG or Subscription in the portal
  • Locks are resources of type Microsoft.Authorization/locks managed by ARM
  • ReadOnly on a Storage Account blocks the listKeys operation, breaking applications that depend on listing keys
  • The recommended combination for production is: CanNotDelete on RG + Activity Log Alert for lock removal
  • Azure Policy can use Append effect to ensure locks are automatically created on new Resource Groups