I was recently preparing a talk on removing all secrets from your application using managed identities and workload identity federation. Whenever authentication and authorization is involved, I need to refresh my memory on how exactly it all works, and this time was no different. In this post, I'll try to explain the internal workings of workload identity federation.
What is workload identity federation?
Imagine we have a situation where our application needs to authenticate to a service managed by Entra Id with certain restrictions:
- No passwords are allowed for the application level
- We need to be able to run anywhere
Often with Azure, managed identities handle auth requirements between services, but they are not supported for non-Azure based callers. This is where workload identity federation comes in, allowing us to define a trust relationship between Entra ID and an external identity provider.
Microsoft has listed a bunch of different use cases where workload identity federation can be used. But mostly it boils down to service-to-service connectivity, like Github -> Azure, or AWS -> Azure and so on. Other identity service providers also support auth via workload identity federation, but this post focuses on Entra ID.
Pieces of the puzzle
Looking from a bird's eye view, we have the following requirements in making this work.
- Our workload, a custom application requiring access to Entra ID protected resources or services
- An external identity provider, generating tokens for our workload. This could be anything from Kubernetes service tokens to GitHub tokens for example.
- Publicly hosted OpenID Connect (OIDC) Discovery Documents, and a JSON Web Keyset (JWKS) document. These describe the keys and key types to be used to validate the external identity provider tokens.
- Entra ID app registration or user assigned managed identity, protecting the service we want to connect to. This is the application id our tokens will be created for. It also specifies the permissions we have, and contains the trust relationship (federated identity credential) setup.
- Target Service, something we want to connect to. For example, an Azure Key Vault.
Trust Relationship
For the trust relationship, we need to specify the following pieces in the federated identity credential:
- Issuer, this is the URL of the external identity provider. It is used to locate the OpenID Connect Discovery Document, and must match the external IdP token
issuer
claim exactly. - Subject Identifier, in the format specified by the external IdP. Can be anything, but Kubernetes tokens for example have the format
system:serviceaccount:namespacename:serviceaccountname
whereas Azure DevOps has a format ofsc://organization/project/serviceconnection
. Must match thesubject
claim of the external IdP token. - Audiences, describing what Entra should accept in the
aud
claim of the external IdP token. They recommend using the defaultapi://AzureADTokenExchange
value, but you should be able to specify anything (and multiple audiences too) as long as they match the value in the external IdP token.
Note that these are not really secrets, they merely specify that your app registration can provide Entra ID tokens "in exchange" to external identity provider tokens that contain those values. The values are case sensitive.
OpenID Connect Discovery & JWKS
Hopefully you won't need to handle these yourself, but if that's the case you can use the Azure AD Workload Identity CLI (azwi) to help setting these up.
The OpenID Connect Discovery standard can be found here. It's a bit confusing to read though. Below is a simple example I generated for my demos.

Now that we have a discovery document, you can use the azwi jwks
command documented here to generate the JWKS. The function of this file was to tell Entra ID the public keys it can use to validate the external IdP token.

Putting it all together
Microsoft has this clear chart for the flow our authentication goes through
- Our workload requests a token from the external IdP
- We get the token back. In the kubernetes context this is a service account token projected onto our pod
- Our workload sends the token to Entra ID while requesting an Entra ID token
- If the token claims (
issuer
,subject
,aud
) match what's specified in the Entra ID app registration, Entra uses the OpenID Discovery and JWKS documents to validate the token - All is well, our workload gets the Entra ID token with the permissions granted to the app registration
- Our workload uses the Entra ID token to access Entra ID protected resources