Audit extension tenant selection for guest and cross-tenant scenarios
- Dominant language
- Go
- Stars
- 569
- Forks
- 364
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 136
Description
## Background
PR #7549 fixed core azd tenant selection by distinguishing:
- the **access tenant** (`UserAccessTenantId` / proto `UserTenantId`) used to acquire credentials for a signed-in user
- the **subscription/resource tenant** (`Subscription.TenantId`) that owns the subscription and its RBAC state
That PR intentionally stayed core-only. A follow-up extension audit found a separate cleanup worth tracking.
This is broader than #7077, which fixed one extension path with the same access-tenant issue.
The extension-facing APIs already expose both values on `azdext.Subscription`, so this should not require new gRPC surface area.
## Follow-up work
1. **Fix generated extension templates**
The generated Go / JS / .NET prompt samples currently use `PromptSubscription().Subscription.TenantId` when creating `AzureDeveloperCliCredential`.
These are access-tenant credential scenarios and should use `UserTenantId` instead.
Files:
- `extensions/microsoft.azd.extensions/internal/resources/languages/go/internal/cmd/prompt.go.tmpl`
- `extensions/microsoft.azd.extensions/internal/resources/languages/javascript/commands/prompt.js`
- `extensions/microsoft.azd.extensions/internal/resources/languages/dotnet/commands/PromptCommand.cs`
2. **Fix resource-tenant extension flows**
At least one extension path looks like the same class of bug that #7549 fixed in core:
- `extensions/azure.ai.agents/internal/project/agent_identity_rbac.go`
This code currently uses `Account().LookupTenant(...)` and then performs Graph service principal discovery plus RBAC role assignment. Since `LookupTenant()` returns the access tenant, this path should be reviewed to confirm whether it must instead use the subscription/resource tenant.
3. **Audit remaining explicit-subscription fallback paths**
Several extensions call `LookupTenant(...)` or persist `AZURE_TENANT_ID` during explicit-subscription flows. Many of these may be correct access-tenant scenarios, but they should be audited and documented so we are consistent about when to use:
- `UserTenantId` / `LookupTenant()` for user credential acquisition
- `Subscription.TenantId` for resource-tenant principal / RBAC operations
Candidate files:
- `extensions/azure.appservice/internal/cmd/swap.go`
- `extensions/azure.ai.models/internal/cmd/init.go`
- `extensions/azure.ai.models/internal/cmd/custom.go`
- `extensions/azure.ai.agents/internal/cmd/init_foundry_resources_helpers.go`
- `extensions/azure.ai.finetune/internal/cmd/init.go`
- `extensions/azure.ai.agents/internal/project/service_target_agent.go`
## Acceptance criteria
- Generated extension templates use `UserTenantId` for `PromptSubscription`-based credential creation
- Resource-tenant principal / RBAC flows in extensions use the subscription tenant where required
- We add regression coverage for at least one guest/cross-tenant case for each fixed pattern
- We document any remaining intentional `LookupTenant()` usages as access-tenant cases
## Related
- #7173
- #7077
- #7549
Contributor guide
Assessment
This issue has not been assessed yet.