Azure / Azure/azure-cli

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

Open
#33,833 2 comments 0 reactions 1 assignee Claimed by @isra-fel View on GitHub
Account act-identity-squad ARM Auto-Assign Azure CLI Team customer-reported feature-request
Dominant language
Python
Stars
4.6k
Forks
3.5k
Avg merge
3d 2h
Merged PRs (30d)
60

Description

**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:

```bash
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//`.

Suggested shape:

- Global argument `-p/--profile `, 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 ` 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:

```zsh
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.

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.