Azure / Azure/azure-dev

Audit extension tenant selection for guest and cross-tenant scenarios

Open
#7,563 0 comments 0 reactions 0 assignees View on GitHub
area/auth area/extensions area/ux enhancement
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.