Skip to main content
KBY Technologies Logo
cd ../config-traps
risk/register/wildcard-federated-credentials-widen-uami-blast-radius.html
Azure Workload Identity Federationcritical severityAzure

Wildcard Federated Credentials Widen UAMI Blast Radius

Overview

A federated credential subject that accepts any GitHub environment name, paired with a Contributor role assignment at subscription scope, lets a workflow meant for one resource group deploy, delete or read secrets across every resource group in the subscription. Azure AD's OIDC exchange never checks resource group boundaries, so RBAC scope is the only control that matters.

At a glance

Unsafe setting
User-assigned managed identity granted Contributor at subscription scope with a federated credential subject using an environment wildcard.
Failure trigger
A GitHub Actions workflow in any environment matching the wildcard subject requests an OIDC token and assumes the identity outside its intended resource group.
Blast radius
The compromised or misdirected workflow gains Contributor rights across every resource group in the subscription, not just its target.
Recommended control
Scope role assignments to exact resource group ARM IDs and pin federated credential subjects to exact repo, branch and environment strings.

Fix commands and configuration

az role assignment create --role Contributor --scope /subscriptions/{subId}/resourceGroups/{rgName} --assignee-object-id {principalId} --assignee-principal-type ServicePrincipal
az role assignment delete --assignee {principalId} --scope /subscriptions/{subId}
az identity federated-credential create --name gh-deploy-prod --identity-name uami-prod --resource-group rg-identity --issuer https://token.actions.githubusercontent.com --subject "repo:org/repo:environment:prod" --audiences api://AzureADTokenExchange

The Trap

Wildcard Federated Credential Subjects on Subscription-Scoped User-Assigned Managed Identities. A user-assigned managed identity (UAMI) is created for GitHub Actions or Azure DevOps deployment, and the federated credential subject claim is written with a wildcard segment — for example repo:org/repo:environment:* or repo:org/repo:ref:refs/heads/* — instead of an exact string. The same identity’s role assignment is then created at subscription or management group scope rather than against the single resource group it is meant to deploy into.

The Default State

The Azure Portal’s role assignment wizard opens with the subscription pre-selected in the scope picker; drilling down to a resource group is an extra step most engineers skip when time-pressured. Command-line users copy a working az role assignment create --role Contributor --scope /subscriptions/{subId} snippet from internal documentation and never narrow it. On the federation side, az identity federated-credential create accepts any string in --subject without validating it against real GitHub environments, so teams write one broad subject to cover multiple branches or environments rather than maintaining a federated credential per pipeline stage.

The Blast Radius

Azure AD’s OIDC token exchange checks issuer, audience and subject string match only — it has no concept of resource group boundaries. Once a workflow run produces a token whose subject satisfies the wildcard, it receives the identity’s access token with whatever RBAC scope that identity holds. If the identity is Contributor at subscription level, a workflow intended to deploy a single storage account can instead modify network security groups in the production networking resource group, read secrets from an unrelated Key Vault, or delete resources in a resource group it has never touched. A dependency-confusion compromise in a low-trust repository environment therefore escalates into subscription-wide write access, and Defender for Cloud’s anomalous-role-usage alerts fire only after the damage, not before it.

The Lead Mechanic Fix

Scope every managed identity role assignment to the exact resource group ARM ID: az role assignment create --role Contributor --scope /subscriptions/{subId}/resourceGroups/{rgName} --assignee-object-id {principalId} --assignee-principal-type ServicePrincipal, then remove any broader grant with az role assignment delete --assignee {principalId} --scope /subscriptions/{subId}. Pin federated credential subjects to exact repository, branch and environment strings — one credential per pipeline stage, e.g. az identity federated-credential create --name gh-deploy-prod --identity-name uami-prod --resource-group rg-identity --issuer https://token.actions.githubusercontent.com --subject "repo:org/repo:environment:prod" --audiences api://AzureADTokenExchange. Enforce the scope rule with an Azure Policy definition that denies Microsoft.Authorization/roleAssignments writes above resource group scope for principals tagged as workload identities, and audit quarterly with az role assignment list --all --query "[?principalType=='ServicePrincipal']".