Skip to main content

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:

ValuePurpose
Application (client) IDUniquely identifies this app registration
Directory (tenant) IDWhich tenant this registration belongs to
Redirect URIsWhere Entra is allowed to send users back to after a login flow completes — must match exactly what the app actually uses
Client secret / certificateHow 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 PrincipalManaged Identity
CredentialA client secret or certificate you generate and must rotate/manage yourselfFully managed by Azure — no credential you ever see or handle at all
Tied toAn 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 riskClient secrets expire and must be rotated manually or via automation — a genuinely common cause of pipelines suddenly failing authNo expiration to manage — Azure handles credential rotation invisibly
Typical useCI/CD pipelines (Azure DevOps service connections), external integrations that aren't themselves Azure resourcesAn 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

TypeLifecycle
System-assignedCreated and destroyed automatically with the resource it's attached to — one-to-one, deleted when the App Service is deleted
User-assignedCreated 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

SymptomLikely causeWhat to check
Auth fails silently, no clear startup error, token looks otherwise validMissing AzureAd:Instance in Microsoft.Identity.Web configurationConfirm 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 SQLThe corresponding Azure AD database user was never created inside the databaseConnect via Azure AD auth and run CREATE USER ... FROM EXTERNAL PROVIDER for that identity
Pipeline auth suddenly fails after working for monthsService principal's client secret expiredCheck 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 oneEach system-assigned identity is unique per resource — role assignments don't transfer between themConfirm 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 individuallyUsing system-assigned identities where a user-assigned identity would be more appropriateConsider 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 accessManaged identities only exist for actual Azure resources — nothing to authenticate as locallyUse 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

CategoryItemDetail
ConceptTenantAn isolated Entra ID directory instance
ConceptApp registrationHow an app declares itself to Entra, has client ID/tenant ID/redirect URIs
IdentityService principalCredential you manage yourself, usable outside Azure
IdentityManaged identityAzure-managed, no credential, tied to a specific resource
Managed identitySystem-assignedTied 1:1 to a resource's lifecycle
Managed identityUser-assignedStandalone, shareable across multiple resources
GotchaAzureAd:InstanceRequired by Microsoft.Identity.Web — omission causes silent auth failure
GotchaManaged identity SQL authRequires CREATE USER ... FROM EXTERNAL PROVIDER, via an AD-authenticated connection
Commandaz ad app createCreate an app registration
Commandaz webapp identity assignAssign 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.