Wildcard Federated Credentials Widen UAMI Blast Radius
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 ServicePrincipalaz 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://AzureADTokenExchangeThe 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']".