Skip to content

[Feature Request] Global --read-only Mode for Azure CLI #32974

Open

Description

Preconditions

  • No need to upgrade Python SDK or the Python SDK is ready.

Related command

No response

Resource Provider

N/A

Description of Feature or Work Requested

I would like to request the implementation of a global read-only ("sandbox") mode for the Azure CLI, similar to the behavior of the Azure MCP server.

When enabled, this mode should restrict the CLI to only executing list, show, and get commands, effectively blocking any commands that would create, update, or delete resources.

Motivation

With the rise of unsupervised coding agents, Copilot CLI, and MCP-based integrations, there is a growing need for a "safety rail."

Safety: Prevent agents from accidentally modifying or deleting production infrastructure during diagnostic tasks.

Trust: Allow users to grant CLI access to AI tools with the confidence that no state-changing operations will be performed.

Efficiency: Avoid the complexity of creating specific "Reader" RBAC roles for every temporary session or agent environment. Not always users have the needed right on Entra ID.

If a user attempts a command like az group delete, the CLI should intercept the call and return an error:
Error: Azure CLI is in read-only mode. Command execution blocked.

Minimum API Version Required

N/A

Swagger PR link / SDK link

N/A

Request Example

No response

Target Date

2026-12-31

PM Contact

N/A

Engineer Contact

N/A

Additional context

No response

Activity

  1. yonzhan commented on Mar 16, 2026

    @yonzhan
    Collaborator

    Thank you for opening this issue, we will look into it.

  2. added
    customer-reportedIssues that are reported by GitHub users external to the Azure organization.
    ARMaz resource/group/lock/tag/deployment/policy/managementapp/account management-group
    on Mar 16, 2026
  3. added
    Azure CLI TeamThe command of the issue is owned by Azure CLI team
    questionThe issue doesn't require a change to the product in order to be resolved. Most issues start as that
    on Mar 16, 2026
  4. github-actions commented on Mar 16, 2026

    @github-actions

    This issue is related to security. Please pay attention.

    Powered by issue-sentinel

  5. removed
    questionThe issue doesn't require a change to the product in order to be resolved. Most issues start as that
    on Mar 16, 2026
  6. added this to the Backlog milestone on Mar 16, 2026
  7. 5 remaining items

  8. microsoft-github-policy-service commented on Sep 17, 2026

    @microsoft-github-policy-service
    Contributor

    🔔 Routing this issue to @Azure/act-identity-squad.

  9. x-engineering-agent commented on Sep 20, 2026

    @x-engineering-agent
    Contributor

    Hi Danilo Spinelli (@gunzip), a quick follow-up on the information requested earlier. Could you share the outstanding details when you have a chance? Please redact any credentials or other sensitive values.

    I'll pick this up automatically once you reply.

  10. gunzip commented on Sep 21, 2026

    @gunzip
    Author

    Hi @x-enginerring-agent, thanks for the follow-up. This is an enhancement request (not a defect), anyway, here are the requested details.

    Version/platform/extensions

    • azure-cli 2.87.0 (core 2.87.0), macOS 26.5.2 (build 25F84), arm64
    • No read-only enforcement exists today, so there is no version to reproduce against

    Proposed usage

    • Persistent (for agents/CI): az config set core.read_only=true or AZURE_CLI_READ_ONLY=true
    • Per-invocation: az --read-only <command>
    • The flag can only enable the mode, never disable it (prevents an agent from lifting the rail)

    Observed behavior
    N/A — enhancement only. With the mode off, az group delete -n <rg> runs after confirmation.

    Safe acceptance cases (disposable RG rg-ro-test created once with the mode off)

    Command Expected
    az group list / az group show -n rg-ro-test allowed
    az vm list -g rg-ro-test / az account show allowed
    az rest --method GET --url ... allowed
    az group create ... / az group delete ... blocked
    az vm create ... / az deployment group create ... blocked
    az keyvault secret set ... / az role assignment create ... blocked
    az rest --method DELETE --url ... blocked
    extension write commands (e.g. az aks nodepool add ...) blocked

    Expected error: Error: Azure CLI is in read-only mode. Command execution blocked.

  11. x-engineering-agent commented on Sep 21, 2026

    @x-engineering-agent
    Contributor

    X Engineering Agent Bug analysis: Root cause analysis

    Enhancement analysis: global read-only mode

    The sanitized author reply supplies sufficient requirements; no further reproduction request is needed for this enhancement. Reported context: Azure CLI/core 2.87.0, macOS 26.5.2 arm64. The current write-enabled behavior is that az group delete -n <rg> proceeds after confirmation. Requested behavior is opt-in read-only enforcement, with Error: Azure CLI is in read-only mode. Command execution blocked. for denied commands. This is not a claimed regression or a locally reproduced failure.

    Ownership and source evidence (read-only inspection of 37c9b6b4ee3363e6333450e85c5ee25ee83ffe1a):

    • AzCli initialization registers shared CLI features. Command invocation loads/resolves/parses commands; subsequent dispatch confirms and validates before executing jobs. These inspected stages have no read-only gate. Enforcing only inside a handler would be too late.
    • Extension loading merges extension commands into the same command table, including overrides. The shared dispatcher, not a single service module, must enforce the policy.
    • The REST entry point delegates to send_raw_request. REST arguments default to GET and also expose mutating methods; command-name filtering alone cannot classify az rest.

    Repository inference resolves the verified REST source to the built-in util module in Azure/azure-cli. The primary implementation component is Core because the requirement is global. Extension examples are acceptance coverage, not grounds for an azure-cli-extensions tracker.

    Proposed implementation contract

    1. Default off; support core.read_only=true, AZURE_CLI_READ_ONLY=true, and the leading form az --read-only <command>. Resolve enablement before command discovery/dispatch as necessary. Any enabled source keeps the invocation read-only: absence or a false value elsewhere must not lower it, and there must be no disabling counterpart to the flag. Preserve normal behavior when off; document boolean parsing and configuration lifecycle.
    2. Gate resolved operations before confirmation, command/argument validators, handlers, or other command-side effects. Cover built-ins, generated-command dispatch, extensions, aliases/overrides, and serial/concurrent ID expansion. Review earlier parser/loading hooks rather than claiming a late handler filter is comprehensive isolation.
    3. Allow the reported read cases: az group list, az group show -n rg-ro-test, az vm list -g rg-ro-test, and az account show. Use conservative, explicit read-operation classification; do not treat an arbitrary name containing get, list, or show as proof of safety. Deny unclassified operations and mutation verbs beyond just create/update/delete, including set/add. For REST, explicitly classify the effective method (including case normalization and default GET); allow GET and block DELETE/PUT/POST/PATCH. Do not infer that every POST or every extension read-looking command is safe.
    4. Deny the author's group create/delete, VM create, deployment group create, key vault secret set, role assignment create, and extension-write cases with the requested error and a nonzero exit. --yes, --no-wait, or changes through the CLI that lower an active read-only setting must not bypass enforcement.
    5. Describe this accurately as a cooperative client-side safety rail, not authorization or a tamper-proof sandbox. A same-user agent can change its environment/configuration or use other clients; extensions load executable Python. Do not promise protection against these capabilities or replace server-enforced least-privilege RBAC.

    Validation for the implementation worker: add offline mocked coverage in the existing core/parser/command suites for all three opt-in paths, enablement precedence, leading/global flag parsing, allowed reads, each denied family, REST default/case variants, extension/override behavior, and unchanged mode-off behavior. Assert denied commands never reach confirmation, validators, handlers, or request transmission. Do not execute the reporter's resource-changing examples against Azure. This triage ran no local tests or issue commands.

    Generation classification: the proposed enforcement belongs in handwritten CLI core (and a handwritten REST adapter only if needed), not a fabricated command_modules/core directory. Do not edit generated aaz/<profile>/ files. The following repository-owned Codegen protocol applies if implementation discovers a necessary generated-command change.

    PR title & description format (required)

    This repo enforces a PR format (guide). Please author the PR exactly as follows or CI's Check the Format of Pull Request Title and Content will fail.

    Use this EXACT PR title (copy verbatim, do not reword):

    [Core] Fix #32974: `az group delete`: Add opt-in global read-only command enforcement
    

    Keep the backticks around the command and the Fix #32974: prefix. You may only adjust the wording after the command (the final summary) if the fix changes; the [Core] prefix, issue link, and backticked command must stay.

    Description — follow the PR template and fill in:

    • Link the issue — start the Description with a closing keyword so the PR auto-links and closes it: Fixes Azure/azure-cli#32974.
    • Related command — the az ... command this affects.
    • Description (mandatory) — why the bug happens, what you changed, and the resulting behavior.
    • Testing Guide — example command(s) showing the fix works.
    • History Notes — leave the title to drive the history note, or add extra lines in the same format (component in brackets + the command in backticks), e.g. [Core] `az <command>`: <note>.
    • Keep the template checklist and tick the items you've satisfied.
    Mandatory Codegen execution protocol

    Before editing implementation files, determine whether the affected core command is AAZ-generated. Files under aaz/<profile>/ are generated output and must never be patched directly, including by an AI agent. Check out Azure/aaz beside Azure/azure-rest-api-specs, Azure/aaz-dev-tools, and the downstream repository. API-schema defects start in the specification; command naming, grouping, arguments, API-version selection, help, and examples belong in the durable Azure/aaz command model; non-modelable client behavior belongs in a handwritten subclass or wrapper in custom.py, registered from commands.py. X Engineering Agent creates and promotes the corresponding durable Azure/aaz source pull request before it promotes downstream generated output.

    Follow the Azure CLI repository's Codegen workflow and the aaz-dev setup documentation. Set up the checked-out repositories with azdev setup. Use generate only when importing or redesigning command models from Swagger/TypeSpec. For an existing module whose durable Azure/aaz model has been updated, render that model with regenerate:

    aaz-dev cli regenerate --name core --cli-path <azure-cli>
    
    # New/imported command model only:
    aaz-dev cli generate --spec <specification-name> --module core

    You MUST actually run the generator; do not merely describe it or imitate its output. If the AAZ/specification checkout, local source change, credentials, or generator is unavailable, stop and report the blocker instead of editing generated files. Inspect _aaz_info provenance and the complete regenerated diff, then run focused azdev style, azdev linter, and azdev test validation. For an extension, also update its version and HISTORY.rst, preserve azext_metadata.json compatibility, and let release automation update src/index.json.

    X Engineering Agent · Fixer · react 👍 / 👎 to train the agent

  12. x-engineering-agent commented on Sep 21, 2026

    @x-engineering-agent
    Contributor

    Thanks Danilo Spinelli (@gunzip) for the version, proposed switches, and acceptance cases. Understood: this is an enhancement request, not a defect in an existing read-only mode. There is no need to provide another failing-command reproduction.

    Before this can become a bounded implementation proposal for the owning maintainers, please clarify these remaining policy decisions:

    • Guardrail versus security boundary: Is an opt-in guardrail against accidental writes acceptable? An agent that can change its environment/configuration or invoke another client can bypass a CLI-only setting; an enable-only flag cannot provide tamper-resistant authorization. If preventing that bypass is required, please describe which externally enforced restriction is available. Azure RBAC/service permissions remain the authorization boundary.
    • Unclassified and local operations: With the mode enabled, should commands without explicitly reviewed read-only classification be blocked, including extension commands? Please specify the expected policy for local-state operations such as login, configuration changes, and extension installation, and for service read operations implemented with HTTP POST. Command names or HTTP verbs alone do not settle all these cases.

    For the remaining cases, a small operation | allowed or blocked | reason table is sufficient; the existing list/show/create/delete examples do not need to be repeated. The owning maintainers will need to agree on this cross-cutting behavior before implementation; I am not starting an automated bug-fix PR for the enhancement.

    I'll pick this up automatically once you reply.

  13. microsoft-github-policy-service commented on Sep 21, 2026

    @microsoft-github-policy-service
    Contributor

    🔔 Routing this issue to @Azure/act-identity-squad.

  14. x-engineering-agent commented on Sep 24, 2026

    @x-engineering-agent
    Contributor

    Hi, a friendly reminder about the outstanding checklist above. When you have a chance, could you share the missing evidence already requested? We'll pick this up automatically once you reply.

  15. mahauber commented on Sep 28, 2026

    @mahauber

    Human pls

  16. isra-fel commented on Oct 1, 2026

    @isra-fel
    Member

    Related topic: Microsoft offers Conditional Access for agents that controls how agents access resources protected by Microsoft Entra ID.

    https://learn.microsoft.com/en-us/entra/identity/conditional-access/agent-id

  17. x-engineering-agent commented on Oct 19, 2026

    @x-engineering-agent
    Contributor

    X Engineering Agent Issue triage: Triage finding

    This is a feature request, not a regression: the reporter has already specified proposed switches and acceptance cases. The CLI registers global arguments in core, loads core and extension commands into one command table, and az rest passes its selected HTTP method to request dispatch. A command-name-only allowlist cannot cover the proposed REST-method and extension cases. A client-side guard also cannot replace server-enforced, least-privilege authorization for preventing writes outside the CLI.

    Next action: Azure CLI and identity maintainers should decide whether this is a best-effort CLI safety rail or an enforceable security requirement, then define how the policy covers core commands, extensions, and az rest. No additional reproduction details or bug-fix job are warranted for this design decision.

    X Engineering Agent · Fixer · react 👍 / 👎 to train the agent

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

ARMaz resource/group/lock/tag/deployment/policy/managementapp/account management-groupAuto-AssignAuto assign by botAzure CLI TeamThe command of the issue is owned by Azure CLI teamSecurity-Issueact-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