Microsoft Entra ID
Volume 4 — Azure Foundations
Microsoft Entra ID (formerly Azure Active Directory) is the identity platform underneath every Azure sign-in, every service principal, and every managed identity used across this handbook. The Authentication & Authorization chapter covered Entra External ID (CIAM) specifically for customer-facing login flows and JWT claims — this chapter covers the broader Entra ID platform: tenants, app registrations, and the machine identities (service principals and managed identities) that Azure resources and pipelines use to authenticate to each other.
1. Tenant and Directory
A tenant is a dedicated, isolated instance of Entra ID — effectively "the directory" for an organization. Every user, group, app registration, and Azure subscription is associated with exactly one tenant (though a subscription's resources can be accessed by users from other tenants via explicit guest access, that's the exception, not the default).
az account show --query "tenantId"
Traxs Group's Azure resources live under one Entra tenant; the External ID (CIAM) tenant used for RoundTrip/Waypoint customer authentication (covered in the Authentication & Authorization chapter) is conceptually related but serves a distinct purpose — a workforce tenant manages your organization's identities and resources, while a CIAM tenant manages your customers' identities for sign-in to your product.
2. App Registrations
An app registration is how an application declares itself to Entra ID — it's what makes OAuth2/OIDC sign-in (or API-to-API authentication) possible at all.
az ad app create --display-name "RoundTrip API"
Key values every app registration has:
| Value | Purpose |
|---|---|
| Application (client) ID | Uniquely identifies this app registration |
| Directory (tenant) ID | Which tenant this registration belongs to |
| Redirect URIs | Where Entra is allowed to send users back to after a login flow completes — must match exactly what the app actually uses |
| Client secret / certificate | How the app proves its own identity when it's the one authenticating (not a user) |
An app registration paired with a client secret or certificate creates a corresponding service principal (Section 3) — the registration is the definition, the service principal is the actual identity that can be granted permissions.
3. Service Principals vs. Managed Identities
Both let an application (rather than a human) authenticate — the difference is entirely about credential management.
| Service Principal | Managed Identity | |
|---|---|---|
| Credential | A client secret or certificate you generate and must rotate/manage yourself | Fully managed by Azure — no credential you ever see or handle at all |
| Tied to | An app registration, usable from anywhere (a pipeline, an external script, a non-Azure server) | A specific Azure resource (an App Service, a VM) — only usable from that resource |
| Expiration risk | Client secrets expire and must be rotated manually or via automation — a genuinely common cause of pipelines suddenly failing auth | No expiration to manage — Azure handles credential rotation invisibly |
| Typical use | CI/CD pipelines (Azure DevOps service connections), external integrations that aren't themselves Azure resources | An App Service or VM accessing Key Vault, Storage, or SQL — anything running as an Azure resource |
Rule of thumb: if the thing needing to authenticate is itself an Azure resource, use a managed identity. If it's external to Azure (a pipeline agent, a third-party integration), a service principal is the only option, since managed identities are strictly tied to a specific resource and can't be used from outside Azure.
4. System-Assigned vs. User-Assigned Managed Identities
| Type | Lifecycle |
|---|---|
| System-assigned | Created and destroyed automatically with the resource it's attached to — one-to-one, deleted when the App Service is deleted |
| User-assigned | Created independently as its own resource, and can be attached to multiple Azure resources simultaneously — outlives any single resource |
az webapp identity assign --name roundtrip-api --resource-group traxs-prod # system-assigned
az identity create --name traxs-shared-identity --resource-group traxs-prod # user-assigned, standalone resource
az webapp identity assign --name roundtrip-api --resource-group traxs-prod --identities <user-assigned-id>
System-assigned is the simpler default for a single App Service needing its own identity. User-assigned becomes worth the extra setup specifically when several resources need to share the exact same identity and permission set — e.g. multiple App Service slots that should all have identical Key Vault access, without configuring role assignments separately for each.
5. The AzureAd:Instance Configuration Gotcha
Microsoft.Identity.Web (the .NET library handling Entra authentication in RoundTrip/Waypoint) requires an AzureAd:Instance configuration value — and omitting it causes a silent authentication failure, not an obvious startup error.
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "<tenant-id>",
"ClientId": "<client-id>"
}
}
Without Instance explicitly set, the library doesn't throw a clear configuration exception at startup — authentication simply fails at runtime in a way that's easy to mistake for a token/claims problem (covered in the Authentication & Authorization chapter) rather than a missing base configuration value. When JWT validation is failing mysteriously and the token itself looks correct, confirm AzureAd:Instance is actually present in the effective configuration before debugging further into claims or signature validation.
6. Managed Identity SQL Authentication
Using a managed identity to authenticate an App Service to Azure SQL (instead of a SQL login/password) requires the identity to exist as an Azure AD user inside the database itself — and creating that database user requires connecting via an Azure AD-authenticated connection, not a standard SQL login connection.
-- Run this connected via Azure AD auth (e.g. through SSMS/Azure Data Studio with Azure AD login),
-- NOT via a standard SQL Server username/password connection — a standard SQL connection
-- does not have permission to create Azure AD-mapped users, regardless of its own permissions.
CREATE USER [roundtrip-api] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [roundtrip-api];
ALTER ROLE db_datawriter ADD MEMBER [roundtrip-api];
This is a genuinely easy setup step to miss, because the error it produces when skipped — the App Service failing to authenticate to SQL despite having a seemingly correctly configured managed identity and correct Azure RBAC role assignments — looks identical to a permissions problem, when the actual issue is that the database user backing that identity was never created in the first place.
7. Troubleshooting Playbook
| Symptom | Likely cause | What to check |
|---|---|---|
| Auth fails silently, no clear startup error, token looks otherwise valid | Missing AzureAd:Instance in Microsoft.Identity.Web configuration | Confirm Instance, TenantId, and ClientId are all present in the effective configuration at runtime |
| Managed identity has correct RBAC role, still can't connect to Azure SQL | The corresponding Azure AD database user was never created inside the database | Connect via Azure AD auth and run CREATE USER ... FROM EXTERNAL PROVIDER for that identity |
| Pipeline auth suddenly fails after working for months | Service principal's client secret expired | Check the app registration's certificates & secrets expiration date; rotate and update the service connection |
| Managed identity works for one App Service, not a similarly-configured one | Each system-assigned identity is unique per resource — role assignments don't transfer between them | Confirm the specific managed identity's object ID has the intended role assignments, not just "an" identity |
| Need the same permissions across multiple resources, tedious to configure individually | Using system-assigned identities where a user-assigned identity would be more appropriate | Consider a single user-assigned identity, attached to every resource that needs the same access |
| Local development can't replicate an App Service's managed-identity-based access | Managed identities only exist for actual Azure resources — nothing to authenticate as locally | Use a separate local development credential (developer's own az login identity, or a dedicated dev service principal) rather than trying to simulate the managed identity itself |
8. Quick Reference
| Category | Item | Detail |
|---|---|---|
| Concept | Tenant | An isolated Entra ID directory instance |
| Concept | App registration | How an app declares itself to Entra, has client ID/tenant ID/redirect URIs |
| Identity | Service principal | Credential you manage yourself, usable outside Azure |
| Identity | Managed identity | Azure-managed, no credential, tied to a specific resource |
| Managed identity | System-assigned | Tied 1:1 to a resource's lifecycle |
| Managed identity | User-assigned | Standalone, shareable across multiple resources |
| Gotcha | AzureAd:Instance | Required by Microsoft.Identity.Web — omission causes silent auth failure |
| Gotcha | Managed identity SQL auth | Requires CREATE USER ... FROM EXTERNAL PROVIDER, via an AD-authenticated connection |
| Command | az ad app create | Create an app registration |
| Command | az webapp identity assign | Assign a system-assigned managed identity |
Part of the Traxs Engineering Handbook — Volume 4: Azure Foundations. Companion chapters in this volume: Azure CLI, Azure RBAC, Azure Networking, Azure Storage, Azure Key Vault.
Volume 4 — Azure Foundations is now complete: Azure CLI, Azure RBAC, Azure Networking, Azure Storage, Azure Key Vault, and Microsoft Entra ID.