Victor applies a CanNotDelete lock, tries to delete the resource, watches Azure refuse — then the controlled override.
Run one step, then check it
Read the step before copying. Bash commands belong in Git Bash on Windows or Azure Cloud Shell set to Bash; PowerShell uses different syntax. A JSON, YAML, Bicep or application-code example belongs in the named file, not directly at the terminal prompt. Follow any shell-specific instructions below.
Keep the same terminal open so earlier variables remain available. Copy one complete command block without the terminal's $ prompt. A backslash continues a command onto the next line. If Bash shows a lone >, it is waiting for the rest of a quote, command or file block. Finish the complete block; if the paste was incomplete, press Ctrl+C and copy it again. Do not paste the next step into an unfinished command.
A line such as RG="training-group" stores a value without printing it. Output captured with $(...) is also stored; a blank screen alone does not prove failure. A sleep deliberately waits, and -o none suppresses normal output. Wait for your normal prompt, then run the step's checkpoint. After an error, stop and keep the exact command and message; later steps cannot repair a missing resource. Never share passwords, access tokens or secret values in a screenshot.
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.
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.
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.
A group with something worth protecting
Normal command output is suppressed here. Use the checkpoint to verify the resource or result; an error still needs investigation.
# 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
az storage account show --name "$SA" --resource-group "$RG" --query name -o tsv returns $SA.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."
az lock list --resource-group "$RG" --query "[].{name:name, level:level}" -o table shows your lock with level CanNotDelete.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 is not 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
>>> 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.Remove the lock, then the delete works
This block includes a deliberate wait. Leave this terminal open until the normal prompt returns; a wait is not proof that access has propagated.
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
>>> 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.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
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.
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.