Command Palette

Search for a command to run...

Back to Blog
Cloud SecurityAzureZero TrustSecurityEntra IDRBACIdentityAZ-104DevSecOps

Project: Building a Zero Trust Identity Architecture in Azure

January 2, 2026
12 min read
Cover image for Project: Building a Zero Trust Identity Architecture in Azure

Screenshot from Azure Portal

In the world of Cloud Engineering, clicking "Create User" is easy. But designing a secure, scalable identity system that survives a security audit? That is the real challenge.

In this project, I simulated a real-world scenario for a fictional FinTech client, FinCore Systems. The goal was to move away from the "Wild West" of manual permissions and implement a Zero Trust architecture using Microsoft Entra ID and Custom RBAC (Role-Based Access Control).

If you are studying for the AZ-104 or just want to learn how to secure Azure like a pro, follow this step-by-step guide.

AZ-104 Labs Curriculum Mapping

This project combines and extends the concepts from the official Microsoft Learning labs. It transforms the isolated tasks into a cohesive, production-ready solution.

Lab 01: Manage Entra ID Identities
Lab 02a: Subscriptions & RBAC

🏢 The Business Scenario

Client: FinCore Systems (FinTech)

The Problem: The "Help Desk" team has too much power. They currently have Contributor access, which allows them to delete production databases.

The Requirement: We need a custom security role that allows them to:

  • Restart Virtual Machines (to fix issues).
  • Open Support Tickets (to get help).
  • Strictly Block them from creating new resources or registering expensive service providers (Shadow IT).

🏗️ The Architecture

Instead of assigning permissions to individuals (which is unscalable), we will build a hierarchy:

  1. Identity: Users are assigned to an Entra ID Group (grp-fincore-support).
  2. Scope: We create a Management Group (mg-fincore-corp) to govern all subscriptions.
  3. Permissions: We attach a Custom RBAC Role to the Management Group, which trickles down to everything below it.
Zero Trust Principle

Never trust, always verify. Permissions are explicitly granted, never assumed. Every action requires validation.


🚀 Step-by-Step Implementation

Phase 1: Identity Management (Entra ID)

First, we need to create the "Who." We never assign roles to users directly; we assign them to groups.

1. Create the Security Group

I started by creating a dedicated security group for the support team. This ensures that if we hire 50 new engineers, we just add them to this group, and they inherit the permissions automatically.

  • Group Name: grp-fincore-support
  • Type: Security

Starting group creation Configuring group details Adding members to group Group creation confirmation

Best Practice

Always assign RBAC roles to groups, not individual users. This provides scalability and reduces administrative overhead when employees change roles or leave the organization.

2. Create the Test User

Next, I created a user named Alex Support to act as our "victim" for testing. Crucially, I set the Usage Location to the United States (a common oversight that blocks license assignments later).

Creating test user


Phase 2: Governance Scope (Management Groups)

To manage policies at scale, we don't want to touch every individual subscription. I created a Management Group to act as a "Root Folder" for the organization.

  • ID: mg-fincore-corp
  • Display Name: FinCore Corporate Root

Management Group Hierarchy

Why Management Groups?

Management Groups allow you to apply governance at scale. Instead of assigning a role to 50 individual subscriptions, you assign it once at the Management Group level, and it automatically cascades down to all child subscriptions and resources.


Phase 3: The "Least Privilege" Custom Role

This is the core of the project. The built-in "Support Request Contributor" role was too weak (can't restart VMs), but "Virtual Machine Contributor" was too dangerous (can delete VMs).

I created a Custom Role by cloning the Support role and modifying it.

1. Adding Permissions (The "Allow" List)

We need to create a role that specifically allows VM restart but denies everything else initially.

Starting IAM Role Creation Defining permissions

I explicitly added Microsoft.Compute/virtualMachines/restart/action. This gives Alex the power to reboot a frozen server without giving him the power to delete it.

Adding VM Restart permission

2. Blocking Shadow IT (The "NotAction" List)

To prevent the Help Desk from accidentally enabling expensive services (like AI or Blockchain), I added Microsoft.Support/register/action to the NotActions list. This effectively "denies" the ability to register new resource providers.

Adding NotActions Reviewing custom role

Common Misconception

NotActions is NOT a "Deny" statement. It simply subtracts permissions from the Actions list in that specific role. If a user has another role that grants the permission, they will still have access.

3. The Final Configuration Code

This JSON represents the final "Infrastructure as Code" artifact for the role.

RoleDefinition.json
ARM
{
  "properties": {
    "roleName": "FinCore Support Specialist",
    "description": "Can open tickets and restart VMs. Cannot register new providers.",
    "assignableScopes": [
      "/providers/Microsoft.Management/managementGroups/mg-fincore-corp"
    ],
    "permissions": [
      {
        "actions": [
          "Microsoft.Authorization/*/read",
          "Microsoft.Resources/subscriptions/resourceGroups/read",
          "Microsoft.Support/*",
          "Microsoft.Compute/virtualMachines/restart/action"
        ],
        "notActions": [
          "Microsoft.Support/register/action"
        ],
        "dataActions": [],
        "notDataActions": []
      }
    ]
  }
}

There are three critical components to this configuration:

  1. AssignableScopes: The role is scoped to /mg-fincore-corp. This means it cannot be assigned at the Root Management Group (too broad) or a single Subscription (too narrow). It exists exactly where FinCore operates.
  2. Actions: We explicitly grant Microsoft.Support/* for ticketing and the specific restart/action for VMs. This avoids the dangerous write or delete permissions found in standard Contributor roles.
  3. NotActions: This acts as a safety filter. Even if another policy or role tries to grant "Support" access, this role explicitly carves out the ability to register new resource providers, preventing accidental cost spikes from "Shadow IT" service headers.

Phase 4: Assigning the Role

With the role created, we now assign it to our security group at the Management Group scope. This ensures that the permissions trickle down to all subscriptions and resources within our organization.

Starting role assignment Selecting the custom role Selecting the target group


Phase 5: The "Hacker" Verification

A security architecture is only good if it works. I logged in as Alex (using an Incognito window) to test the boundaries.

Test 1: VM Operations (The "Least Privilege" Test)

First, I attempted to Restart a Virtual Machine. Since this action was explicitly allowed in our custom role, it should work.

VM Restart Success

Success! The command executed without issues.

Next, I attempted to Delete the same VM. Since this action was NOT in our custom role (and Delete is a destructive action), it should be blocked.

VM Delete Denied

Blocked! Azure's ARM layer correctly prevented the action.

Test 2: Support Operations

I attempted to open a Support Ticket. The custom role successfully allowed access to the support blade.

Opening Support Request Support Ticket Success

Test Passed

Alex can successfully perform legitimate support operations. The role grants exactly what is neededno more, no less.

Test 3: Governance Scope (Blocked)

I attempted to create a new Resource Group. As expected, the Zero Trust policy kicked in.

Access Denied (Expected)

Authorization Failed: The user 'alex.support@fincore.com' does not have authorization to perform action 'Microsoft.Resources/resourceGroups/write' over scope '/subscriptions/xxxx'.

Perfect! The guardrails are working exactly as designed.


📊 Key Takeaways

Identity Design

Use Security Groups for role assignments, not individual users. This ensures scalability and reduces administrative burden.

Best Practice:
Always assign RBAC roles to groups. When employees change roles or leave, simply update group membership instead of hunting down individual assignments.

Least Privilege

Built-in roles are often too broad. Use Custom RBAC Roles to grant exactly the permissions needednothing more.

Example:
The "Contributor" role allows VM deletion. Create a custom "VM Operator" role that only allows start/stop/restart actions.

Hierarchy Design

Use Management Groups to apply governance at scale. Permissions cascade down automatically to all child resources.

Efficiency:
Assign a role once at the Management Group level instead of 50 times across individual subscriptions.

Testing

Always test your roles using a non-privileged account. Verify both positive cases (can do job) and negative cases (cannot break things).

Testing Method:
Use an Incognito window to log in as the test user. Attempt both allowed actions and restricted actions to verify the role works as designed.

🎯 Conclusion

Building a Zero Trust Identity Architecture is not about making access harderit's about making access smarter. By combining:

  • Entra ID Security Groups (for identity)
  • Management Groups (for scope)
  • Custom RBAC Roles (for least-privilege permissions)

...we created a system that is both secure and scalable. The Help Desk team can do their job effectively, but they cannot accidentally (or maliciously) destroy production resources.

For AZ-104 Candidates

This project covers multiple exam domains: Entra ID management, Custom RBAC role creation, Management Group hierarchies, and Zero Trust principles. Understanding these concepts will help you ace identity and governance questions on exam day.

If you're preparing for Azure certifications or building production-grade cloud environments, I hope this walkthrough helps you implement security with confidence.

Next Steps:

  • Implement Conditional Access policies for device compliance
  • Add Azure Policy to enforce naming conventions
  • Deploy Azure AD Privileged Identity Management (PIM) for just-in-time access

Want to see more cloud architecture projects? Follow my blog for deep dives into Azure, AWS, and DevSecOps best practices.

Want to discuss this further?

I'm always happy to chat about cloud architecture and share experiences.