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.
Related command
az(global argument) /az account/azure.cli.core._profileIs 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 loginfor 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 toaz. Two terminals working on two clients race with each other.--subscriptionper 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 listWhere 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:
-p/--profile <name>, plus anAZURE_PROFILEenvironment variable.--profile>AZURE_PROFILE>AZURE_CONFIG_DIR> default.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-hybridmeans an API version profile, andazureProfile.jsonmeans the subscription cache. If that collision is a blocker,--contextwould avoid it and would align with Azure PowerShell'sSelect-AzContext/-AzContextand withkubectlcontexts.Describe alternatives you've considered
AZURE_CONFIG_DIR+ shell aliases — what I do today, and it works: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:
commandIndex.json, help indexes andconfigare 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.az profile list; the only inventory isls ~/.azure-*plus whatever the aliases happen to say.az— those all have to know to setAZURE_CONFIG_DIRthemselves.~/.azuresilently accumulates identities from anyaz loginthat 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:
--profile/AWS_PROFILEgcloud config configurations activate,--configuration--context,kubectl config use-contextSelect-AzContext, per-cmdlet-AzContextNotably 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_DIRalready provides the underlying isolation, this could plausibly be implemented largely as resolution and ergonomics on top of existing behaviour inazure/cli/core/_environment.pyand_profile.py, rather than as a new storage model.