1. The business problem
Contoso runs two environments in Azure. Production holds the web servers VM-Web1 and VM-Web2 and the database server VM-SQL1 that customers depend on. Development holds copies that engineers break and rebuild every week. Three departments use these systems: Sales, Finance and Operations.
Four separate things worry the people involved.
- Finance wants Production and Development on separate invoices, and wants the Production invoice split by department, because Sales will not pay for Operations' servers.
- Ravi in Operations builds a test web tier on Monday and wants to delete the whole thing on Friday in one action, not resource by resource.
- Everyone wants a guarantee that nobody deletes VM-SQL1 by mistake, even an administrator having a bad day.
- Sarah in Finance wants to see, at month end, how much each department spent.
Azure solves these with four different features. Keeping them separate in your head is most of the work of this lesson:
| Question | Feature |
|---|---|
| Who pays, and how much may they use? | Subscription |
| What belongs together and is managed as one? | Resource group |
| What must not be deleted or changed? | Lock |
| Which department does this cost belong to? | Tag |
2. The Azure resource hierarchy
Everything in Azure is arranged in a tree. You met it in the RBAC lesson; here is the same tree with Contoso's containers filled in, because the rest of this lesson is about the middle three levels.
Three different things travel down this tree, and they do not all behave the same way. This is the single most useful distinction in the lesson:
| What | Set at a level, does it reach everything below? |
|---|---|
| Role assignments (RBAC) | Yes. Reader on Production reaches RG-Web, RG-Data and every VM in them. |
| Resource locks | Yes. A lock on RG-Data covers VM-SQL1 and anything added to RG-Data later. |
| Tags | No. A tag on RG-Data is a tag on RG-Data only. VM-SQL1 does not get it. |
Quick check
Sarah puts the tag CostCentre = 4471 on resource group RG-Data. Ravi later creates a new disk inside RG-Data. Does the disk carry the tag?
3. Subscriptions
What problem it solves. Finance needs Production and Development on separate invoices, and needs a way to stop one team consuming all of Contoso's allowed capacity.
What it is. A subscription is an account inside the tenant. It does three jobs at once: it is the unit Azure bills, it is the unit Azure applies limits to (how many CPU cores, how many storage accounts, and so on), and it is a boundary for access management, because roles are commonly assigned at this level. Contoso therefore has two: Production and Development.
How it works. Every resource lives inside exactly one subscription, and its cost appears on that subscription's invoice. The limits (Azure calls them quotas (per-subscription, per-region ceilings on how much of each resource type you may create; raised by request to Microsoft)) are counted per subscription, so a runaway experiment in Development cannot exhaust the cores Production needs.
When an administrator uses it. When a part of the business needs its own invoice, its own spending controls or its own quota, you create a subscription. Subscriptions can be moved between management groups at any time, and a subscription's billing ownership can be transferred to another organisation. Resources in different subscriptions can still talk to each other over the network; the subscription boundary is about money and management, not connectivity.
What AZ-104 expects. That a subscription is the billing, quota and access boundary; that it belongs to one tenant and one management group; and that moving a subscription into a management group makes it inherit that group's policies and role assignments.
4. Resource groups and locations
What problem it solves. Ravi's Monday-to-Friday experiment is a VM, two disks, a network card, a public IP and a network security group. Deleting six objects individually is slow and error-prone.
What it is. A resource group is a folder inside a subscription. Every resource must be in exactly one group. The group has no cost of its own; it is purely an organising unit.
How it works. Put resources that share a lifecycle (they are created together, changed together and will be removed together) in the same group. When Ravi deletes RG-Test on Friday, Azure deletes everything inside it in one operation. That is the main reason to group by lifecycle rather than by type: putting all VMs in one group and all disks in another would make the Friday clean-up impossible.
One detail confuses beginners. When you create a group you choose a location, such as Australia Southeast. This is where Azure stores the group's own record, its metadata (the description of the group: its name, tags and the list of what is in it). It is not a rule about where the contents must live. RG-Web in Australia Southeast can hold VM-Web1 in Australia East. The location only matters if the Australia Southeast region is unavailable, because then you temporarily cannot change the group's own settings.
When an administrator uses it. Every time a resource is created, a group is chosen. Good practice is one group per application tier or per project, named for what it holds.
What AZ-104 expects. One group per resource; deleting the group deletes its contents (unless a lock prevents it); the group location is metadata only; and that role assignments and locks placed on a group apply to everything in it.
Quick check
Resource group RG-Web was created with location Australia Southeast. Can it contain a virtual machine deployed in Australia East?
5. Resource locks
What problem it solves. Ravi has Contributor on Production so he can manage the servers. Contributor includes delete. One mis-click on VM-SQL1 and the company database is gone. RBAC cannot express "may do everything except delete this one thing", so Azure provides a separate safety catch.
What it is. A lock is a setting you attach to a resource, a resource group or a subscription. It comes in two strengths:
| CanNotDelete (portal: "Delete") | ReadOnly | |
|---|---|---|
| Reading | Allowed | Allowed |
| Changing settings | Allowed | Blocked |
| Deleting | Blocked | Blocked |
| Who it applies to | Everyone, including Owners | Everyone, including Owners |
How it works. A lock sits in front of the permission check. Even if your role allows the action, a lock refuses it and the error message names the lock. Locks are inherited downward: a lock on RG-Data covers VM-SQL1 and anything added to RG-Data later, and the most restrictive lock in the chain wins. A lock on any single resource inside a group also stops the whole group being deleted, because Azure will not delete a group partially.
Because a lock overrides roles, removing one is deliberately restricted. Only roles that include Microsoft.Authorization/locks/* can add or remove locks: Owner and User Access Administrator have it, Contributor does not. The intended workflow is: an Owner removes the lock, the change is made, the lock goes back.
Why ReadOnly is stronger than it sounds. ReadOnly means "only read requests are allowed". Some operations that feel like reading are, underneath, write-type requests to Azure, and they fail under ReadOnly. The documented examples that appear on the exam:
- Viewing a storage account's access keys is blocked (the "list keys" request is a POST). People then need Entra ID sign-in to reach the data.
- A ReadOnly lock on a resource group blocks starting or restarting the VMs in it.
- A ReadOnly lock on a group containing an App Service plan blocks scaling the plan.
So CanNotDelete is the everyday choice. ReadOnly is for the rare case where the requirement is "nothing about this may change".
Still allowed
- Resize, start, stop, change settings
- Add new resources to RG-Data
- Read everything
- Owner or User Access Administrator can remove the lock first
Side effects
- Blocks every change, not only deletes
- Blocks listing storage keys
- Blocks starting or restarting VMs in the group
- Blocks scaling an App Service plan in the group
"Prevent accidental deletion" means CanNotDelete, usually on the resource group. "Prevent any modification" means ReadOnly, and the question will often then ask what unexpectedly stops working.
One more boundary. Locks act on the management side of Azure, the portal and API calls that create, change and delete resources. They do not reach inside the resource. A lock on a storage account does not stop someone deleting the files in it through the storage service itself. Data protection is a separate topic in the storage module.
When an administrator uses it. On every production resource group, as a standing CanNotDelete lock, with the note field explaining how to request removal.
What AZ-104 expects. The two lock types and what each blocks; that locks apply to everyone and inherit downward; that Owner or User Access Administrator (not Contributor) manages them; the ReadOnly side effects above; and that locks are about the management plane, not the data inside.
Quick check
A ReadOnly lock is applied to resource group RG-Data. Which of these will FAIL for an Owner? (pick the best answer)
6. Tags and cost tracking
What problem it solves. Sarah needs the Production invoice split by department. Azure knows what each resource cost, but not which department it belongs to. Tags supply that missing information.
What it is. A tag is a name and a value, both plain text, attached to a resource: CostCentre = 4471, Department = Sales, Environment = Production. You can attach up to 50 tags to one resource, and the same tag name can have different values on different resources.
How it works. Tags are set on the Tags tab of every creation wizard, on the Resource › Tags blade afterwards, or by script. Cost analysis can then group spend by any tag, so Sarah picks "group by CostCentre" and sees Sales, Finance and Operations as separate lines. Tags also let you filter the resource list and target policies.
The part that catches people. Tags are not inherited. Tagging RG-Web does not tag VM-Web1, and cost analysis looks at the resource's own tags. This is different from roles and locks on purpose: a tag is a label on one object, not a rule about a scope. If you want tags to flow down, you add a rule that copies them: the built-in Azure Policy Inherit a tag from the resource group (Modify effect) adds the tag when a resource is created, and a remediation task (a Policy job that goes back and applies a Modify or DeployIfNotExists rule to resources that already existed before the rule was assigned) applies it to resources that already exist. A second built-in, Require a tag on resources (Deny effect), refuses to create anything without the tag.
When an administrator uses it. From day one: decide the three or four tag names the company needs, require them by policy, and inherit them by policy.
What AZ-104 expects. 50 tags per resource; tags are not inherited; cost analysis groups by the resource's own tags; the two policies that enforce and inherit tags.
Quick check
Contoso's cost report shows VM-Web1 and VM-Web2 with no department, although RG-Web is tagged Department = Sales. What is the least-effort fix for existing and future resources?
7. Moving resources
What problem it solves. Ravi built VM-Web2 in the wrong resource group, or Finance decides the reporting server should be billed to Development instead of Production.
What it is. A move changes which resource group, and optionally which subscription, a resource belongs to. It does not change where the resource physically runs; the region stays the same. Changing region is a copy operation with a different tool (Azure Resource Mover), covered in the compute module.
How it works. From Resource group › Move › Move to another resource group (or subscription), you select the resources and Azure runs a validation before doing anything. The points that matter:
- A VM depends on its disks, network card and public IP. For a move to another subscription, the resource and everything it depends on must be in the same group and move together.
- Not every resource type can be moved, and some services have their own restrictions. The validation step tells you.
- During the move, both the source and destination groups are locked for changes (up to a few hours, usually minutes). Running resources keep running.
- A ReadOnly lock on either group, or on the subscription, blocks the move.
- For cross-subscription moves, both subscriptions must be in the same tenant.
- Role assignments on the resource do not move with it; recreate them afterwards. Tags do move, because they are part of the resource.
- The resource's ID changes, so scripts and dashboards that reference it need updating.
When an administrator uses it. To correct placement mistakes or to change which subscription pays. Always validate first, and move dependencies together.
What AZ-104 expects. Moves are between groups or subscriptions, not regions; dependent resources move together; both groups are locked during the move; some types cannot move; role assignments are lost.
Quick check
You move VM-Web2 from RG-Web to RG-Test in the same subscription. Which statement is correct?
8. AZ-104 exam scenarios
These are the shapes the exam uses for this topic. Read each, decide, then compare with the reasoning.
Scenario A. "You need to ensure that VM-SQL1 cannot be deleted, while still allowing administrators to resize it. Solution: apply a ReadOnly lock to RG-Data. Does this meet the goal?" No. ReadOnly blocks resizing as well as deleting. CanNotDelete meets both parts.
Scenario B. "A user with the Contributor role reports that they cannot remove a lock from RG-Prod. What should you do?" Grant Owner or User Access Administrator on RG-Prod (or remove the lock for them). The behaviour is by design; Contributor lacks the locks permission.
Scenario C. "Finance needs the monthly invoice to show cost per department. Resource groups are already named by department." Tag the resources (and use the inherit-tag policy). Group names are not available in cost analysis grouping the way tags are, and tags are the documented mechanism.
Scenario D. "You attempt to delete RG-Test and receive an error that the group is locked, but RG-Test itself has no lock." A resource inside RG-Test has a lock. Any locked resource blocks deleting the whole group.
Scenario E. "You plan to move a VM from Subscription A to Subscription B. What must be true?" Same tenant; VM and its dependencies in one group moved together; the destination subscription registered for the resource providers and within quota; no ReadOnly locks.
You, the admin: Contoso's Friday checklist
- Resource groups › RG-Data › Locks › + Add: name no-delete, type Delete (CanNotDelete), note "raise a change to remove". Repeat for RG-Web.
- Policy › Assignments › Assign policy: "Require a tag on resources" with tag name CostCentre, scope Production subscription.
- Assign "Inherit a tag from the resource group" for CostCentre at the same scope, then Policy › Remediation › create a remediation task for existing resources.
- Tag RG-Web with CostCentre = 4471 (Sales) and RG-Data with CostCentre = 4480 (Operations). New resources inherit; the remediation task fixes the old ones.
- Delete RG-Test: RG-Test › Delete resource group, type the name to confirm. Everything inside goes.
Script: az lock create -n no-delete -g RG-Data --lock-type CanNotDelete · az tag create --resource-id <id> --tags CostCentre=4471 · az group delete -n RG-Test
9. Revision summary
- Subscription = billing + quota + access boundary. One tenant, one management group, separate invoice.
- Resource group = lifecycle folder. One per resource. Delete the group, delete the contents (unless locked). Location is metadata only.
- Roles and locks flow down the tree. Tags do not.
- CanNotDelete blocks delete only. ReadOnly blocks every change, including listing storage keys, starting VMs and scaling App Service plans.
- Only Owner and User Access Administrator manage locks. A lock on one resource blocks deleting its group.
- Locks govern the management plane, not the data inside a resource.
- Tags: up to 50; cost analysis groups by the resource's own tags; use "Require a tag" (Deny) and "Inherit a tag from the resource group" (Modify) policies plus remediation.
- Moves change group or subscription, never region; move dependencies together; both groups lock during the move; role assignments do not move.