Lab: Azure foundation, resource hierarchy, and least privilege

Outcome

Create a tagged resource group, deploy one storage account with Bicep, give a test group Reader access only to that resource group, then diagnose why that group cannot create a resource. This is the minimum control-plane loop behind many AZ-104 tasks.

Before you begin

You need a non-production subscription where you can create resource groups and role assignments. Before you create anything, complete this workload card. It turns the lab from a list of portal actions into an operational decision.

Workload concernTraining decision
Owner and costYour training identity; a subscription you may charge and clean up.
Runtime/dataA StorageV2 account with no workload data.
Identity/authorizationA disposable Entra security group receives Reader at one resource group.
Network boundaryBlob public access is disabled; this does not configure private networking.
Delivery/observability/recoveryBicep through ARM; CLI/portal state and Activity Log; resource-group deletion.

In Cloud Shell, set these values. Replace only the values in angle brackets.

az account set --subscription '<training-subscription-id-or-name>'
az group create --name rg-azlearn-governance --location <azure-region> --tags purpose=training owner=<your-alias>

If az group create fails, stop: your current account does not have the required subscription access. Record the error; do not ask someone to grant more access than the lab requires.

Learn

  • A resource-group groups related resources; deleting it deletes the resources in it.
  • RBAC grants access through a principal, role, and scope. Assignments are additive; a narrower Reader assignment does not take away a broader Contributor assignment.
  • Policy governs which configurations Azure will accept. It is not a substitute for RBAC.
  • bicep sends a declarative desired state to Azure Resource Manager.

Do

Create main.bicep in Cloud Shell with this content:

param location string = resourceGroup().location
param storageName string
 
resource storage 'Microsoft.Storage/storageAccounts@2023-05-01' = {
  name: storageName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    allowBlobPublicAccess: false
    minimumTlsVersion: 'TLS1_2'
  }
  tags: {
    purpose: 'training'
  }
}

Deploy it. Storage-account names are globally unique, lowercase, and 3–24 characters. Choose a unique value for <unique-storage-name>.

az deployment group create \
  --resource-group rg-azlearn-governance \
  --template-file main.bicep \
  --parameters storageName=<unique-storage-name>

In Microsoft Entra ID, create a security group named azlearn-rg-readers and add a test user who does not already have a broader role at this subscription. At the resource-group scope, assign the built-in Reader role to that group. Use the portal’s Access control (IAM) page or this equivalent CLI form:

az role assignment create \
  --assignee-object-id '<group-object-id>' \
  --assignee-principal-type Group \
  --role Reader \
  --scope "$(az group show --name rg-azlearn-governance --query id -o tsv)"

Verify

Run these checks as your administrator account:

az group show --name rg-azlearn-governance --query '{name:name,tags:tags}' -o json
az storage account show --name <unique-storage-name> --resource-group rg-azlearn-governance --query '{name:name,httpsOnly:enableHttpsTrafficOnly,publicBlob:allowBlobPublicAccess}' -o json
az role assignment list --scope "$(az group show --name rg-azlearn-governance --query id -o tsv)" --all -o table

Then sign in as the test user in a private browser session. They should be able to view the resource group and storage account, but not create a storage account. Explain the result using principal + Reader role + resource-group scope.

Break and fix

  1. While signed in as the test user, try to create a storage account in rg-azlearn-governance. Capture the authorization failure.
  2. As the administrator, change the group’s assignment to Contributor at that resource-group scope only. Retest after token/role propagation.
  3. Remove the Contributor assignment and restore Reader. Confirm that creation fails again.

The lesson is not that Contributor is “stronger” in the abstract. It is that Azure evaluates the roles applicable to the requested action and scope. Do not use a narrower Reader assignment to try to cancel a subscription-level Contributor assignment; role assignments are additive.

Scenario practice

  1. Configure: Choose the resource-group scope and role for a trainee who must inspect the training workload but never create resources.
  2. Diagnose: A user can view a storage account but cannot create one. Which identity, role, scope, and ARM evidence explains the result?
  3. Distinguish: Contrast a tenant, subscription, resource group, ARM deployment, and RBAC role assignment.

Clean up

Delete the training resource group. This removes the deployed storage account.

az group delete --name rg-azlearn-governance --yes --no-wait

Remove the lab role assignment and test group only if they were created solely for this exercise.

Ready to move on?

You are ready when you can explain the difference between a tenant, management group, subscription, resource group, resource, ARM deployment, and an RBAC role assignment without looking them up. You should also be able to name the workload owner, identity, authorization scope, data boundary, deployment path, evidence, recovery action, and cost owner.

Sources and re-audit

Re-audit when ARM deployment behavior, storage-account defaults, resource-group deletion semantics, or RBAC role-assignment behavior changes.

Azure from Zero · RBAC · Azure Policy · Bicep · All labs