CAMPUX Cloud Bootcamp Lab · Governance ← All labs
Hands-On Lab · Beginner
~20 min · Free tier · Cloud Shell
CLI & Bicep · torn down at the end
Governance

The seatbelt: stop accidental deletion.

Someone runs the delete against the wrong resource group at four on a Friday, and production goes with it. RBAC decides who may delete; it does nothing to stop an authorized person deleting the wrong thing. The last-line defense is a resource lock — and even an Owner can't get past it.

Fig. 1 · A CanNotDelete lock that outranks RBAC
Resource group · rg-lab-locks — CanNotDelete lockProtected resourceinside the locked groupdelete attemptthe lock outranks even an Owner
● Screen walkthrough Not yet recorded · ~5 min
Reel · 00:00 / 05:00

Victor applies a CanNotDelete lock, tries to delete the resource, watches Azure refuse — then the controlled override.

Placeholder — the page below stands alone until the reel lands
Why

Locks vs. policy vs. RBAC

These three get confused constantly, and interviewers probe exactly here. RBAC decides who is allowed to perform an action. Azure Policy decides what configurations are allowed to be created or changed. A resource lock stops a specific destructive action — delete, or delete-and-modify — regardless of who you are. A lock is the seatbelt: it does not care that you are allowed to drive; it stops you going through the windscreen. There are two levels — CanNotDelete (read and modify, but not delete) and ReadOnly (no changes at all). This lab uses CanNotDelete, the common one.

RBAC says who. A lock says not this, not even you.

Before you begin — one-time setup

You need a free Azure account, the Azure CLI (az), then be signed in with az login. First time? The 15-minute Set up your machine page covers the account, the installs (winget / brew / apt), and sign-in. Prefer zero installs? Run everything in Azure Cloud Shell (Bash), preinstalled and already signed in.

Before you start

You need Owner or User Access Administrator (managing locks needs Microsoft.Authorization/locks/*). Run it in Azure Cloud Shell (Bash). Cost: one empty storage account (pennies), deleted at the end. Bicep version and this guide: github.com/kloudcaptain/campux-labs.

Step 1

A group with something worth protecting

# Windows/Git Bash: stop it mangling /subscriptions/... arguments (harmless on macOS/Linux)
export MSYS_NO_PATHCONV=1

SUFFIX=$RANDOM
RG="campux-lab-locks-rg"
LOCATION="eastus"
SA="campuxlock$SUFFIX"          # 3-24 lowercase alphanumeric
LOCK_NAME="campux-prod-donotdelete"

az group create --name "$RG" --location "$LOCATION"
az storage account create --name "$SA" --resource-group "$RG" \
  --location "$LOCATION" --sku Standard_LRS -o none
Checkpoint az storage account show --name "$SA" --resource-group "$RG" --query name -o tsv returns $SA.
Step 2

Lock the resource group

One lock on the group protects everything inside it.

az lock create \
  --name "$LOCK_NAME" \
  --lock-type CanNotDelete \
  --resource-group "$RG" \
  --notes "Protect Campux production resources from accidental deletion."
Checkpoint az lock list --resource-group "$RG" --query "[].{name:name, level:level}" -o table shows your lock with level CanNotDelete.
Step 3

Prove it: the delete is refused

Try to delete the storage account. The lock must block it. (Lock changes usually take effect within seconds; occasionally ARM takes a minute to recognize a new lock.)

if az storage account delete --name "$SA" --resource-group "$RG" --yes 2>/tmp/lockerr; then
  echo "!! Delete SUCCEEDED — the lock isn't enforcing yet. Wait ~60s, recreate the account, retry."
else
  if grep -qi "ScopeLocked\|is locked\|locked and can" /tmp/lockerr; then
    echo ">>> BLOCKED by the lock — exactly right."
  else
    echo "Delete failed for a NON-lock reason (not the proof):"; cat /tmp/lockerr
  fi
fi
Checkpoint You see >>> BLOCKED by the lock. An authorized delete was stopped cold — not by permissions, but by the lock. That message prints only when the failure reason is a lock (ScopeLocked), so a green result is real proof.
Step 4

Remove the lock, then the delete works

az lock delete --name "$LOCK_NAME" --resource-group "$RG"

# Lock removal can also take a few seconds to register. Retry until it goes through.
for i in 1 2 3 4 5; do
  if az storage account delete --name "$SA" --resource-group "$RG" --yes 2>/tmp/lockerr2; then
    echo ">>> Deleted on attempt $i — with the lock gone, the same command now works."
    break
  fi
  echo "attempt $i: still blocked (lock removal registering) — waiting 20s"
  sleep 20
done
Checkpoint >>> Deleted. The identical command that was refused in Step 3 now succeeds — the only thing that changed is the lock. That is the entire lesson: the lock, not your permissions, was the gate.
Down

Tear it down

The storage account is already gone. Remove the group — no lock remains to block it.

az group delete --name "$RG" --yes
az group exists --name "$RG"   # -> false
Remember at teardown time

A locked resource group cannot be deleted until the lock is removed — that is the whole point of the lock. If az group delete ever refuses with a lock error, list with az lock list -g "$RG" and delete the lock first.

End

What you can now honestly claim

You applied a resource lock to protect production from accidental deletion, proved it blocks a real delete regardless of permissions, and removed it to let the same command through. A lock stops a destructive operation even for an Owner; CanNotDelete blocks deletion while allowing changes, ReadOnly blocks changes too; and locks are inherited, so one on a group protects everything inside it. In production you declare them as code — the Bicep version ships the lock with the infrastructure it protects. This pairs with the Azure Policy lab: locks stop deletion, policy stops non-compliant creation — two different guardrails.