Subscription-Scoped Federated Credentials Widen UAMI Trust
A federated credential on a user-assigned managed identity issues tokens purely on issuer, subject and audience claims, then Azure RBAC assigns that identity Contributor at subscription scope. Any workload capable of matching the subject claim inherits control over every resource group underneath, and Conditional Access never sees the exchange.
Operational summary
At a glance
- Symptom
- A workflow or branch matching the federated credential's subject claim requests a token and inherits subscription-wide write access.
- Likely cause
- A federated credential on a user-assigned managed identity is paired with a subscription-scoped Contributor role assignment.
- Impact
- Any pipeline matching the subject claim gains Contributor rights over every resource group in the subscription, not just its intended target.
- Verification signal
- Re-run the detection test and a controlled negative-path test.
- Safe correction
- Scope role assignments to the specific resource group or resource, tighten subject claims to exact branch or environment names, and use custom roles over Contributor.
- Rollback or recovery
- Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.
The Trap
Federated credentials on a user-assigned managed identity (UAMI) are paired with a subscription-level role assignment instead of a resource group or resource-scoped one. The federated credential itself has no concept of authorisation boundaries — it only validates issuer, subject and audience claims from the external OIDC token before Entra ID mints an access token for the UAMI. The actual blast radius is entirely determined by whatever role assignment sits on that identity.
The Default State
Engineers wiring up GitHub Actions or GitLab CI to Azure via az identity federated-credential create typically follow the quickstart pattern: create one UAMI, attach a federated credential scoped to a repository or environment subject, then run az role assignment create --role Contributor --scope /subscriptions/<sub-id> because that’s the fastest path to a working pipeline. Terraform modules copied from example repositories frequently hardcode the subscription-level scope argument on azurerm_role_assignment rather than parameterising it per resource group. Nobody revisits the scope once the pipeline goes green.
The Blast Radius
The subject claim match is often looser than intended — wildcard branch patterns like repo:org/*:ref:refs/heads/* or environment-level subjects that match any deployment job mean any branch or fork with write access to workflow files can request a token for that UAMI. Because the role assignment is subscription-wide Contributor, a compromised workflow, a malicious pull request that triggers a workflow_run, or a misconfigured self-hosted runner gains write access to every resource group in the subscription: production databases, key vaults, storage accounts, and networking, not just the one microservice the pipeline was built to deploy. Azure AD Conditional Access does not apply to workload identity federation token issuance, so there is no MFA or location check standing between the matched claim and the token.
The Lead Mechanic Fix
Scope every role assignment on a federated UAMI to the specific resource group or resource: az role assignment create --assignee <uami-object-id> --role Contributor --scope /subscriptions/<sub-id>/resourceGroups/<rg-name>. Tighten the federated credential’s subject claim to an exact branch or environment name, never a wildcard covering all refs. Where the workload only needs to deploy specific resource types, replace Contributor with a custom role restricted to the required Microsoft.*/write actions. Audit existing assignments with az role assignment list --assignee <uami-object-id> --all and remove any entry whose scope is a subscription or management group.
Apply the safer control
Before you change production
Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.
Fix commands and configuration
az role assignment create --assignee <uami-object-id> --role Contributor --scope /subscriptions/<sub-id>/resourceGroups/<rg-name>Microsoft.*/writeaz role assignment list --assignee <uami-object-id> --allVerify, roll back or escalate
Verify
Re-run the detection test and a controlled negative-path test. Confirm the unsafe behaviour is blocked while approved traffic still succeeds.
Rollback
Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.
Escalate
Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.