Federated Credentials Limitations and Solutions in Azure

6 minute read

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 to api://AzureADTokenExchange for Microsoft Entra ID. It defines what the Microsoft identity platform should accept in the aud 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. If subject 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. If claimsMatchingExpression 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 operators eq and matches
  • Claim job_workflow_ref supports operators eq and matches

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:

  1. Restrict to the main branch only:
    claims['sub'] matches 'repo:furmidgeuk/*:ref:refs/heads/main'
    
  2. 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'
    
  3. 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 multiple sub claims.

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:-

federated credentials

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.
  • Restrict Repository Creation to Admins and GitHub App
    • Only Admin members and the GitHub App should have the ability to create repositories.
    • This ensures that all repositories requiring federated credentials are explicitly reviewed and approved.

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:

  1. Further granular control by refining claims.
  2. Evaluate security implications of wildcard-based authentication.
  3. 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: $

Tags:

Categories:

Updated: