Post

Azure Federated Credentials: Using Claims Matching Expressions with GitHub Actions OIDC

Using the new claims matching expression feature in Azure federated credentials to use wildcards with GitHub Actions OIDC subject claims

Azure Federated Credentials: Using Claims Matching Expressions with GitHub Actions OIDC

Overview

In a previous post, I covered how to use OIDC with reusable workflows in GitHub Actions to securely access cloud resources like Azure. One of the pain points I mentioned was that Azure required an exact match on the subject identifier when configuring federated credentials - meaning no wildcards. If you wanted to match multiple repositories, branches, or tags, you had to create a separate federated credential for each combination, and you’re limited to 20 per app registration.

AWS has supported wildcards for a while, but Azure was lagging behind. Not anymore! With the new Claims matching expression feature (currently in Preview), Azure now supports wildcard-like expressions in federated credentials.

Claims Matching Expressions

Instead of selecting “Explicit subject identifier” when creating a federated credential, you can now select “Claims matching expression (Preview)” and use the matches operator with * wildcards.

For example, instead of creating individual federated credentials for each repository, you can use an expression like:

1
claims['sub'] matches 'repo:my-org/*:ref:refs/heads/main'

This would match the sub claim for any repository in the my-org organization on the main branch.

Wildcard Patterns

You can use wildcards in different parts of the expression to match various patterns:

ExpressionMatches
claims['sub'] matches 'repo:my-org/*:*'Any repo in my-org, any ref
claims['sub'] matches 'repo:my-org/*:ref:refs/heads/main'Any repo in my-org, but only the main branch
claims['sub'] matches 'job_workflow_ref:my-org/reusable-workflows/.github/workflows/deploy.yml@refs/tags/v*'The specific reusable workflow, but any v tag (e.g., v1, v2, etc.)

That last example is particularly useful when combined with customized OIDC subject claims and reusable workflows. You can use a single federated credential to match multiple tags of a reusable workflow instead of having to update the credential each time you release a new version.

Using Repository Custom Properties

Expressions aren’t limited to the sub claim, either. GitHub Actions OIDC tokens now support repository custom properties as claims, prefixed with repo_property_. This lets you match on repository metadata without needing to list repos individually:

ExpressionMatches
claims['repo_property_team'] == 'platform'Any repo with the team custom property set to platform
claims['repo_property_data_classification'] == 'strict' && claims['sub'] matches 'repo:my-org/*:*'Any repo in my-org with the data_classification custom property set to strict

Configuring in Azure

To configure a claims matching expression in Azure:

  1. In Entra ID, navigate to the app registration and go to “Certificates & secrets” > “Federated credentials”
  2. Select “Other issuer” as the federated credential scenario
  3. For the issuer, use: https://token.actions.githubusercontent.com
  4. For the type, select “Claims matching expression (Preview)” instead of “Explicit subject identifier”
  5. For the value, enter your expression, such as:
    1
    
     claims['sub'] matches 'job_workflow_ref:my-org/reusable-workflows/.github/workflows/azure-oidc-sample.yml@refs/tags/v*'
    
  6. It should look something like this: Configuring a claims matching expression in Azure for a federated credential Configuring a claims matching expression in Azure for a federated credential Configuring a claims matching expression in Azure for a federated credential

The claims matching expression feature is currently in Preview. See the Microsoft docs for the latest information and supported syntax.

Use IDs Instead of Names for Extra Security

When using wildcards in claims matching expressions, consider using IDs instead of names for organizations and repositories. Org and repo names can be renamed - and if someone claims an abandoned name, they could impersonate the original OIDC subject. This is especially relevant when using broad wildcard patterns like repo:my-org/*:*.

GitHub’s OIDC token includes ID-based claims like repository_id, repository_owner_id, and others. You can customize the subject claim to include these ID-based claims instead of (or in addition to) name-based ones. For example, using @tspascoal’s gh-oidc-sub gh CLI extension:

1
gh oidc-sub set --repo my-org/my-repo --subs "repository_owner_id,repository_id"

This would produce a subject claim like:

1
"sub": "repository_owner_id:106885989:repository_id:561484078"

Then in Azure, you can use a claims matching expression with the IDs:

1
claims['sub'] matches 'repository_owner_id:106885989:*'

Since IDs are immutable and don’t change when an org or repo is renamed, this avoids the rename/name-squatting problem entirely.

Using ID-based claims like repository_owner_id and repository_id instead of name-based ones (e.g., repo:my-org/*:*) eliminates the risk of someone claiming an abandoned org/repo name and matching your federated credential.

Summary

I’ve been wanting wildcards in Azure federated credentials for a long time, so it’s nice to finally see this available (even if it’s still in Preview). Combined with the 20 federated credential limit per app registration, this makes managing OIDC at scale much more practical - especially if you’re using reusable workflows with customized subject claims. And if you’re going the wildcard route, definitely consider using ID-based claims (repository_owner_id, repository_id) instead of names to avoid any potential rename/graveyard attacks. ✨

This post is licensed under CC BY 4.0 by the author.