Secure Azure Resources with RBAC

Assign built-in and custom roles to secure Azure resources using RBAC.

Introduction

30 Second Summary

Think about how offices have different keys for different rooms. Not everyone gets access to the server room, and a new intern probably should not have the master key.

In this project, you will configure role-based access control in Azure to secure cloud resources. You will assign built-in roles at different scopes, verify access using the CLI, and create a custom role that follows the principle of least privilege.

What You'll Build

You will configure access control for a simulated team environment in Azure using both the Azure portal and Azure CLI.

By the end of this project, you'll have:

  • A resource group representing a team workspace with role assignments configured.
  • Built-in role assignments (Reader and Contributor) applied at different scopes to control access.
  • A custom role definition called "Virtual Machine Operator" with targeted permissions for monitoring and restarting VMs.
  • Secret Mission: Create a "Storage Auditor" custom role with granular permissions and assign it with a documented description.

Are there any prerequisites?

You need an Azure account (a free account works). A credit or debit card is required for Azure account signup verification, but no charges will be incurred.

Before We Start

To secure cloud resources, you need to control who can do what. In Azure, this is handled through Role-Based Access Control (RBAC), a system that assigns permissions to users based on their role.

In this step, you will set up your Azure account and install the Azure CLI so you can manage role assignments from your terminal.

In this step, get ready to:
  • Sign up for or verify your Azure account.
  • Install the Azure CLI.
  • Sign in to the Azure CLI and confirm your subscription is active.
Sign up for Azure or verify your existing account

You need an Azure account to create resources and assign roles. A free account gives you everything needed for this project at no cost.

What is an Azure free account?

Azure offers a free account with $200 credit for 30 days and access to 65+ always-free services. No charges will occur unless you explicitly upgrade to pay-as-you-go later.

A credit or debit card is required for identity verification during signup, but you will not be charged.

Install the Azure CLI

The Azure CLI is a command-line tool for managing Azure resources. You will use it throughout this project to create role assignments, list permissions, and define custom roles.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
  • Check if Azure CLI is already installed by running this command:
az --version

✔️ I see version 2.87.0 or higher

Your Azure CLI is up to date. Skip ahead to the next substep where you sign in.

ⓧ I see an older version

You have Azure CLI installed but need to update it. Upgrade to the latest version by running:

az upgrade

The CLI will prompt you to confirm the upgrade. Enter y to proceed.

After the upgrade completes, run az --version again to confirm you see 2.87.0 or higher.

ⓧ Command not found

Azure CLI is not installed yet. Follow the instructions for your operating system below.

Windows

  • Install Azure CLI using WinGet by running this command in PowerShell:
winget install --exact --id Microsoft.AzureCLI
What happens after installation?

After the installation is complete, you must close and reopen any active terminal window to use the Azure CLI. This is required for your system to recognize the new az command.

  • Close PowerShell completely and reopen it.
  • Verify the installation by running:
az --version

You should see version 2.87.0 or higher in the output.

macOS

  • Install Azure CLI using Homebrew by running this command in Terminal:
brew update && brew install azure-cli
  • After installation completes, verify by running:
az --version

You should see version 2.87.0 or higher in the output.

Homebrew not installed?

If you see a command not found error for brew, install Homebrew first by visiting https://brew.sh and following the instructions. Then re-run the install command above.

Help me install Homebrew and Azure CLI on macOS

Still having trouble with the install?

Make sure your terminal is running with standard permissions. If you see a permissions error on Windows, try running PowerShell as Administrator.

Help me troubleshoot my Azure CLI installation

Sign in to the Azure CLI

Now that the CLI is installed, you need to authenticate it with your Azure account so it can manage your resources.

  • Sign in to Azure by running this command:
az login

What happens when you run az login?

A browser window will open automatically, asking you to sign in with your Microsoft account. After signing in, the browser will confirm the authentication and you can return to your terminal.

If a browser does not open, the terminal will display a URL and a device code for you to sign in manually.

  • After signing in, confirm your subscription is active by running:
az account show --output table

You should see a table with your subscription name, subscription ID, and a state of Enabled.

Seeing a login error or no subscription?

If you see no subscriptions listed, make sure you completed the Azure signup process fully, including card verification. You can also try running az login again with a different browser.

Help me fix my Azure CLI authentication

Your environment is ready. Next up, you will explore Azure's built-in roles and understand how scope controls where permissions apply.

Set Up Your Azure Account and CLI

Before you can configure access control in Azure, you need two things: a browser session in the Azure portal and a working Azure CLI on your machine.

In this step, you will sign into the Azure portal, install the Azure CLI, and authenticate so you can run commands from your terminal.

In this step, get ready to:
  • Sign in to the Azure portal.
  • Install and verify the Azure CLI.
  • Authenticate and confirm your subscription details.
Sign up for Azure or verify your existing account

The Azure portal is the web-based management interface where you will visually confirm role assignments later in this project.

What is the Azure free account?

Azure offers $200 in credit for 30 days plus free monthly amounts of 65+ always-free services. No charges are incurred unless you explicitly upgrade to pay-as-you-go.

A credit or debit card is required for identity verification during signup, but nothing will be charged for this project.

  • After signing in, confirm you see the Azure portal home page with the search bar at the top and service icons below.

Why do I need to sign into the portal?

Azure requires multifactor authentication (MFA) for portal sign-ins. Having a browser session active now means you can quickly switch between the portal and CLI throughout the project to verify your role assignments visually.

Stuck in a sign-in loop?

If your browser keeps redirecting between the login page and the portal, check your system clock and time zone. A mismatch is the most common cause. Open your Date & Time settings and enable automatic time sync.

If the problem persists, try an incognito or InPrivate browser window.

Help me troubleshoot my Azure portal sign-in issue.

Install the Azure CLI

The Azure CLI is a command-line tool that lets you manage Azure resources from your terminal. You will use it to create role assignments, list permissions, and define custom roles throughout this project.

  • Press the Windows key to open your search bar.
  • Type PowerShell and press Enter to open it.
  • Install the Azure CLI by running this command:
winget install --exact --id Microsoft.AzureCLI

What does this command do?

This uses WinGet (the Windows package manager) to install the Azure CLI. The --exact flag ensures you get the correct package, and --id Microsoft.AzureCLI specifies the exact package identifier.

  • Close your PowerShell window completely after the installation finishes.
  • Open a new PowerShell window (press the Windows key, type PowerShell, press Enter).
  • Verify the installation by running:
az --version

You should see version 2.87.0 or later in the output.

Why close and reopen the terminal?

The Azure CLI installer updates your system PATH. Your existing terminal session still uses the old PATH, so it cannot find the new az command. A fresh terminal window picks up the updated PATH automatically.

✔️ I see version 2.87.0 or higher

Your Azure CLI is ready. Move on to the next substep.

ⓧ I see an older version

You have an older version installed. Upgrade by running:

az upgrade

Follow the prompts, then run az --version again to confirm you see 2.87.0 or higher.

ⓧ Command not found

The CLI did not install correctly or your terminal was not restarted. Try these steps:

  • Make sure you fully closed and reopened PowerShell after the install.
  • Re-run the install command:
winget install --exact --id Microsoft.AzureCLI
  • Close and reopen PowerShell again, then retry az --version.

Help me troubleshoot my Azure CLI installation on Windows.

Sign in to the Azure CLI

Now that the CLI is installed, you need to authenticate it so your terminal commands can access your Azure subscription.

  • In your PowerShell window, sign in by running:
az login

What happens when you run this?

A browser window opens for you to sign in with your Microsoft account. After you authenticate, the CLI stores a token locally so future commands can access your subscription without re-authenticating.

Azure requires MFA for CLI sign-ins, so complete any authentication prompts in your browser.

  • Complete the sign-in in the browser window that opens.
  • After signing in, confirm your subscription is active by running:
az account show --output table

You should see a table with your subscription name, subscription ID, and state showing Enabled.

  • Note down your subscription ID from the output. You will need it in later steps when constructing scope paths for role assignments.

Keep your subscription ID handy

Your subscription ID looks like a long string of letters, numbers, and hyphens (e.g. 12345678-abcd-1234-abcd-1234567890ab). Copy it somewhere accessible. You will paste it into multiple commands throughout this project.

Don't see a subscription?

If the output shows no subscription or an error, make sure you signed in with the same Microsoft account you used to create your Azure free account.

If you have multiple subscriptions, you can set the active one with az account set --subscription "Your Subscription Name".

Help me fix my Azure CLI subscription issue.

Your Azure environment is ready. Next up, you will explore the built-in roles that Azure provides and understand how scopes control where permissions apply.

Explore Built-in Roles and Understand Scopes

Before you assign any roles, you need to understand what roles are available and where they apply. Azure comes with hundreds of built-in roles, each defining a set of allowed and denied actions.

In this step, you will explore built-in roles using the Azure CLI and learn how scopes control where permissions apply. This foundation will make the role assignments in the next step much clearer.

In this step, get ready to:
  • List built-in roles using the Azure CLI.
  • View the scope hierarchy in the Azure portal.
  • Compare the Reader, Contributor, and Owner roles.
List built-in roles using the CLI

Azure has hundreds of built-in roles you can assign without creating anything custom. Let's start by seeing the full list, then drill into a specific role to understand its structure.

  • List all available built-in roles by running this command:
az role definition list --output table

What does this command do?

This queries Azure for every role definition available to your subscription and displays them in a readable table format. You will see columns for the role name, type, and description.

The list is long because Azure provides roles for every service. In the next command, you will zoom into one specific role.

  • You should see a table with hundreds of rows listing role names like Contributor, Reader, and Owner alongside service-specific roles.
  • Inspect the Contributor role in detail by running this command:
az role definition list --name "Contributor" --output json

What is a role definition?

A role definition is a JSON object that describes what a role can and cannot do. The key fields are:

  • Actions lists the operations the role is allowed to perform.
  • NotActions lists operations explicitly excluded from the allowed set.
  • AssignableScopes defines where the role can be assigned.
  • You should see a JSON array containing the Contributor role with * in its Actions (meaning it can do everything) and entries like Microsoft.Authorization/*/Write in its NotActions (meaning it cannot manage role assignments).

Seeing an empty result or error?

Make sure you are still signed in to the Azure CLI. Run az account show to confirm your session is active.

If your session expired, run az login again to re-authenticate. Help me troubleshoot my az role definition list command

Understand the scope hierarchy

Roles alone do not grant access. A role must be assigned at a specific scope, which determines which resources the permissions apply to.

  • Switch to the Azure portal in your browser.
  • In the search bar at the top, type Subscriptions and select Subscriptions from the results.
  • Click on your subscription name to open it.
  • In the left menu, click Access control (IAM).
  • Click the Role assignments tab to see any existing role assignments at this scope.

What are the four scope levels?

Azure organizes resources into four nested scope levels. Permissions assigned at a higher scope automatically inherit downward to child scopes:

  • Management group (broadest, covers multiple subscriptions).
  • Subscription (all resource groups and resources within it).
  • Resource group (a logical container for related resources).
  • Resource (narrowest, a single VM, storage account, or database).

A Reader role assigned at the subscription scope gives read access to every resource group and resource inside that subscription. This inheritance is what makes scopes so powerful.

  • You should see the Access control (IAM) page showing any current role assignments for your subscription. If this is a new account, you will likely see your own user listed as Owner.
Compare key built-in roles

The three most important built-in roles are Reader, Contributor, and Owner. Understanding their differences is essential for applying the principle of least privilege.

  • Inspect the Reader role by running this command:
az role definition list --name "Reader" --output json

How do Reader, Contributor, and Owner differ?

Each of these three roles grants a progressively wider set of permissions:

  • Reader has only */read in Actions. It can view all resources but cannot make any changes.
  • Contributor has * in Actions but Microsoft.Authorization/*/Write and others in NotActions. It can manage everything except role assignments.
  • Owner has * in Actions with no NotActions. It has full access including the ability to assign roles to others.

The principle of least privilege means always choosing the narrowest role that still lets someone do their job. If a team member only needs to view dashboards, Reader is the right choice.

  • In the Reader role JSON output, confirm that the actions array contains only */read and the notActions array is empty.

Output looks confusing?

The JSON output can be long. Focus on the permissions section inside each role definition. Look for the actions and notActions arrays to understand what each role allows and denies.

Help me understand the JSON output from az role definition list

You now understand how Azure roles define permissions and how scopes control where those permissions apply. Next up, you will create a resource group and put this knowledge into practice by assigning roles at different scopes.

Create a Resource Group and Assign Built-in Roles

You now understand how Azure's built-in roles differ and how scopes control where permissions apply. Time to put that knowledge into practice by creating real resources and assigning roles.

In this step, you will create a resource group to represent a team workspace. Then you will assign the Reader role at subscription scope and the Contributor role at resource group scope to see how the same user can have different permissions at different levels.

In this step, get ready to:
  • Create a resource group to simulate a team environment.
  • Assign the Reader built-in role at subscription scope.
  • Assign the Contributor built-in role at resource group scope.
Create a resource group

A resource group is a container that holds related Azure resources. You will create one named rbac-project-rg to represent a team workspace where you can practice assigning roles.

  • Create the resource group by running this command in your terminal:
az group create --name rbac-project-rg --location eastus

What does this command do?

This creates a new resource group called rbac-project-rg in the eastus region.

Resource groups are free to create and act as logical boundaries for managing permissions. Any role assigned at this resource group scope applies only to resources inside it.

  • You should see JSON output containing "provisioningState": "Succeeded" confirming the resource group was created.

Seeing an authorization error?

Make sure you are signed in to the correct subscription. Run az account show to confirm your active subscription.

If you see a permissions error, your account may not have Contributor or Owner access on the subscription. Free trial accounts automatically have Owner access, so this should not occur on a new free account.

Help me troubleshoot my az group create error

Assign the Reader role at subscription scope

Now you will create your first role assignment. Assigning Reader at the subscription scope grants read-only access to all resources across the entire subscription.

  • First, note your subscription ID and email address. You already retrieved these from az account show in the previous step.
  • Assign the Reader role at subscription scope by running this command:
az role assignment create --assignee [[YOUR_EMAIL="your Azure account email"]] --role "Reader" --scope "/subscriptions/[[SUB_ID="your subscription ID from az account show"]]"

What does this command do?

The --assignee flag identifies who receives the role. This is the email address you sign in to Azure with.

The --role flag specifies which role to assign. Reader grants only */read permissions, so the assignee can view resources but cannot modify them.

The --scope flag defines where the permission applies. Setting it to /subscriptions/{id} means the role applies across the entire subscription.

  • You should see JSON output containing the role assignment details, including a roleDefinitionName of Reader and your subscription path as the scope.

Why assign roles to yourself?

In a real team, you would assign roles to other users or groups. Since you likely do not have a second Azure account, you are assigning to your own account for practice.

As the subscription Owner, you already have full access. These additional assignments demonstrate how RBAC works without affecting your existing permissions.

Getting a "does not exist" error?

Double-check that the email you used in --assignee exactly matches the email from az account show.

Verify your subscription ID has no extra spaces or characters. You can run az account show --query id --output tsv to get the clean ID value.

Help me fix my role assignment error

Assign the Contributor role at resource group scope

Now you will assign a more powerful role, but at a narrower scope. The Contributor role grants full management permissions (except role assignment), but only within the rbac-project-rg resource group.

  • Assign the Contributor role at resource group scope by running this command:
az role assignment create --assignee [[YOUR_EMAIL="your Azure account email"]] --role "Contributor" --scope "/subscriptions/[[SUB_ID="your subscription ID from az account show"]]/resourceGroups/rbac-project-rg"

How does this differ from the Reader assignment?

The Reader role you assigned earlier applies to the entire subscription but only allows viewing. This Contributor assignment allows full resource management but is limited to a single resource group.

This is the principle of least privilege in action. You grant broad read access for visibility, then targeted write access only where the user needs to make changes.

  • You should see JSON output with roleDefinitionName showing Contributor and the scope pointing to /subscriptions/.../resourceGroups/rbac-project-rg.

Command succeeded but output looks wrong?

Confirm the scope path ends with resourceGroups/rbac-project-rg and not resourcegroups (the G in Groups must be uppercase).

If you see a resource group not found error, make sure the az group create command from the previous substep completed successfully.

Help me troubleshoot my Contributor role assignment

You now have two role assignments configured at different scopes. Next up, you will verify these assignments using both the Azure portal and CLI queries to confirm everything is in place.

Verify and List Role Assignments

You have assigned the Reader role at the subscription scope and the Contributor role at the resource group scope. Now it is time to confirm those assignments are in place.

Verifying role assignments is a critical habit in real cloud environments. In this step, you will use both the Azure CLI and the Azure portal to confirm your assignments exist at the correct scopes.

In this step, get ready to:
  • List all role assignments for your user via the CLI.
  • Verify assignments visually in the Azure portal.
  • Filter role assignment output with a targeted query.
List role assignments for your user

Before trusting that your role assignments are active, you should always confirm them with a direct query. The az role assignment list command retrieves every assignment tied to a specific user.

  • List all role assignments for your account by running this command:
az role assignment list --assignee [[YOUR_EMAIL="your-email@example.com"]] --output table --all

What does this command do?

The --assignee flag filters results to only your account.

The --output table flag formats results as a readable table with Principal, Role, and Scope columns. The --all flag includes assignments at child scopes so nothing is hidden from you.

You should see a table listing both the Reader assignment (scoped to your subscription) and the Contributor assignment (scoped to rbac-project-rg).

Only seeing one assignment?

Make sure you included the --all flag. Without it, the command only returns assignments at the default subscription scope and may hide the resource group assignment.

Also confirm the email address you passed to --assignee matches the one you used in the previous step exactly.

help me figure out why my role assignment list is missing entries

Verify in the Azure portal

The CLI gives you a fast programmatic check, but the Azure portal provides a visual confirmation that is easier to read at a glance.

  • Switch back to the Azure portal in your browser.
  • In the portal search bar at the top, type rbac-project-rg and select your resource group from the results.
  • In the left sidebar of the resource group, click Access control (IAM).
  • Click the Role assignments tab.
  • You should see your email listed with the Contributor role.

Now confirm the Reader assignment at the subscription level.

  • In the portal search bar, type Subscriptions and select Subscriptions from the results.
  • Click your subscription name.
  • In the left sidebar, click Access control (IAM).
  • Click the Role assignments tab.
  • You should see your email listed with the Reader role.

Why verify in both places?

Each scope in Azure has its own Access control (IAM) blade. An assignment at the subscription scope will not appear on the resource group IAM page unless you check the Include inherited assignments filter.

Checking each scope individually confirms that your assignments landed at exactly the right level in the hierarchy.

Filter and query role assignments

In real environments, the full role assignment list can be long and noisy. The --query flag lets you extract only the fields you care about using a JMESPath expression.

  • Get a clean summary of who has access to your resource group by running this command:
az role assignment list --resource-group rbac-project-rg --output json --query "[].{principalName:principalName, roleDefinitionName:roleDefinitionName, scope:scope}"

What does this query do?

The --resource-group flag scopes the results to only rbac-project-rg.

The --query flag uses a JMESPath expression to select three fields from each result: principalName (who), roleDefinitionName (what role), and scope (where). This is much easier to read than the full JSON output.

You should see a JSON array with your email, the Contributor role, and the scope path pointing to rbac-project-rg.

Save queries for auditing

In production, teams run filtered queries like this regularly to audit who has access to sensitive resource groups. You can save useful queries as shell aliases or scripts for repeated use.

Seeing an empty array?

Double check the resource group name is exactly rbac-project-rg. A typo will return an empty result without an error.

If you still see no results, run the command without --query to see the full output and confirm assignments exist for that resource group.

help me troubleshoot why my filtered role assignment query returns empty results

Your role assignments are confirmed at both scopes. Next up, you will create a custom role that grants only the specific permissions needed to monitor and restart virtual machines.

Create a Custom Role Definition

You have verified that built-in roles are correctly assigned at both subscription and resource group scopes. Now it is time to go further.

Built-in roles cover common access patterns, but real-world teams often need more precise control. In this step, you will create a custom role that grants only the permissions needed to monitor and restart virtual machines. This is the principle of least privilege in action.

In this step, get ready to:
  • Create a custom role JSON definition file.
  • Register the custom role in Azure.
  • Assign the custom role at resource group scope.
Create the custom role JSON file

A custom role definition is a JSON file that specifies exactly which actions a principal can perform. The "Virtual Machine Operator" role you will create grants read access to compute, storage, and network resources, plus the ability to start and restart VMs.

  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create a new file called vm-operator-role.json on your Desktop and paste the following content into it:
{
  "Name": "Virtual Machine Operator",
  "Description": "Can monitor and restart virtual machines.",
  "Actions": [
    "Microsoft.Storage/*/read",
    "Microsoft.Network/*/read",
    "Microsoft.Compute/*/read",
    "Microsoft.Compute/virtualMachines/start/action",
    "Microsoft.Compute/virtualMachines/restart/action",
    "Microsoft.Authorization/*/read",
    "Microsoft.ResourceHealth/availabilityStatuses/read",
    "Microsoft.Resources/subscriptions/resourceGroups/read",
    "Microsoft.Insights/alertRules/*",
    "Microsoft.Insights/diagnosticSettings/*",
    "Microsoft.Support/*"
  ],
  "NotActions": [],
  "DataActions": [],
  "NotDataActions": [],
  "AssignableScopes": [
    "/subscriptions/[[SUBSCRIPTION_ID="your subscription ID"]]"
  ]
}

What does this file define?

  • Actions lists every operation this role is allowed to perform. The read entries (Microsoft.Storage/*/read, Microsoft.Network/*/read, Microsoft.Compute/*/read) grant visibility into resources without modifying them.
  • The two start/action and restart/action entries are the only write-like operations the role allows. The operator can restart a stuck VM but cannot delete or resize it.
  • NotActions is empty because we are not excluding anything from the allowed actions.
  • AssignableScopes controls where this role can be assigned. Setting it to your subscription means the role can be used anywhere within that subscription.
  • Save the file as vm-operator-role.json on your Desktop.
  • Confirm the file exists by running:
ls vm-operator-role.json

You should see vm-operator-role.json in the output.

Don't see the file?

  • Make sure you saved the file on the Desktop and that your terminal is in the same directory. Run pwd to check your current location.
  • Check that the file name is exactly vm-operator-role.json with no extra spaces or extensions like .json.txt.

Help me find my vm-operator-role.json file on my Desktop.

✔️ Awesome, I've got everything!

Great. Double check you have saved vm-operator-role.json with your actual subscription ID in the AssignableScopes field.

ⓧ I'd like to double check the full code

Here is the complete vm-operator-role.json file for reference:

{
  "Name": "Virtual Machine Operator",
  "Description": "Can monitor and restart virtual machines.",
  "Actions": [
    "Microsoft.Storage/*/read",
    "Microsoft.Network/*/read",
    "Microsoft.Compute/*/read",
    "Microsoft.Compute/virtualMachines/start/action",
    "Microsoft.Compute/virtualMachines/restart/action",
    "Microsoft.Authorization/*/read",
    "Microsoft.ResourceHealth/availabilityStatuses/read",
    "Microsoft.Resources/subscriptions/resourceGroups/read",
    "Microsoft.Insights/alertRules/*",
    "Microsoft.Insights/diagnosticSettings/*",
    "Microsoft.Support/*"
  ],
  "NotActions": [],
  "DataActions": [],
  "NotDataActions": [],
  "AssignableScopes": [
    "/subscriptions/[[SUBSCRIPTION_ID="your subscription ID"]]"
  ]
}
Register the custom role in Azure

With the JSON file ready, you can register it as a custom role definition in your Azure tenant.

  • Create the custom role in Azure by running this command:
az role definition create --role-definition vm-operator-role.json

What does this command do?

The az role definition create command reads the JSON file and registers its contents as a new role definition in your Azure tenant. Once registered, the role becomes available for assignment just like any built-in role.

  • Verify the custom role was created successfully by running:
az role definition list --name "Virtual Machine Operator" --output json

You should see a JSON response containing the role name, description, and the list of actions you defined.

Seeing a permissions error?

  • Creating custom roles requires the Owner or User Access Administrator role on your subscription. If you are using a free trial account, you are automatically the subscription Owner and should have this permission.
  • Make sure the AssignableScopes value in your JSON file contains your actual subscription ID, not the placeholder text. Run az account show --query id --output tsv to retrieve it.
  • Confirm that vm-operator-role.json is in your current directory. The command reads the file from wherever your terminal is located.

Help me fix my custom role creation error.

Assign the custom role to your user

Now that the role exists, you can assign it to a user at a specific scope. You will assign it to yourself at the resource group scope so the permissions apply only within rbac-project-rg.

  • Assign the Virtual Machine Operator role at resource group scope by running:
az role assignment create --assignee "[[YOUR_EMAIL="your-email@example.com"]]" --role "Virtual Machine Operator" --scope "/subscriptions/[[SUBSCRIPTION_ID="your subscription ID"]]/resourceGroups/rbac-project-rg"

What does this assignment do?

This command creates a role assignment with three elements: a security principal (your user account), a role definition (Virtual Machine Operator), and a scope (the rbac-project-rg resource group).

Because the scope is set to the resource group level, your custom permissions apply only to resources inside rbac-project-rg. Resources in other resource groups are unaffected.

  • Verify the assignment was created by running:
az role assignment list --assignee "[[YOUR_EMAIL="your-email@example.com"]]" --role "Virtual Machine Operator" --output table

You should see a table row showing the Virtual Machine Operator role assigned at the rbac-project-rg scope.

Role assignment not appearing?

  • Azure RBAC is eventually consistent. Role assignment changes can take up to 10 minutes to propagate. Wait a moment and run the list command again.
  • Make sure you replaced the email placeholder with the same email address you used in previous steps. Run az account show --query user.name --output tsv to confirm your signed-in email.
  • Check that the subscription ID in the --scope matches the one from az account show.

Help me troubleshoot my custom role assignment.

You have created a custom role that follows the principle of least privilege. Next up, you will clean up all the role assignments and resources you created throughout this project.

Secret mission

Create a Storage Auditor Custom Role

You have mastered built-in roles and created a Virtual Machine Operator custom role. Now, take it further by building a Storage Auditor role that grants only the permissions needed to read storage account properties and list blob containers. You will also learn how to document role assignments using the --description parameter, a best practice for compliance auditing.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

This project uses only Azure RBAC features (role assignments, custom role definitions, and a resource group), all of which are free. There are no ongoing costs for leaving these resources in place.

Resources you used:

  • Role assignments: Reader (subscription scope), Contributor (resource group scope), Virtual Machine Operator (resource group scope).
  • Custom role definition: Virtual Machine Operator.
  • Resource group: rbac-project-rg (eastus).
  • Local files: vm-operator-role.json and storage-auditor-role.json.

Keep everything running

No action needed. Choose this if you plan to continue experimenting with Azure RBAC or building on this project.

  • Your role assignments, custom role definition, and resource group remain active in Azure.
  • Azure CLI stays installed on your machine for future Azure projects.
  • None of these resources incur charges. Azure RBAC is free.

Pause - I'll come back to this later

Remove the role assignments to tidy up your access control, but keep the resource group and local files so you can pick up where you left off.

  • Remove the Virtual Machine Operator assignment:
az role assignment delete --assignee [[YOUR_EMAIL="your-email@example.com"]] --role "Virtual Machine Operator" --scope "/subscriptions/[[SUB_ID="your-subscription-id"]]/resourceGroups/rbac-project-rg"
  • Remove the Contributor assignment:
az role assignment delete --assignee [[YOUR_EMAIL="your-email@example.com"]] --role "Contributor" --scope "/subscriptions/[[SUB_ID="your-subscription-id"]]/resourceGroups/rbac-project-rg"
  • Remove the Reader assignment:
az role assignment delete --assignee [[YOUR_EMAIL="your-email@example.com"]] --role "Reader" --scope "/subscriptions/[[SUB_ID="your-subscription-id"]]"

Your custom role definition, resource group, and local JSON files stay in place for when you return.

Delete - I don't want to use this again

Remove all project resources completely. This deletes role assignments, the custom role definition, the resource group, and your local files.

  • Remove the Virtual Machine Operator role assignment:
az role assignment delete --assignee [[YOUR_EMAIL="your-email@example.com"]] --role "Virtual Machine Operator" --scope "/subscriptions/[[SUB_ID="your-subscription-id"]]/resourceGroups/rbac-project-rg"
  • Remove the Contributor role assignment:
az role assignment delete --assignee [[YOUR_EMAIL="your-email@example.com"]] --role "Contributor" --scope "/subscriptions/[[SUB_ID="your-subscription-id"]]/resourceGroups/rbac-project-rg"
  • Remove the Reader role assignment:
az role assignment delete --assignee [[YOUR_EMAIL="your-email@example.com"]] --role "Reader" --scope "/subscriptions/[[SUB_ID="your-subscription-id"]]"
  • Delete the custom role definition:
az role definition delete --name "Virtual Machine Operator"
  • Delete the resource group:
az group delete --name rbac-project-rg --yes --no-wait
  • Delete the local JSON files. On macOS or Linux:
rm vm-operator-role.json storage-auditor-role.json
  • On Windows (PowerShell):
Remove-Item vm-operator-role.json, storage-auditor-role.json

Nice Work!

Nice Work!

You have just secured Azure resources using role-based access control. You now know how real organizations manage who can access what in the cloud.

You've learned how to:

  • Assigned built-in roles (Reader, Contributor) at different scopes to control access across your Azure subscription and resource groups.
  • Created a custom role definition ("Virtual Machine Operator") with targeted permissions following the principle of least privilege.
  • Verified and queried role assignments using both the Azure portal and Azure CLI.
  • Created a "Storage Auditor" custom role with granular permissions and assigned it with a documented description for audit purposes.

Ready to quiz yourself?