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
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
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
Conditional Access
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.
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:
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:
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
✅ Correct: managed identity / federated
❌ Wrong: Owner role for app
✅ Correct: least privilege
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.