Skip to content

Azure Entra ID & RBAC

Key Points

  • Microsoft Entra ID = renamed Azure AD. Identity for users + apps + workloads. Tenants, app registrations, service principals.
  • RBAC = roles assigned at scope (subscription, RG, resource). 100+ built-in roles; custom possible.
  • Conditional Access = policies that gate sign-in (MFA, device compliance, location, risk).
  • Workload identities: managed identity, service principal, federated identity. Apps don't need passwords.
  • App registration vs Service Principal: registration is the "app definition"; SP is the "instance" in a tenant.

Concepts (deep dive)

What Entra ID is, and how it relates to RBAC

Entra ID (formerly Azure AD) is Microsoft's cloud identity provider — the system that knows who a principal is (a user, a group, an app, a managed identity, a workload). Identities authenticate against Entra ID and receive an OIDC token. Azure RBAC is a separate layer that maps those identities to what they can do on Azure resources — roles assigned at a scope (subscription, resource group, or specific resource).

   ┌────────────────────────────────────────────────────────────┐
   │     Entra ID tenant (the identity provider — WHO)          │
   │                                                            │
   │   ┌────────┐  ┌────────┐  ┌──────────────┐  ┌──────────┐  │
   │   │ users  │  │ groups │  │ service principals│  │ managed │ │
   │   │        │  │        │  │ (app identities)  │  │ identities│
   │   └────────┘  └────────┘  └──────────────┘  └──────────┘  │
   │                                                            │
   │   conditional access, MFA, sign-in risk, app registrations │
   └────────────────────────────────────────────────────────────┘
                              │ "I am <principal>" (OIDC token)
   ┌────────────────────────────────────────────────────────────┐
   │       Azure RBAC (the authorization layer — WHAT)          │
   │                                                            │
   │   role assignment = (principal, role, scope)               │
   │       scope: /subscription/x/resourceGroup/y/resource/z    │
   │       inherited downward                                   │
   │       100+ built-in roles; custom allowed                  │
   └────────────────────────────────────────────────────────────┘

The two-layer split is intentional: you manage who exists in one place (Entra ID) and what they're allowed to do per-resource in another (RBAC). The same identity can hold many roles at many scopes; the same role can be granted to many identities. Almost every "why can't my app read this Key Vault?" debug session ends in either "the identity is wrong" (Entra) or "the role is wrong/scope is wrong" (RBAC).

App Registration vs Service Principal (the most-confused pair)

You'll create both when you onboard a new application, and they sound interchangeable but aren't:

  • An App Registration (Microsoft.Graph/applications) is the blueprint — the global definition of the app: its name, redirect URIs, exposed API scopes, required permissions. Lives in the home tenant where it was created.
  • A Service Principal (Microsoft.Graph/servicePrincipals) is the tenant-local instance — the materialization of the app inside a specific tenant where it's actually used. It's what RBAC grants roles to. A multi-tenant app has one App Registration and N Service Principals (one per consuming tenant).

For a single-tenant app the distinction looks academic; for multi-tenant SaaS or app-consent flows it's load-bearing. az ad app create creates both at once for the common case.

Tenants

A directory. Each Azure subscription belongs to one tenant.

App Registration

App Registration (Application object) — the "blueprint"
Service Principal — the "tenant-local instance" of the app
az ad app create --display-name myapp
# Creates Application + Service Principal automatically

Workload identities

Identity Use
Managed Identity Azure resource (App Service, Function, VM)
Service Principal (with secret) App outside Azure (rare; avoid)
Federated Identity Credential GitHub Actions, K8s pod, external IdP
Workload Identity (AKS) Pod tied to AAD app via service account

Modern best practice: managed identity or workload identity. Avoid client secrets.

RBAC

Subscription
  └── Resource Group
       └── Resource (KeyVault, SQL, etc.)
            └── Sub-resource (secret, table)

Roles assigned at any scope; inherited down. Example built-in roles:

  • Reader — view all.
  • Contributor — modify, but no IAM.
  • Owner — full + IAM.
  • Key Vault Secrets User — read secrets.
  • Storage Blob Data Contributor — RW blobs.

Custom roles possible.

az role assignment create --assignee $principalId --role "Storage Blob Data Reader" --scope $storageId

Least privilege

❌ Owner on subscription for app
✅ Specific role on specific resource

Conditional Access

If user signs in:
  AND device is non-compliant:
    BLOCK or require MFA

Policies layered. Gate access to sensitive apps. Common rules: - Require MFA for admin roles. - Block legacy auth (deprecated protocols). - Require compliant device for accessing finance apps.

Privileged Identity Management (PIM)

Just-in-time elevation. Roles activated for hours; auto-expire. Audit + approval workflows.

User → "I need Owner on subscription" → PIM activates for 4 hours → expires

Service Principal (legacy / external)

az ad sp create-for-rbac -n myapp --role Contributor --scopes /subscriptions/...
# Returns appId + password (secret) — store in Key Vault if must use

For non-Azure apps (laptop scripts, on-prem). Modern alt: federated credentials.

Federated Identity Credential (FIC)

az identity federated-credential create \
  -g rg -i mi --name github-deploy \
  --issuer https://token.actions.githubusercontent.com \
  --subject "repo:org/repo:ref:refs/heads/main" \
  --audience api://AzureADTokenExchange

External identities (GitHub Actions, AKS pod) get tokens via OIDC trust. No secret stored.

App authentication for users

OIDC + Microsoft Entra:

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
"AzureAd": {
  "Instance": "https://login.microsoftonline.com/",
  "TenantId": "tenant-id",
  "ClientId": "app-id"
}

App-to-app auth (client credentials)

Service-to-service:

var token = await new DefaultAzureCredential().GetTokenAsync(
    new TokenRequestContext(new[] { "api://target-app/.default" }));

var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new("Bearer", token.Token);

Or IDownstreamApi from Microsoft.Identity.Web:

public class C(IDownstreamApi api)
{
    public Task<Order[]> GetOrders() =>
        api.GetForAppAsync<Order[]>("OrderApi", o => o.RelativePath = "/orders");
}

Multi-tenant apps

App registered to be used by other tenants:

"signInAudience": "AzureADMultipleOrgs"

Validate iss and tid (tenant ID) in incoming tokens. Different tenants → different policies.

Microsoft Graph

API for Entra + M365 data (users, groups, mail, calendar, files).

var graph = new GraphServiceClient(new DefaultAzureCredential());
var me = await graph.Me.GetAsync();

Permissions: delegated (user) or application.

B2B / B2C

  • B2B: invite external users (guest); they sign in with their own org's identity.
  • B2C (now External ID for Customers): customer-facing identity; sign-up flows; social logins.

App roles

Define in app registration:

"appRoles": [{ "displayName": "Admin", "value": "Admin", "id": "..." }]

Assign to users/groups. Tokens include roles claim.

Groups vs app roles

  • Groups: org-wide; reusable.
  • App roles: app-specific; preferred for app-level authorization.

For new apps, prefer app roles.

Conditional Access for apps

Lock down by policy: - Trusted IP ranges. - Compliant device required. - MFA required. - Block legacy auth.

Tokens

Validate carefully. See JWT Validation Pitfalls. Pin issuer, audience, algorithm.

App permissions vs delegated

  • Delegated: app acts on user's behalf. User context.
  • Application: app acts as itself. No user.

For workers/daemons: application. For user-facing apps: delegated.


Code: correct vs wrong

❌ Wrong: client secret in code

var token = new ClientSecretCredential(tenantId, clientId, "hunter2");

✅ Correct: managed identity / federated

var token = new DefaultAzureCredential();

❌ Wrong: Owner role for app

az role assignment create --assignee app --role Owner

✅ Correct: least privilege

az role assignment create --assignee app --role "Key Vault Secrets User" --scope $kvId

Design patterns for this topic

Pattern 1 — "Managed identity over secrets"

  • Intent: zero-secret cloud auth.

Pattern 2 — "Federated credentials for CI"

  • Intent: GitHub Actions secret-free.

Pattern 3 — "Least privilege RBAC"

  • Intent: scoped, specific roles.

Pattern 4 — "Conditional Access for sensitive apps"

  • Intent: MFA + device compliance.

Pattern 5 — "PIM for admin roles"

  • Intent: just-in-time access.

Pros & cons / trade-offs

Aspect Pros Cons
Managed Identity No secrets Azure-only
FIC External integrations Setup
Conditional Access Zero-trust Configuration
PIM JIT admin Workflow overhead

When to use / when to avoid

  • Always managed identity / FIC over client secrets.
  • Use least-privilege RBAC.
  • Use Conditional Access for sensitive resources.
  • Avoid Owner role for apps.

Interview Q&A

Q1. App Registration vs Service Principal? Registration: app blueprint (in home tenant). SP: instance per tenant; what gets RBAC.

Q2. Managed identity types? System-assigned (tied to resource), user-assigned (independent).

Q3. Federated Identity Credentials? External issuers (GitHub, K8s) trust → AAD token without secret.

Q4. Conditional Access? Policies gating sign-in. MFA, device, location, risk.

Q5. PIM? Just-in-time role activation. Time-limited; audited.

Q6. App role vs Group? App role: app-specific; preferred for authz. Group: org-wide; reusable but less specific.

Q7. Delegated vs Application permissions? Delegated: user context; user must consent. Application: app acts as itself; admin consent.

Q8. Microsoft Graph? API for Entra + M365. Users, groups, mail, files.

Q9. B2B vs External ID for Customers? B2B: invite external users. External ID for Customers (formerly B2C): customer-facing IDP.

Q10. Multi-tenant app token validation? Validate iss and tid; allowlist tenants if needed.

Q11. Tokens — what to validate? Signature, issuer, audience, algorithm, expiry. See JWT pitfalls.

Q12. Owner role — when? Almost never for apps. Specific role at specific scope.


Gotchas / common mistakes

  • ⚠️ Owner on subscription for an app.
  • ⚠️ Client secrets in code.
  • ⚠️ No Conditional Access on sensitive apps.
  • ⚠️ Permanent admin (no PIM).
  • ⚠️ Multi-tenant without tenant validation.

Further reading