Federated Credentials Limitations and Solutions in Azure
Background
Federated identity credentials in workload identity federation require an exact match between the defined subject, issuer, and audience in the credential and those in the token sent to Microsoft Entra. Due to the current limit of 20 federated identity credentials per application or user-assigned managed identity, scaling constraints can be reached quickly.
Solution
Flexible federated identity credentials enhance the existing federated identity credential model by supporting a restricted expression language for matching incoming subject claims. They also extend authorization beyond the subject, issuer, and audience claims by allowing certain approved custom claims within federated identity credentials.
These credentials help streamline management when authenticating external workloads with Microsoft Entra and mitigate scalability limitations in workload identity federation.
How does it work?
Flexible federated identity credentials maintain the core functionality of federated identity credentials by defining trust relationships that specify which tokens from an external IdP should be trusted by your application. However, they enhance this model by allowing multiple scenarios that previously required separate federated identity credentials to be managed under a single flexible federated identity credential.
Some key use cases include:
-
GitHub repositories with multiple workflows across different branches – Previously, each branch required a separate federated identity credential for workflows running across them. With flexible federated identity credentials, this can be managed under a single credential.
-
Reusable GitHub Actions workflows – By leveraging wildcards, flexible federated identity credentials can match against GitHub’s job_workflow_ref claim, enabling broader authorization without multiple credentials.
Language structure
A flexible federated identity credential expression consists of three components: the claim lookup, the operator, and the comparand. The table below provides a detailed breakdown of each component.
Name | Description | Example |
---|---|---|
Claim lookup | The claim lookup must follow the pattern of claims[‘ |
claims[‘sub’] |
Operator | The operator portion must be just the operator name, separated from the claim lookup and comparand by a single space | matches |
Comparand | The comparand contains what you intend to compare the claim specified in the lookup against - it must be contained within single quotes | repo:furmidgeuk/testrepo:ref:refs/heads/*’ |
When combined, a flexible federated identity credential expression is represented as a JSON object, as shown in the following example:
claims['sub'] matches 'repo:furmidgeuk/testrepo:ref:refs/heads/*'.
Set up federated identity credentials through Microsoft Graph
To support flexible federated identity credentials, the federatedIdentityCredentials
resource has been extended with a new claimsMatchingExpression
property. Additionally, the subject
property is now nullable. These two properties are mutually exclusive, meaning you cannot define both within the same federated identity credential.
Key Properties
audiences
: Specifies the audience that must appear in the external token. This field is required and should be set toapi://AzureADTokenExchange
for Microsoft Entra ID. It defines what the Microsoft identity platform should accept in theaud
claim of the incoming token. Since this value represents Microsoft Entra ID in your external identity provider, you may need to create a new application registration in your IdP to serve as the audience for this token.issuer
: The URL of the external identity provider. It must match the iss (issuer) claim of the external token being exchanged.subject
: Identifies the external software workload within the identity provider. Since each IdP formats this differently (e.g., GUID, colon-delimited identifier, or arbitrary string), the value must match the sub claim in the token presented to Microsoft Entra ID. Ifsubject
is defined,claimsMatchingExpression
must be set to null.name
: A unique identifier for the credential. This property serves as an alternate key and can be used to reference the federated identity credential in GET and UPSERT operations.claimsMatchingExpression
: A new complex type that contains two properties: -value
: Defines the expression for claim matching. -languageVersion
: Specifies the version of the flexible federated identity credential expression language (FFL) being used. This should always be set to 1. IfclaimsMatchingExpression
is defined, subject must be set to null.
Flexible federated identity credential expression language functionality
Flexible federated identity credentials currently support a limited set of operators across the enabled issuers. In the flexible federated identity credential expression language, single quotes are treated as escape characters.
Operator | Description | Example |
---|---|---|
matches | Enables the use of single-character (denoted by ?) and multi-character (denoted by *) wildcard matching for the specified claim | • “claims[‘sub’] matches ‘repo:furmidgeuk/testrepo:ref:refs/heads/*’” • “claims[‘sub’] matches ‘repo:furmidgeuk/*:ref:refs/heads/????’” |
eq | Used for explicitly matching against a specified claim | • “claims[‘sub’] eq ‘repo:furmidgeuk/testrepo:ref:refs/heads/main’” |
and | Boolean operator for combining expressions against multiple claims | • “claims[‘sub’] eq ‘repo:furmidgeuk/testrepo:ref:refs/heads/main’ and claims[‘job_workflow_ref’] matches ‘foo-org/bar-repo /.github/workflows/*@refs/heads/main’” |
Issuer URLs, supported claims, and operators
Supported issuer URLs: https://token.actions.githubusercontent.com Supported claims and operators per claim:
- Claim
sub
supports operatorseq
andmatches
- Claim
job_workflow_ref
supports operatorseq
andmatches
Solution
Since GitHub Environments modify the sub
claim format, we had to create three separate federated identity credentials:
Federated Credential 1 (Branch-Based Workflows)
claims['sub'] matches 'repo:furmidgeuk/*:ref:*'
- Allows authentication for any repository in the organization for branch-based workflows.
Federated Credential 2 (Environment-Based Workflows)
claims['sub'] matches 'repo:furmidgeuk/*:environment:*'
- Allows authentication for GitHub Environments.
Federated Credential 3 (Pull Request Workflows)
claims['sub'] matches 'repo:furmidgeuk/*:pull_request'
- Allows authentication for any repository in the organisation for pull requests.
Further Refinements
To increase granularity, we could also:
- Restrict to the main branch only:
claims['sub'] matches 'repo:furmidgeuk/*:ref:refs/heads/main'
- Specify individual environments:
claims['sub'] matches 'repo:furmidgeuk/*:environment:dev' claims['sub'] matches 'repo:furmidgeuk/*:environment:tst' claims['sub'] matches 'repo:furmidgeuk/*:environment:val' claims['sub'] matches 'repo:furmidgeuk/*:environment:prd'
- Attempting to combine environments into a single claim failed:
claims['sub'] matches 'repo:furmidgeuk/*:environment:dev' and claims['sub'] matches 'repo:furmidgeuk/*:environment:dev'
- The
and
operator does not work with multiplesub
claims.
- The
Testing Results
The solution was tested successfully with the following claims:
claims['sub'] matches 'repo:furmidgeuk/*:ref:*'
claims['sub'] matches 'repo:furmidgeuk/*:environment:*'
claims['sub'] matches 'repo:furmidgeuk/*:pull_request'
- Authentication worked across all repositories and branches in combination with all environments.
We also tested this solution successfully when creating the following claims:-
claims['sub'] matches 'repo:testrepo/*:ref:*'
claims['sub'] matches 'repo:testrepo/*:pull_request'
claims['sub'] matches 'repo:testrepo/*:environment:prd'
Again the authentication worked as desired. Here is a screenshot from one of the claims:-
Here is the output from the github action that used these federated credentials:-
Running Azure CLI Login.
/usr/bin/az cloud set -n azurecloud
Done setting cloud: "azurecloud"
Federated token details:
issuer - https://token.actions.githubusercontent.com
subject claim - repo:testrepo/github:environment:prd
Attempting Azure CLI login by using OIDC...
Subscription is set successfully.
Azure CLI login succeeds by using OIDC.
Security Considerations
The Claims Matching Expression
we have tested currently allows any repository within the testrepo
organization to authenticate and deploy to Azure. To prevent unauthorized deployments, we must ensure that only trusted repositories can be created within the organization.
Steps to Restrict Repository Creation:
- Disable Repository Creation for Non-Admins
- Navigate to
testrepo → Settings → Member Privileges
. -
Uncheck the following options under
Repository creation
:❌ Private repositories
❌ Internal repositories
- This prevents regular members from creating repositories that could inherit federated credentials.
- Navigate to
- Restrict Repository Creation to Admins and GitHub App
- Only
Admin members
and theGitHub App
should have the ability to create repositories. - This ensures that all repositories requiring federated credentials are explicitly reviewed and approved.
- Only
By enforcing these restrictions, we mitigate the risk of unauthorized repository creation and ensure that only trusted repositories can leverage federated authentication for Azure deployments.
Conclusion and Considerations
This approach provides a scalable and manageable solution to Azure’s federated credential limit. While it is currently well within the 20
federated credential limit, continuous monitoring and refinements may be required as the number of repositories and environments grow.
Considerations:
- Further granular control by refining claims.
- Evaluate security implications of wildcard-based authentication.
- If possible, automate credential provisioning to streamline future updates.
This approach balances security, scalability, and manageability while complying with Azure’s limitations on federated credentials.
Workflow used for testing
name: Test Federated Credentials
on:
pull_request:
branches:
- main
workflow_dispatch:
inputs:
environment:
description: "Deployment environment (dev, tst, prd)"
required: true
type: choice
options:
- dev
- tst
- prd
permissions:
id-token: write
contents: read
jobs:
test-fed-credentials:
runs-on: ubuntu-latest
environment: $
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Authenticate to Azure for $
uses: azure/login@v2
with:
client-id: $
tenant-id: $
subscription-id: $