Skip to content

[Profile] Add a native profile concept (az -p <profile> / AZURE_PROFILE) for working across multiple tenants #33833

Description

@NeilMazumdar

Related command

az (global argument) / az account / azure.cli.core._profile

Is your feature request related to a problem? Please describe.

I work across a number of separate Azure tenants, each with a distinct sign-in identity (different UPNs, different MFA, some guest invitations). The CLI stores all of its authentication state — MSAL token cache, azureProfile.json, the active subscription, config and installed extensions — in a single directory, ~/.azure.

That means the CLI only has one "current" identity/subscription at a time, and it is global mutable state:

  • az login for a second tenant does not isolate anything; it merges into the same profile and token cache.
  • az account set --subscription ... changes behaviour for every shell, script and tool on the machine that shells out to az. Two terminals working on two clients race with each other.
  • Passing --subscription per command mitigates the race but does not address identity isolation, and it is easy to forget on a destructive command.

For anyone consulting across multiple customers — or just separating prod from dev tenants — there is no supported way to say "run this command as that identity" without mutating shared state.

Describe the solution you'd like

A first-class named-profile concept, selectable per invocation:

az -p contoso group list          # or --profile
AZURE_PROFILE=contoso az group list

Where a profile is simply an isolated set of the state the CLI already keeps per config dir (token cache, subscription list, active subscription, config), stored under something like ~/.azure/profiles/<name>/.

Suggested shape:

  • Global argument -p/--profile <name>, plus an AZURE_PROFILE environment variable.
  • Resolution precedence: --profile > AZURE_PROFILE > AZURE_CONFIG_DIR > default.
  • Management commands: az profile list, az profile show, az profile create/delete/rename, so profiles are discoverable rather than filesystem trivia.
  • az login --profile <name> to bootstrap one without pre-creating directories.

Naming caveat: "profile" is already overloaded in the CLI — az cloud set --profile 2020-09-01-hybrid means an API version profile, and azureProfile.json means the subscription cache. If that collision is a blocker, --context would avoid it and would align with Azure PowerShell's Select-AzContext / -AzContext and with kubectl contexts.

Describe alternatives you've considered

AZURE_CONFIG_DIR + shell aliases — what I do today, and it works:

alias az-clienta='AZURE_CONFIG_DIR=~/.azure-clienta az'
alias az-clientb='AZURE_CONFIG_DIR=~/.azure-clientb az'

Each directory holds its own MSAL cache, so switching tenants is a different command rather than a re-login, and nothing leaks between shells. But as a substitute for a native feature it has real costs:

  • Extensions, commandIndex.json, help indexes and config are duplicated per directory. Installing or upgrading an extension has to be repeated N times, and it is easy to end up with drifted extension versions between tenants.
  • Profiles are not discoverable. There is no az profile list; the only inventory is ls ~/.azure-* plus whatever the aliases happen to say.
  • Aliases are shell-specific and invisible to scripts, Makefiles, CI, and any tool that shells out to az — those all have to know to set AZURE_CONFIG_DIR themselves.
  • Nothing surfaces which profile is active, so there is no reliable way to show it in a shell prompt or guard a destructive command.
  • The default ~/.azure silently accumulates identities from any az login that predates or bypasses the convention, at which point the isolation is only nominal and you have to audit it by hand (az account list --query "[].user.name" -o tsv | sort -u).

Multiple logins in one config dir + az account set — supported today, but shares one token cache and one global current subscription; that is the problem being described.

Service principals per tenant — does not help where interactive/MFA sign-in is required, and still lands in one shared cache.

A container or devcontainer per client — effective isolation but heavyweight for what is a config-directory concern.

Additional context

Prior art for exactly this pattern in comparable CLIs:

Tool Mechanism
AWS CLI --profile / AWS_PROFILE
gcloud named configurations: gcloud config configurations activate, --configuration
kubectl contexts: --context, kubectl config use-context
Azure PowerShell contexts: Select-AzContext, per-cmdlet -AzContext
azd environments

Notably Azure PowerShell already has the concept, so this would bring the CLI in line with the rest of the Azure toolchain rather than introducing a new idea.

Since AZURE_CONFIG_DIR already provides the underlying isolation, this could plausibly be implemented largely as resolution and ergonomics on top of existing behaviour in azure/cli/core/_environment.py and _profile.py, rather than as a new storage model.

Metadata

Metadata

Assignees

Labels

ARMaz resource/group/lock/tag/deployment/policy/managementapp/account management-groupAccountaz login/accountAuto-AssignAuto assign by botAzure CLI TeamThe command of the issue is owned by Azure CLI teamact-identity-squadcustomer-reportedIssues that are reported by GitHub users external to the Azure organization.feature-request

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions