Azure Error Guide: 'LinkedAuthorizationFailed' — Grant Cross-Resource Access
Fix Azure 'LinkedAuthorizationFailed' during ARM/Bicep deployments: understand the linked-scope permission check, grant the missing role on the referenced resource, and verify with az role assignment.
- #azure
- #cloud
- #troubleshooting
- #errors
Stuck on this Azure with AI error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Overview
Azure Resource Manager returns LinkedAuthorizationFailed when a deployment succeeds in authorizing the primary resource you are creating but fails a second, linked authorization check on a resource in another scope that the primary resource references. The literal message looks like this:
Code: LinkedAuthorizationFailed
Message: The client 'deployer@contoso.com' with object id 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
has permission to perform action 'Microsoft.Network/loadBalancers/write' on scope
'/subscriptions/1111.../resourceGroups/app-rg/providers/Microsoft.Network/loadBalancers/app-lb';
however, it does not have permission to perform action(s)
'Microsoft.Network/virtualNetworks/subnets/join/action' on the linked scope(s)
'/subscriptions/1111.../resourceGroups/network-rg/providers/Microsoft.Network/virtualNetworks/hub-vnet/subnets/app-subnet'
or the linked scope(s) are invalid.
The tell is the phrase “on the linked scope(s)” — this is not the same as AuthorizationFailed, which fires when you cannot act on the primary resource itself. Here you can create the resource, but you lack a permission on something it depends on.
Symptoms
- A deployment (portal,
az deployment, Bicep, Terraform) fails withLinkedAuthorizationFailedeven though you have Contributor on the target resource group. - The message names one action you have on the primary scope and a different action you lack on a linked scope — often in a different resource group or subscription.
- Common linked actions:
Microsoft.Network/virtualNetworks/subnets/join/action(NIC/VM/App Gateway joining a subnet in a shared network RG),Microsoft.Network/publicIPAddresses/join/action,Microsoft.ManagedIdentity/userAssignedIdentities/assign/action(assigning a user-assigned identity to a VM/AKS), orMicrosoft.KeyVault/vaults/deploy/action. - Service principals or managed identities running CI/CD pipelines hit it while humans with broader roles do not.
Common Root Causes
- Hub-spoke / shared VNet: the network lives in a central
network-rg(or a platform subscription) and the deployer has Contributor only on the workload RG, so it cannotjointhe subnet. - Cross-subscription reference: the linked resource (VNet, Public IP, Key Vault, managed identity) is in a different subscription where the identity has no role assignment.
- User-assigned managed identity: assigning a UAMI to a VM/VMSS/AKS requires
Microsoft.ManagedIdentity/userAssignedIdentities/assign/actionon the identity, which Contributor on the workload RG does not include if the identity lives elsewhere. - Custom role gaps: a least-privilege custom role that grants
writeon the primary type but omits the.../join/actionor.../assign/actionNotActions/Actions needed for the link. - Role assignment not yet propagated: a freshly granted role can take a few minutes; a pipeline that assigns then immediately deploys can race it.
Diagnostic Workflow
First, read the error carefully — it already names the exact missing action and the linked scope. Capture the full deployment error:
az deployment group show \
--resource-group app-rg \
--name <deployment-name> \
--query "properties.error" -o json
Identify who the deployer is. For a pipeline, get the service principal’s object id:
az account show --query user -o json
az ad sp show --id <appId> --query id -o tsv # object id of the SP
Check what roles that identity actually has on the linked scope (not the primary RG):
# The linked scope from the error, e.g. the network resource group
az role assignment list \
--assignee <objectId> \
--scope /subscriptions/1111.../resourceGroups/network-rg \
-o table
Confirm which role definitions contain the missing action, so you grant the least-privileged one:
az role definition list \
--query "[?contains(to_string(permissions[].actions[]), 'virtualNetworks/subnets/join')].roleName" \
-o tsv
For a user-assigned identity link, inspect the identity’s scope and existing assignments:
az identity show --name <uami> --resource-group identity-rg --query id -o tsv
az role assignment list --scope <uami-resource-id> --assignee <objectId> -o table
Example Root Cause Analysis
A pipeline deploys an Application Gateway into app-rg. Its service principal has Contributor on app-rg. The gateway references a subnet in hub-vnet, which lives in network-rg (a shared connectivity resource group owned by the platform team).
The deployment authorizes Microsoft.Network/applicationGateways/write on app-rg — the SP has that. ARM then performs the linked check Microsoft.Network/virtualNetworks/subnets/join/action on network-rg/hub-vnet/app-subnet. The SP has no role assignment on network-rg, so the second check fails and ARM returns LinkedAuthorizationFailed.
The fix is not to make the SP an Owner. The Network Contributor built-in role includes the subnets/join/action, so grant it scoped as narrowly as possible — ideally to the specific VNet or subnet, not the whole subscription:
az role assignment create \
--assignee <objectId> \
--role "Network Contributor" \
--scope /subscriptions/1111.../resourceGroups/network-rg/providers/Microsoft.Network/virtualNetworks/hub-vnet
After the assignment propagates (allow a minute or two), re-run the deployment. The linked check now passes.
Prevention Best Practices
- Grant join/assign rights at the linked scope up front. When a workload uses a shared VNet, subnet, public IP, Key Vault, or user-assigned identity, give the deploying identity
Network Contributor(or a custom role with just the neededjoin/assignaction) scoped to that specific resource — not broad Owner. - Scope to the resource, not the subscription. The action is
subnets/join/actionon one VNet; assign at the VNet or subnet scope to keep least privilege. - Model cross-RG references in your IaC reviews. Any Bicep/Terraform that references a resource id in another resource group or subscription is a candidate for a linked-authorization failure — check permissions before the run.
- Handle propagation delay in pipelines. If a pipeline creates a role assignment and then deploys, add a short wait or a retry so the assignment is live before the linked check runs.
- Prefer built-in roles that already contain the action.
Network Contributor,Managed Identity Operator(forassign/action), and similar roles are safer than hand-rolled custom roles that easily miss a single.../action.
Quick Command Reference
# See the exact missing action + linked scope
az deployment group show -g app-rg -n <name> --query "properties.error" -o json
# Who is the deployer (SP object id)
az ad sp show --id <appId> --query id -o tsv
# What roles does it have on the LINKED scope
az role assignment list --assignee <objectId> --scope <linked-scope-id> -o table
# Which roles contain the needed action
az role definition list --query "[?contains(to_string(permissions[].actions[]),'subnets/join')].roleName" -o tsv
# Grant least-privilege role at the specific linked resource
az role assignment create --assignee <objectId> --role "Network Contributor" \
--scope <linked-vnet-or-subnet-id>
Conclusion
LinkedAuthorizationFailed is Azure being precise: you have permission on the resource you are creating, but not on a resource it depends on in another scope. The error message names the exact action and the exact linked resource — read it, confirm the deployer’s role assignments on that linked scope, and grant the narrowest built-in role (usually Network Contributor for subnet joins or Managed Identity Operator for identity assignment) at the specific resource. In shared hub-spoke and platform-subscription designs this is a routine onboarding step, so bake the linked-scope grant into your landing-zone process and your pipelines stop hitting it.
Fixed it? Get 500 Azure with AI & DevOps AI prompts — free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.
Did this fix your issue?
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.