Rules for running Azure without adrenaline β portal discipline, CLI habits, tags and locks that prevent 2am pages, and a decommission process that doesn't leave billing ghosts.
3 chapters Β· 8 rules
4 reusable commands β fill the placeholders, copy, done. Values you fill are never stored.
The thirty seconds that catch template surprises before they happen (Rule 4).
az deployment group what-if --resource-group {{resource_group}} --template-file {{template_file}} --parameters {{parameters_file}}
Follows Rule 4
Who owns what β the first question of every incident and every cost review.
az resource list --tag owner={{owner}} --query "[].{name:name, type:type, rg:resourceGroup}" -o table
Rule 6, as one line.
az lock create --name {{lock_name}} --resource-group {{resource_group}} --lock-type CanNotDelete
Follows Rule 6
The point of no return β everything inside goes with it. Run the decommission recipe first, not after.
az group delete --name {{resource_group}} --yes --no-wait
Careful: Irreversible for most resource types. --yes skips the confirmation; the recipe IS the confirmation.
Follows Rule 8
1 repeatable process β read straight through, or run step by step with a private record of what you did.
Tear down a system so that nothing breaks elsewhere, nothing keeps billing from beyond the grave, and there is a way back for the first week.
az resource list --resource-group {{resource_group}} -o table
Search other groups for pointers into this one: private endpoints, VNet peerings, Key Vault references in app settings, DNS records, pipeline service connections. The group's contents can be deleted; the things pointing AT them break.
az group export --name {{resource_group}} > {{archive_path}}
Export skips some resource types (it warns) β note the skips in the ticket; they are what you cannot restore from template alone.
Key Vaults, Recovery Services vaults, and Cognitive/OpenAI accounts do not fully die with the group β they enter soft-delete, keep their name reserved, and some keep billing. List them now and decide: purge after delete, or keep the recovery window.
az lock list --resource-group {{resource_group}} -o table az lock delete --name {{lock_name}} --resource-group {{resource_group}}
az group delete --name {{resource_group}} --yes --no-wait
Everything above was the confirmation. This is the action.
A delete that fails halfway usually hit a lock on a nested resource β see the attached failure note.
β Group delete fails partway: hidden lock on a nested resource
Deletion runs for minutes then fails; some resources gone, others remain; error cites a lock
Likely cause: Resource-level locks are separate from group-level locks and az lock list at group scope can be filtered oddly by inherited vs direct
Fix: Delete the resource-level locks, re-run the group delete. The half-deleted state is safe to re-run; delete is idempotent.
az keyvault list-deleted and the equivalent for other soft-delete types; purge the ones marked purge in step 4. Then check the subscription's cost analysis a week later β the line for this system should be zero, not merely smaller.
A "deleted" vault still billing = soft delete kept it alive β see the attached failure note.
β The deleted resource group that kept billing
Weeks later the subscription still shows charges for the "deleted" system
Likely cause: Soft-deleted vaults/accounts retain reserved capacity or storage that bills during the retention window
Fix: Purge the soft-deleted residents (az keyvault purge / account purge) where policy allows. Add the step-7 afterlife audit to every decommission.
2 notes from the field β observations, discoveries, warnings, and lessons.
You cannot create a new vault with the same name until the soft-deleted one is purged or expires β which surprises every pipeline that tears down and recreates by fixed name. Either purge deliberately (audit first: purge protection may forbid it) or generate unique vault names.
what-if sometimes reports noise-level modifies (tag ordering, identity blocks) that the deploy won't actually change. Learn your templates' known-noise signature β the danger is alert fatigue making someone skim past a real delete one day.
2 known failuresβ the approaches that didn't work, preserved so you don't repeat them.
Deletion runs for minutes then fails; some resources gone, others remain; error cites a lock
Attempted: az group delete on a group whose group-level lock was removed
Context: Groups where someone locked individual resources (not just the group) months earlier
Likely cause: Resource-level locks are separate from group-level locks and az lock list at group scope can be filtered oddly by inherited vs direct
Diagnose: az lock list --resource-group X --query "[].{name:name, scope:id}" -o table β look for locks scoped to individual resources
Fix: Delete the resource-level locks, re-run the group delete. The half-deleted state is safe to re-run; delete is idempotent.
Weeks later the subscription still shows charges for the "deleted" system
Attempted: Deleted a group containing a Key Vault and an OpenAI account; closed the ticket
Context: Any teardown that skipped the soft-delete audit
Likely cause: Soft-deleted vaults/accounts retain reserved capacity or storage that bills during the retention window
Diagnose: az keyvault list-deleted; az cognitiveservices account list-deleted; cost analysis filtered by the system's tags
Fix: Purge the soft-deleted residents (az keyvault purge / account purge) where policy allows. Add the step-7 afterlife audit to every decommission.
Most Azure incidents are self-inflicted: the portal change nobody recorded, the delete that took a dependency with it, the "deleted" vault that kept billing. These rules make the safe path the default path β with the exact commands and a teardown recipe that checks before it burns.
Anyone with Contributor on a subscription that matters.
Initial publication.
Readers of this book also keep