Updated: Sep 23
azure administrator series
Lab 01 — Scoped Azure RBAC: Assign, Diagnose, and Recover

An application can authenticate successfully and still be unable to read an Azure resource. In this first Azure Workshopz lab, you will give a managed identity Reader access, prove the boundary, diagnose a scope mistake, and restore access using Azure CLI, native Azure PowerShell, and the Azure Portal.
The task is deliberately small: read a resource group and its storage-account metadata, but do not change either. That makes the relationship between identity, role, and scope visible without building an application stack first.
1. What you will learn
By the end, you will be able to identify the three parts of an Azure role assignment, distinguish direct from inherited access, diagnose a wrong-scope assignment, and prove the result with requests made by the affected identity.
This lab maps to these AZ-104 objectives: manage built-in Azure roles; assign roles at different scopes; interpret access assignments; and manage resource groups. It is an independent community workshop.
Level: foundational administrator. Allow 90–120 minutes, including propagation and investigation. The scripts target West Europe and use PowerShell 7 as the local shell. Azure CLI performs setup; native Azure PowerShell performs inspection and repair; the Portal provides visual checkpoints.
2. Before you start: access, cost, and context
Install PowerShell 7.2+, Azure CLI, Az.Accounts, and Az.Resources. Use an enabled subscription where you can create a resource group and resources and manage role assignments at that scope. Contributor alone does not permit assigning Reader. Owner, or suitable resource and RBAC administration permissions, must cover the lab operation. Delegation conditions can further restrict the permitted principals or roles.
The normal run targets less than EUR 0.50. Preflight fetches current West Europe retail prices in EUR and calculates six hours of one sequential 1-vCPU/1-GB probe plus a EUR 0.05 storage contingency. This is a planning estimate, not a bill or a spending cap. Your offer may differ. Expiry tags do not delete resources. Finish the exercise after five hours at the latest and clean up before six hours.
The lab creates one resource group, one user-assigned managed identity, one Standard_LRS storage account, and one short-lived ACI probe per test phase. It uses no VM, public inbound endpoint, application secret, or blob data. The storage public network endpoint is disabled; all storage checks are management-plane metadata reads through Azure Resource Manager.
Sign in to both command tools and choose the same subscription. These commands run in PowerShell 7:
az login
az account set --subscription 'YOUR SUBSCRIPTION NAME'
Connect-AzAccount
Set-AzContext -Subscription 'YOUR SUBSCRIPTION NAME'The Portal must use the same directory. Keep account IDs, tokens, private state, and unredacted logs out of shared screenshots and downloads.
3. Understand the boundary
Azure RBAC joins a principal, a role definition, and a scope. In this lab the principal is a managed identity, the role is Reader, and the intended scope is the lab resource group. An assignment at that group also applies to child resources. An assignment on one storage account does not grant access to its parent resource group.
Azure RBAC roles govern Azure resources. Microsoft Entra directory roles govern directory administration. Granting Reader here does not make the managed identity a directory administrator.
Administrator: creates and manages the disposable lab
Resource group
Managed identity ← used by short-lived ACI probe
Storage account ← management metadata only
Reader assignment → intended scope: resource group
Probe identity → ARM read group: allowed
Probe identity → ARM read storage: allowed
Probe identity → ARM write tag: denied4. Run preflight and create the lab
Extract the bundle and open PowerShell in its folder. Put the run manifest outside the extracted download. It contains the exact resource and assignment IDs required for recovery and cleanup; do not publish it.
$state = Join-Path (Split-Path $PWD -Parent) 'lab01-private/state.json'
./Start-Az104Lab01.ps1 -StatePath $state -Stage Preflight -SubscriptionName 'YOUR SUBSCRIPTION NAME'Preflight performs no Azure writes. It checks that both contexts match, required providers are registered, and the current price estimate is within the lab target. Azure Policy, available quota, and regional capacity can still reject a deployment; the state file makes partial cleanup possible. Resolve an unregistered provider deliberately rather than hiding registration in preflight.
Deploy the healthy environment:
./Start-Az104Lab01.ps1 -StatePath $state -Stage Deploy -SubscriptionName 'YOUR SUBSCRIPTION NAME' -Execute -AcknowledgeCostEvery resource name contains a new run suffix, and supported resources carry Lab, RunId, and expiry tags. An existing state file is not silently reused for a second deployment. To continue this run, use its stage scripts. To start another, clean up this run and choose a new state path.
Here are the core CLI operations used inside setup, shown for explanation. The deployment script has already executed them; do not run this excerpt again:
az group create --name $rg --location westeurope --tags Lab=az104-01-scoped-rbac RunId=$run
az identity create --name $identityName --resource-group $rg --location westeurope
az role definition list --name $readerRoleId
az role assignment create --assignee-object-id $principalId --assignee-principal-type ServicePrincipal --role $readerRoleId --scope $resourceGroupIdUsing the principal object ID avoids a name lookup in Microsoft Graph. Explicit ServicePrincipal type helps when the managed identity is newly created. The implementation resolves the Reader role ID and stores the resulting assignment ID before fault injection.
5. Portal checkpoint: direct and inherited Reader
Open Resource groups and search for the exact name reported by setup. Confirm that it contains the identity and storage account and that the ownership tags match the run.
Open the group's Access control (IAM), choose Role assignments, and filter for the lab identity. Reader should be assigned at this resource-group scope. Then open the storage account's Access control (IAM) and find the same identity. Its group-level Reader is inherited by the storage account.
The Portal is showing the assignment, but you are still signed in as the administrator. Your ability to open a blade is not proof that the managed identity can access it. The next stage tests as the actual application identity.

Live validation: the isolated lab resource inventory. Cropped to exclude account details.
6. Prove the healthy baseline
./Test-Az104Lab01.ps1 -StatePath $state -Phase Baseline -ExecuteThe test runner creates an ACI group with the managed identity and no inbound IP configuration. The container requests a managed-identity token internally, calls ARM, writes only status codes and sanitized error codes, and exits. Credentials and response bodies are never printed.
The required outcomes are resource-group metadata HTTP 200, storage metadata HTTP 200, and tag write HTTP 403 with AuthorizationFailed. A successful read alone would not establish the tested write boundary. The tag attempt is a harmless lab-only marker, so even an unexpected permission error cannot alter production data.
Each phase uses a new execution marker. Bounded retries allow authorization changes to converge. A new token or container does not promise instant propagation. A sign-in error, network failure, or image-pull failure is not an acceptable substitute for an authorization denial.
7. Troubleshooting challenge
Once Baseline passes, introduce the prepared lab fault and run the affected application's checks:
./Set-Az104Lab01Fault.ps1 -StatePath $state -Execute
./Test-Az104Lab01.ps1 -StatePath $state -Phase Fault -ExecuteThe identity previously read the resource group. Now a new execution returns an authorization failure for that group, although authentication works and one resource remains readable. Diagnose why the outcomes differ. Restore only the access required by the resource-group inventory task and prove that writing is still denied.
Before reading the solution, write down the failed action, the target scope, and your hypothesis. Inspect Access control (IAM) at both the group and storage resource. Capture what changed in the assignment's scope and inheritance.

Fault checkpoint: the resource-group IAM list has no assignment covering the lab identity.
Use Azure CLI to inspect the affected principal. Keep the resulting private identifiers out of public evidence:
$s = Get-Content -LiteralPath $state -Raw | ConvertFrom-Json
az role assignment list --assignee-object-id $s.PrincipalId --all --include-inherited --query '[].{role:roleDefinitionName,scope:scope}' -o tableThen compare with native Azure PowerShell:
Get-AzRoleAssignment -ObjectId $s.PrincipalId |
Select-Object RoleDefinitionName, ScopeBoth tools should describe the same assignment. A blank display name can be a directory lookup limitation; inspect the recorded principal ID and assignment fields rather than assuming the identity was deleted.
8. Hints — use one at a time
Separate authentication from authorization. Which step succeeded?
Compare the group metadata request with the storage metadata request. Neither is a blob download.
Inspect the assignment Scope column and whether it is direct or inherited at each level.
Permissions flow down from a parent scope. Does the current assignment cover the failed request's parent resource group?
9. Solution and native PowerShell repair
The fault removed the run's resource-group Reader assignment and created Reader on only the storage account. The role name is still correct, but its scope is too narrow for the application task. The storage metadata read remains authorized; the parent group read is not.
Restore Reader at the original resource-group scope. Do not grant Contributor or Owner and do not broaden the assignment to the subscription.
./Restore-Az104Lab01.ps1 -StatePath $state -Execute
./Test-Az104Lab01.ps1 -StatePath $state -Phase Recovery -ExecuteThe repair script uses native Azure PowerShell. This excerpt explains the essential operation; the script has already performed it and retained the returned assignment ID:
New-AzRoleAssignment -ObjectId $s.PrincipalId -ObjectType ServicePrincipal -RoleDefinitionId $s.ReaderId -Scope $s.ResourceGroupIdThe script finds and removes only the saved fault assignment. Recovery is complete when a new probe reads both metadata targets and its tag write is still denied. The script retains enough state to retry restoration after an interrupted run.

Recovery checkpoint: Reader is back at the resource-group scope. This crop excludes private object identifiers.
10. Expected proof and release evidence
Request as the managed identity | Baseline | Fault | Recovery |
Read resource-group metadata | 200 | 403 | 200 |
Read storage-account metadata | 200 | 200 | 200 |
Write a tag | 403 | 403 | 403 |
The release's actual observations, timestamps, tested tool versions, and cleanup status are recorded in live-test-report.md and evidence/live-results.json in the bundle. A phase passes only when it produces its own expected status and error codes. The expected table above is not a substitute for those results.
11. Troubleshooting reference
Symptom | Check | Response |
CLI and PowerShell disagree | Tenant/subscription context | Align both contexts before changing assignments |
Role assignment creation is denied | RBAC write permission and delegation conditions | Have the appropriate administrator supply the required lab-scope access |
PrincipalNotFound just after identity creation | Principal ID and replication | Use explicit ServicePrincipal type and bounded retries |
Read still works immediately after removal | Authorization propagation | Wait within the bounded test window and preserve timestamps |
ACI does not start | Regional capacity, quota, image and container events | Treat as an infrastructure failure; stop and clean up |
Removal refuses an extra resource | Manifest and ownership tags | Inspect the unexpected item; never broaden deletion to a name prefix |
12. Clean up and prove absence
Preview the exact cleanup boundary, then execute it:
./Remove-Az104Lab01.ps1 -StatePath $state
./Remove-Az104Lab01.ps1 -StatePath $state -Execute
./Get-Az104Lab01Evidence.ps1 -StatePath $state -OutputDirectory './my-evidence'Cleanup checks ownership, removes recorded role assignments before removing the identity, deletes the recorded resource group, waits for its absence, and searches for resources tagged with the exact RunId and remaining assignments for the probe principal. It retains private state for audit. A deletion still in progress is not a clean result.
If you abandon the exercise during the fault, run the cleanup command with the original state file. It can remove the disposable lab directly; it does not need to restore access just to delete the environment. In the Portal, refresh Resource groups and confirm that the exact lab group no longer appears.
13. Apply the lesson in administration
Start with the operation the application needs and choose the smallest scope that covers it. Reader on a storage account is appropriate for inspecting that account; Reader on the group is appropriate for this group's inventory task. The answer depends on the required boundary, not on making the error disappear.
In an organization, separate human administration from workload identity, review inherited assignments, and use groups and eligible privileged access where appropriate. Those are production design topics beyond this small exercise. The managed identity here receives no secret and no storage data role.
14. Knowledge check
Which three elements define a role assignment?
Why does Contributor not necessarily permit assigning Reader?
Can Reader on one storage account authorize its parent group read?
Does management Reader permit downloading blobs?
Why use a separate identity for the probe?
Why repeat the denied-write test after recovery?
Does a new container guarantee immediate RBAC propagation?
Which observations prove cleanup?
Answers: principal/role/scope; role-assignment administration is a separate permission; child permissions do not flow upward; management access is distinct from data access; the administrator's broad access could mask the fault; recovery must preserve the tested write boundary; authorization caches can still delay convergence; and the group, tagged resources, and principal assignments must all be absent. Detailed explanations are included in the bundle.
References and series navigation
Next in the azure administrator series: Lab 02 — Microsoft Entra Identity Lifecycle
Comments