Join our Newsletter — 33% off our NHI Course
Home› Guides› How to replace Azure app secrets with federated…
Guide Non-Human Identity (NHI)

How to replace Azure app secrets with federated credentials: secretless Entra apps without breaking workloads

PDF for newsletter subscribers · free to read online

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 28 October 2026 14 min read
On this page

Every client secret on an Entra ID app registration is a long-lived password that can be copied, leaked or stolen from whoever holds it, and most of them exist only because the workload was set up before federation was an option. Workload identity federation lets the app trust a token issued by the platform the workload already runs on (GitHub Actions, Kubernetes, Google Cloud, AWS, or an Azure user-assigned managed identity) and exchange it for an Entra access token, so no secret is stored anywhere. This guide is the migration job: finding which secrets can be replaced, adding a federated identity credential alongside the secret, cutting the workload over, proving in the logs that the secret is no longer used, and then removing it and blocking new ones. It is written for Entra administrators, platform engineers and NHI programme owners. For the wider risks of client secrets see the Azure Entra Client Secrets Security Guide; for the concept across clouds see the Workload Identity Federation Guide.

Key takeaways

  • Federation removes the secret, not the app. The app registration, its permissions and its service principal stay the same; only the credential type changes, which is why the cutover can be done with overlap and no permission change.
  • Three values must match exactly. The federated identity credential's issuer, subject and audience must match the incoming token's iss, sub and aud claims; a wrong subject is accepted at creation and fails silently at exchange.
  • Prove the secret is unused before removing it. The ClientCredentialType, FederatedCredentialId and ServicePrincipalCredentialKeyId columns in AADServicePrincipalSignInLogs show which credential each sign-in used.
  • The subject is your new security boundary. A subject scoped to a GitHub environment or a single Kubernetes service account is tight; a subject that any branch or namespace can satisfy hands the app's permissions to whoever can run code there.
  • Finish by blocking secrets. App management policies with passwordAddition stop the secret coming back next time someone is in a hurry.

When you need this

  • CI/CD pipelines that deploy to Azure with a client secret stored as a pipeline variable (GitHub Actions, GitLab CI, Azure Pipelines service connections). For GitLab the end-to-end setup is in How to set up workload identity federation for GitLab CI to Azure.
  • Kubernetes workloads on AKS, EKS, GKE or on-premises clusters that mount a secret to call Microsoft Graph, Key Vault or Azure Resource Manager.
  • Workloads in another cloud (Google Cloud service accounts, AWS through IAM outbound identity federation) that call Entra-protected APIs.
  • Azure-hosted apps that use an app registration rather than a managed identity, typically because the app is multitenant or needs app permissions in another tenant. The app can trust a user-assigned managed identity instead of a secret.
  • After an incident or supplier compromise, when rotating secrets would only restart the clock. In the Commvault Metallic breach the exposed credentials were client secrets for Entra app registrations held by a vendor; a credential that is never stored cannot be taken from someone else's environment.

Federation does not fit everything. Workloads on platforms that cannot issue an OIDC token, and third-party SaaS that only accepts a client ID and secret, stay on secrets or certificates. Move those to certificates with short lifetimes and track them with How to find expiring app secrets and certificates in Entra ID.

Before you start

RequirementDetail
Read-only discoveryGraph scope Application.Read.All; Log Analytics read access to the workspace receiving Entra sign-in logs (AADServicePrincipalSignInLogs)
Adding a federated credentialAnyone who can add a secret or certificate to the app can add a federated identity credential. Roles that include microsoft.directory/applications/credentials/update: Application Administrator, Application Developer, Cloud Application Administrator, or the app owner
Blocking secrets afterwardsGlobal Administrator, or Security Administrator plus Cloud Application Administrator or Application Administrator, for app management policies
ToolingAzure CLI (az ad app federated-credential), Az.Resources prerelease module (New-AzADAppFederatedCredential), or Graph /applications/{objectId}/federatedIdentityCredentials
Workload sideAn Azure Identity SDK or MSAL version that supports client assertions; for AKS, Azure Identity minimums are .NET 1.9.0, Go 1.3.0, Java 1.9.0, Node.js 3.2.0 and Python 1.13.0
Change recordApp ID, secret keyId being replaced, consuming workload, owner, and the exact issuer and subject planned

The issuer, subject and audience for each source platform, as Microsoft documents them:

Workload runs onIssuerSubject formatAudience
GitHub Actionshttps://token.actions.githubusercontent.comrepo:<org/repo>:environment:<name>, repo:<org/repo>:ref:refs/heads/<branch>, repo:<org/repo>:ref:refs/tags/<tag> or repo:<org/repo>:pull-requestapi://AzureADTokenExchange
Kubernetes (AKS, EKS, GKE, self-managed)The cluster's OIDC issuer URLsystem:serviceaccount:<namespace>:<service account>api://AzureADTokenExchange
Google Cloudhttps://accounts.google.comThe service account's unique (numeric) IDapi://AzureADTokenExchange
Azure user-assigned managed identityhttps://login.microsoftonline.com/{tenant}/v2.0The managed identity's object (principal) IDapi://AzureADTokenExchange (US Government: api://AzureADTokenExchangeUSGov; China: api://AzureADTokenExchangeChina)

Limits to plan around: 20 federated identity credentials per app or user-assigned managed identity; issuer, subject and audience up to 600 characters each; exactly one audience; no wildcards in any property; the issuer and subject pair must be unique on the app; the credential name (3 to 120 characters, alphanumeric, dash or underscore) cannot be changed later. Only RS256-signed issuers are tested, and Entra ID issued tokens cannot be used as the external token, except through the managed identity scenario above.

Step-by-step

Steps 1 to 3 are read-only. Steps 4 to 6 add a credential and change the workload, and are reversible. Step 7 is destructive.

  1. Inventory secrets and the workloads using them. Export passwordCredentials from every app registration and service principal (the method is in How to find expiring app secrets and certificates in Entra ID). Then find where each secret is used:
    AADServicePrincipalSignInLogs
    | where TimeGenerated > ago(30d)
    | where ResultType == "0"
    | summarize SignIns=count(), IPs=make_set(IPAddress, 20), LastSeen=max(TimeGenerated)
        by AppId, ServicePrincipalName, ClientCredentialType, ServicePrincipalCredentialKeyId
    | order by SignIns desc
    The IP addresses, user agents and resource names tell you whether the caller is a GitHub-hosted runner, a cluster, a cloud VM or a person's laptop. Unused secrets are removal candidates, not migration candidates.
  2. Classify each secret by target platform. Use the decision table below. Record the issuer and the narrowest subject the platform can produce for that one workload.
  3. Check the issuer. Confirm the platform's OIDC discovery document is reachable from the internet (Entra validates the token against the issuer's keys) and that the issuer string in a real token matches what you will enter. GitHub issuers appear in Microsoft's examples both with and without a trailing slash: use the value in the token. A leading or trailing space in the configured issuer blocks the exchange.
  4. Add the federated identity credential (additive). Create it on the same app registration, leaving the secret in place:
    {
      "name": "gh-payments-prod",
      "issuer": "https://token.actions.githubusercontent.com",
      "subject": "repo:contoso/payments:environment:production",
      "description": "Replaces secret keyId 1a2b... CHG-1234",
      "audiences": ["api://AzureADTokenExchange"]
    }
    az ad app federated-credential create --id <appId> --parameters fic.json
    az ad app federated-credential list --id <appId>
    Put the change number and the replaced keyId in the description so the link survives staff changes. Wait several minutes before testing: replication across a region takes time, and early requests fail with AADSTS70021 (no matching federated identity record found).
  5. Change the workload to present a token instead of the secret. The token request swaps client_secret for client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer and a client_assertion that the platform issued, sent to https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token with grant_type=client_credentials. In practice:
    • GitHub Actions: grant the job id-token: write, and pass client-id, tenant-id and subscription-id to the Azure login action without a client secret. Hardening of the GitHub side is in the GitHub Actions OIDC Federation Hardening Guide.
    • AKS: annotate the service account with azure.workload.identity/client-id, label the pod azure.workload.identity/use: "true", and let the SDK read AZURE_FEDERATED_TOKEN_FILE. Do not hard-code the token path.
    • Other Kubernetes or clouds: project a service account token (or fetch a Google or AWS identity token) and pass it to ClientAssertionCredential or the MSAL WithClientAssertion option.
    • Azure compute using an app registration: acquire a managed identity token for api://AzureADTokenExchange/.default and use it as the client assertion; Microsoft.Identity.Web supports this with SourceType SignedAssertionFromManagedIdentity. Only user-assigned managed identities can be used.
    Add retry logic on token requests, as Microsoft advises, rather than assuming the first request after a deployment succeeds.
  6. Run both in parallel and watch the logs. Deploy the federated workload, keep the secret valid, and confirm sign-ins now carry a FederatedCredentialId and no ServicePrincipalCredentialKeyId for the old secret:
    AADServicePrincipalSignInLogs
    | where TimeGenerated > ago(7d) and AppId == "<appId>"
    | summarize count(), LastSeen=max(TimeGenerated)
        by ClientCredentialType, ServicePrincipalCredentialKeyId, FederatedCredentialId
    Leave the secret in place for at least one full run cycle of the workload: monthly jobs, failover paths and disaster recovery runbooks often use a copy of the secret nobody remembers.
  7. Remove the secret (destructive). When the old keyId has had no successful sign-ins for the agreed window, remove it in Certificates & secrets or with the Graph removePassword action, then delete the copy from the pipeline variable store or vault. Removal is immediate and cannot be undone; any caller still using it fails.
  8. Block new secrets on the app. Apply an app management policy with passwordAddition (and symmetricKeyAddition) restricted, scoped to migrated apps or to all apps created after a chosen date. See Hardening afterwards.

Choosing the replacement

SituationBest replacementWhy, and the trade-off
Workload runs in Azure, single tenant, calls Azure resourcesManaged identity directly, no app registrationNo credential to manage at all; the app registration may be retired entirely
Workload runs in Azure but needs an app registration (multitenant, cross-tenant app permissions)Federated credential trusting a user-assigned managed identityKeeps the app's identity and consent; cross-tenant works, cross-cloud does not
GitHub Actions, GitLab CI, Azure PipelinesFederated credential with environment-scoped subjectSubject per environment gives a review gate; branch subjects have no pattern matching, so one credential per branch counts against the 20 limit
Kubernetes inside or outside AzureFederated credential per service accountNamespace and service account become the boundary; anyone who can create pods with that service account gets the token
Google Cloud or AWS workloadsFederated credential using the cloud's identity tokenNo secret crosses clouds; depends on the other cloud's IAM being well governed. See the Cross-cloud workload identity federation guide
Platform cannot issue OIDC tokens, or a SaaS supplier needs a credentialCertificate with short lifetime, or secret with capped lifetimeStill a stored credential; monitor it and revisit when the platform adds federation

Small organisations: start with CI/CD, where a handful of federated credentials remove the most exposed secrets in an afternoon. Large organisations: the 20-credential limit and the one-subject-per-credential rule push towards one app registration per workload or environment rather than one shared deployment app, which is also better for least privilege. Flexible federated identity credentials, which match claims by expression rather than an exact subject, are in preview at the time of writing; treat any pattern-based subject as a widening of trust that needs review.

Verify it worked

  • Sign-in logs: every successful sign-in for the app over the observation window shows a FederatedCredentialId and no ServicePrincipalCredentialKeyId matching a password credential.
  • Credential export: the app's passwordCredentials collection is empty; federatedIdentityCredentials lists only the expected issuer and subject pairs.
  • Stores cleaned: the secret has been deleted from pipeline variables, Kubernetes Secrets, Key Vault and any runbook that held it.
  • Negative test: a run from a branch or namespace outside the subject is refused. An exchange with a non-matching subject fails without a descriptive error, so test the refusal deliberately rather than assuming it.

Rollback and common errors

  • AADSTS70021 straight after creation: replication has not finished. Wait and retry before changing anything.
  • AADSTS70021 that does not clear: issuer, subject or audience mismatch. Decode a real token and compare iss, sub and aud character by character, including the trailing slash and case.
  • Exchange fails after the cutover: while the secret still exists, roll the workload configuration back to it; the federated credential can stay. Once the secret is removed there is no rollback: add a new short-lived secret only as an emergency measure and record it.
  • 409 Conflict in infrastructure as code: credentials on the same user-assigned managed identity were created in parallel. Create them serially (ARM "mode": "serial" or dependsOn chains; Terraform AzureRM 3.40.0 or later does this).
  • 400 "Issuer and subject combination already exists": list existing credentials; an earlier attempt already created it.

Hardening afterwards

  • Block secrets: app management policies support passwordAddition, customPasswordAddition and symmetricKeyAddition to block secrets, and passwordLifetime and asymmetricKeyLifetime to cap the ones you keep. Roll out with exclusions for apps not yet migrated.
  • Control who can add federated credentials: anyone who can add a credential to an app can add a federated one pointing at an issuer they control. Restrict app ownership and Application Administrator assignments, and for user-assigned managed identities consider the Azure Policy deny rule on Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials outside approved deployment paths.
  • Alert on new credentials: a new federated identity credential, secret or certificate on an existing app is a persistence technique (ATT&CK T1098.001 Additional Cloud Credentials). Monitor the Entra audit log. See the Entra ID Sign-In and Audit Log Detection Guide.
  • Review permissions while you are there: federation changes how the app authenticates, not what it can do. Use the migration ticket to remove unused Graph application permissions.
  • Apply Conditional Access for workload identities where licensed, so a token from an unexpected location is refused even if the subject matches.

Common failure patterns

  • Broad subjects: trusting a pull-request subject or a whole repository's branches on an app with write permissions lets untrusted code obtain production tokens. Use environments with required reviewers.
  • Leaving the secret "just in case": the migration adds a federated credential and never removes the secret, so the attack surface grows rather than shrinks.
  • Shared deployment apps: one app registration with many federated credentials for many pipelines hits the 20-credential limit and gives every pipeline the union of permissions.
  • Removing the secret before the last consumer is found: a quarterly batch job or a DR script fails weeks later. The sign-in log window must cover the workload's longest cycle.
  • Unmanaged issuers: trusting a self-managed cluster's issuer whose signing keys sit on a node anyone can reach turns the cluster admin into an Entra app owner.

Detection and measurement

  • Percentage of app registrations with at least one password credential (target: falling each quarter).
  • Share of service principal sign-ins by ClientCredentialType, tracked monthly.
  • Migrated apps with a secret still present (target zero after the observation window).
  • New federated identity credentials added outside the approved pipeline (target zero; each one investigated).
  • Federated credentials whose subject is a pull-request or branch pattern on apps with write permissions.

Framework mapping

FrameworkReferenceRelevance
NIST SP 800-53 Rev 5IA-5 Authenticator Management; IA-9 Service Identification and AuthenticationReplacing stored authenticators with platform-issued, short-lived tokens
NIST SP 800-53 Rev 5AC-6 Least PrivilegeNarrow subjects and per-workload apps
NIST CSF 2.0PR.AA-01; PR.AA-05Service credentials managed; access permissions defined and reviewed
MITRE ATT&CK v20T1552.001 Credentials In Files; T1098.001 Additional Cloud CredentialsSecrets in pipeline files and config removed; new credentials monitored

Practitioner checklist

  • Export every client secret and map it to its caller from AADServicePrincipalSignInLogs.
  • Remove unused secrets instead of migrating them.
  • Pick the narrowest subject the platform supports, preferably an environment or a single service account.
  • Add the federated credential alongside the secret, with the change number in its description.
  • Switch the workload to client assertions and add token retry logic.
  • Confirm FederatedCredentialId on all sign-ins for a full workload cycle before removing the secret.
  • Remove the secret from Entra and from every store that held a copy.
  • Block new secrets with an app management policy and alert on new credentials of any type.

Standards and references

Related NHI Mgmt Group resources: Azure Entra Client Secrets Security Guide · Workload Identity Federation Guide · Multi-Cloud Workload Identity Troubleshooting Guide · Azure Managed Identities Security Guide

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 28 October 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.