Safeguard
Cloud Security

Azure IAM and RBAC Best Practices

A question-driven guide to Azure identity and access management: Entra ID vs Azure RBAC, scoping assignments, managed identities, PIM, and Conditional Access — with az CLI and Terraform examples.

Marcus Chen
Cloud Security Engineer
6 min read

Azure access control confuses people because there are two overlapping systems, and mixing them up is how over-privileged access sneaks in. Microsoft Entra ID roles govern the directory and its services; Azure RBAC governs resources like VMs, storage, and databases. A team that grants Owner "to be safe" or hands a service principal directory-level admin because a doc said to is building the exact conditions that turn one compromised credential into a tenant-wide incident. This guide answers the questions that actually come up when you tighten Azure access, in the order they tend to come up.

What's the Difference Between Entra ID Roles and Azure RBAC?

They control different planes. Entra ID roles (Global Administrator, User Administrator, Application Administrator) manage the directory — users, groups, app registrations, and Microsoft 365. Azure RBAC roles (Owner, Contributor, Reader, and hundreds of scoped built-ins) manage access to Azure resources within subscriptions and resource groups. A Global Administrator can, by default, elevate to manage all Azure subscriptions, which is why directory admin roles must be treated as the crown jewels. Keep the two mental models separate: securing your resources is Azure RBAC work; securing your tenant is Entra ID work.

How Should I Scope Role Assignments?

Always to the narrowest scope that lets the job get done. Azure RBAC assignments inherit downward through management group → subscription → resource group → resource, so an assignment made at the subscription level applies to everything inside it. Assign at the resource or resource-group level by default and reserve subscription-wide assignments for genuine platform roles.

# Scope a workload to exactly one storage account, one role
resource "azurerm_role_assignment" "app_blob_reader" {
  scope                = azurerm_storage_account.data.id
  role_definition_name = "Storage Blob Data Reader"
  principal_id         = azurerm_user_assigned_identity.app.principal_id
}

Prefer specific built-in roles like Storage Blob Data Reader over broad ones like Contributor. If no built-in role fits, write a custom role with an explicit Actions list rather than reaching for a wildcard.

When Should I Use Managed Identities Instead of Service Principals?

Almost always, for Azure-hosted workloads. A managed identity is a service principal whose credential Azure manages and rotates for you — there is nothing to store, leak, or commit to Git. A VM, Function, App Service, or AKS pod can authenticate to Key Vault, Storage, or SQL with a system-assigned or user-assigned managed identity and zero secrets in configuration.

# Enable a system-assigned identity and grant it a scoped role
az webapp identity assign --name sg-api --resource-group sg-rg
az role assignment create \
  --assignee-object-id $(az webapp identity show -n sg-api -g sg-rg --query principalId -o tsv) \
  --assignee-principal-type ServicePrincipal \
  --role "Key Vault Secrets User" \
  --scope $(az keyvault show -n sg-app-kv --query id -o tsv)

Reserve app-registration client secrets and certificates for workloads that genuinely run outside Azure, and rotate them on a schedule.

How Do I Stop Standing Administrative Access?

Use Privileged Identity Management (PIM). Instead of assigning Owner or Global Administrator permanently, make the role eligible, so an admin activates it just-in-time — with justification, optional approval, MFA, and a time limit. Standing privileged access is the difference between a stolen token that can do everything and one that can do nothing until an approval flow runs. Review PIM activation logs as part of your regular access review.

How Do I Enforce Context on Sign-In?

Conditional Access. It evaluates signals — user, device, location, risk — at sign-in and enforces requirements like MFA, compliant device, or block. At minimum: require phishing-resistant MFA for all administrative roles, block legacy authentication protocols that can't honor MFA, and require compliant or hybrid-joined devices for privileged access. Pair this with regular access reviews so group memberships and role assignments don't accumulate silently over time.

How Do I Audit Who Actually Has Access?

You can't tighten what you can't see, and Azure access sprawls quietly through inheritance and nested groups. Start with a periodic export of every role assignment at and below each subscription, paying special attention to assignments made at the subscription or management-group scope, guest (external) accounts, and service principals holding privileged roles.

# List every role assignment in a subscription, including inherited ones
az role assignment list --all --include-inherited \
  --query "[].{principal:principalName, role:roleDefinitionName, scope:scope}" \
  -o table

Cross-reference the results against your access reviews: any Owner or Contributor assignment nobody can justify is a finding. Watch for orphaned assignments left behind by deleted principals and for guest accounts that were added for a one-off project and never removed — both are classic footholds that outlive their purpose.

Azure IAM Checklist

AreaBest practice
ModelKeep Entra ID roles and Azure RBAC mentally separate
ScopeAssign at resource/RG level; avoid subscription-wide Owner
RolesSpecific built-ins over Contributor; custom roles with explicit actions
CredentialsManaged identities for Azure workloads; rotate any stored secrets
PrivilegePIM eligibility for Owner/Global Admin; no standing admin
Sign-inConditional Access MFA; block legacy auth; access reviews scheduled

How Safeguard Helps

Over-privileged Azure access is almost always written into Terraform or Bicep before it becomes a live assignment, which is the cheapest place to catch it. Safeguard's infrastructure-as-code scanning inspects your Azure IaC for subscription-scoped Owner assignments, wildcard custom-role actions, and secrets embedded in configuration — flagging them against the exact line in the pull request so a developer fixes the scope before merge rather than after a security review months later. Griffin, Safeguard's AI triage engine, ranks those identity findings by real blast radius, so a role granting Contributor on a production subscription outranks a harmless reader binding. Because the checks run through the pipeline-native Safeguard CLI, you can gate merges so an over-scoped assignment never ships. If you're comparing this build-time identity analysis to a posture tool that evaluates RBAC after deployment, the Safeguard vs Prisma Cloud comparison breaks down the timing difference.

Catch over-privileged Azure roles before they deploy — create a free account or read the documentation.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.