DS DevShelfHub Projects · AI tools
Cheatsheets / Azure CLI
Cheatsheet · Dev tooling

Azure CLI Cheatsheet: VMs, AKS, Storage and RBAC

By DevShelfHub

Login, subscriptions, resource groups, VMs, storage, AKS, App Service, Functions, RBAC — the Azure CLI commands used daily across Azure infrastructure and CI/CD pipelines. Covers az login flows, JMESPath --query filtering, and the service-principal pattern for automation.

119 items ◷ 9 min az RBAC Resource groups

Start hereQuick start · 6 you’ll reach for daily

Who am Iaz account show
Switch subaz account set -s "Prod"
Set defaultsaz configure --defaults group=rg-prod
Open in browseraz group show -n rg-prod | jq
Slice JSON--query "[?tags.env=='prod'].id"
Tail app logsaz webapp log tail -g RG -n APP

Target versions · paceVersions

Targets: az ≥ 2.65 Microsoft Entra ID RBAC

az ad commands now hit Microsoft Graph (the AAD Graph removal is complete). --query uses JMESPath, --filter uses OData on a handful of commands. Many surfaces have official Bicep / Terraform equivalents — the CLI is best for exploration, one-shots, and operational debugging.

install · login · defaultsSetup

bash
# install (macOS — Homebrew)
brew update && brew install azure-cli

# install (Linux — Microsoft script)
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

# verify
az --version            # azure-cli 2.65+

# human login (browser)
az login                                 # interactive
az login --use-device-code               # remote shell / no browser
az login --tenant TENANT_ID              # pin a tenant

# service principal (CI)
az login --service-principal -u APP_ID -p PASSWORD --tenant TENANT_ID

# managed identity (inside Azure VM/Function)
az login --identity

# pick a subscription
az account list --output table
az account set --subscription "Prod"

# defaults — shorten future commands
az configure --defaults group=rg-prod location=eastus
az config set core.output=table
az config set core.no_color=yes        # for CI logs

tenant · sub · identityLogin & subscriptions

az loginInteractive browser login.
az login --use-device-codeHeadless / remote-shell flow.
az login --tenant TENANT_IDPin to a specific tenant.
az login --service-principal -u APP_ID -p PWD --tenant TCI login with SP secret.
az login --identityManaged identity from inside an Azure resource.
az login --identity --client-id CIDUser-assigned managed identity.
az logoutDrop cached creds.
az account showActive sub + tenant + user.
az account list --output tableAll subs you can see.
az account set --subscription "Prod"Switch active sub (name or ID).
az account get-access-token --resource https://management.azure.comBearer token for ad-hoc curl.
az ad signed-in-user showUPN / object-id of the logged-in user.

--query · --output · --filterOutput & queries

--output jsonDefault. Pipe into jq.
--output jsoncColourized JSON for terminals.
--output tableEyeball-friendly grid.
--output tsvTab-separated. Friendly to xargs.
--output yamlRound-trips with manifests.
--output noneSuppress — use for fire-and-forget commands.
--query "[].name"JMESPath projection.
--query "[?location=='eastus'].id"Filter + project.
--query "[?tags.env=='prod'] | length(@)"Aggregate after filter.
--filter "startswith(displayName,'svc-')"Server-side OData filter (Graph commands only).
--debug --verboseFull HTTP + token traces. Best debug aid.
--only-show-errorsHide preview/warning banners in CI.
bash
# --query is JMESPath; --output controls shape.

# all VMs as a flat table with selected fields
az vm list --query "[].{Name:name, RG:resourceGroup, Size:hardwareProfile.vmSize, State:powerState}" \
  --output table

# filter by tag
az vm list --query "[?tags.env=='prod'].id" --output tsv

# nested property + projection
az resource list \
  --resource-type Microsoft.Web/sites \
  --query "[].{Name:name, RG:resourceGroup, Plan:appServicePlanId}" \
  --output table

# pipe IDs into a delete loop
az vm list --query "[?tags.env=='stale'].id" --output tsv \
  | xargs -I{} az vm delete --ids {} --yes --no-wait

# ARG (Resource Graph) — Kusto across all subs in tenant
az graph query -q "Resources | where type =~ 'microsoft.compute/virtualmachines' | summarize count() by location"

group · resource · deploymentResource groups & resources

az group list --output tableResource groups in sub.
az group create -n rg-prod -l eastusCreate an RG.
az group show -n rg-prodMetadata, tags, provisioning state.
az group delete -n rg-prod --yes --no-waitDestructive. Tears down every resource inside.
az resource list -g rg-prod --output tableEverything inside one RG.
az resource show --ids /subscriptions/…Look up by full Azure resource ID.
az resource tag --tags env=prod owner=team-a --ids IDReplace tags.
az deployment group create -g RG --template-file main.bicep --parameters env=prodApply a Bicep template (or ARM JSON).
az deployment group what-if -g RG --template-file main.bicepPreferred Preview a deployment diff before applying.
az deployment group list -g RG --output tablePast deployment history.
az resource lock create --name no-delete --resource-group RG --lock-type CanNotDeleteSoft-block accidental deletes.
az tag list --resource-id IDTags on a single resource.

vms · ssh · run-commandVirtual machines

az vm list -d --output table-d includes power state — otherwise it’s an extra call per VM.
az vm create -g RG -n web --image Ubuntu2204 --size Standard_B2s --generate-ssh-keysLaunch a VM.
az vm start -g RG -n webPower on.
az vm deallocate -g RG -n webStop + release compute (no more charges).
az vm stop -g RG -n webStop only (still billed).
az vm delete -g RG -n web --yesDestructive. Disks may survive depending on flag.
az vm resize -g RG -n web --size Standard_D4s_v5Change SKU. Requires restart.
az ssh vm --resource-group RG --name webPreferred SSH via AAD — no keypair management.
az vm run-command invoke -g RG -n web --command-id RunShellScript --scripts "uptime"Run a command remotely without SSH.
az vm list-ip-addresses --output tablePublic + private IPs.
az vm extension set -g RG --vm-name web --name CustomScript --publisher Microsoft.Azure.Extensions --settings '{}'Push an agent extension.

accounts · blobs · SASStorage

az storage account list --output tableAll storage accounts in sub.
az storage account create -n myacct -g RG -l eastus --sku Standard_LRSNew account (Locally Redundant).
az storage account show-connection-string -n myacct -g RGConnection string for tools.
az storage container create --account-name myacct -n logsCreate a blob container.
az storage blob upload --account-name myacct -c logs -f file.txt -n key.txtSingle upload.
az storage blob upload-batch --account-name myacct -d logs -s ./distRecursive upload.
az storage blob download-batch --account-name myacct -s logs -d ./localRecursive download.
az storage blob delete --account-name myacct -c logs -n key.txtDelete one blob.
az storage blob generate-sas --account-name myacct -c logs -n key.txt --permissions r --expiry 2026-06-01T00:00ZTime-limited signed URL.
az storage fs list --account-name myacctADLS Gen2 filesystems.
azcopy copy ./dist "https://myacct.blob.core.windows.net/logs?SAS"Preferred Fastest data movement; azcopy ships separately.

SPs · roles · assignmentsEntra & RBAC

az ad sp list --display-name svcService principals by prefix.
az ad sp create-for-rbac --name ci --role Contributor --scopes /subscriptions/SUB/resourceGroups/RG --json-authPreferred Mints SP scoped to one RG, prints JSON for CI.
az ad sp credential reset --id APP_IDRotate the SP secret.
az ad user list --query "[].{n:displayName, u:userPrincipalName}" --output tableDirectory users.
az ad group list / member list / member addGroup lifecycle.
az role definition list --query "[].roleName" --output tsvAll built-in role names.
az role definition list --name ContributorFull permission list of a role.
az role assignment create --assignee EMAIL_OR_OID --role Reader --scope /subscriptions/SUBGrant.
az role assignment list --all --assignee EMAIL --output tableBlast-radius lookup for a principal.
az role assignment delete --assignee EMAIL --role Reader --scope /subscriptions/SUBRevoke.
bash
# create a service principal scoped to a resource group (CI-friendly)
SP=$(az ad sp create-for-rbac \
  --name "ci-deployer" \
  --role Contributor \
  --scopes "/subscriptions/$SUB/resourceGroups/rg-prod" \
  --json-auth)

echo "$SP" > sa.json   # appId, password, tenant, subscriptionId

# add an extra role at a narrower scope
az role assignment create \
  --assignee "$(echo "$SP" | jq -r .clientId)" \
  --role "Storage Blob Data Reader" \
  --scope "/subscriptions/$SUB/resourceGroups/rg-prod/providers/Microsoft.Storage/storageAccounts/myacct"

# audit: who has what on a resource group
az role assignment list \
  --resource-group rg-prod \
  --output table

# revoke
az role assignment delete \
  --assignee APP_ID \
  --role Contributor \
  --scope "/subscriptions/$SUB/resourceGroups/rg-prod"

clusters · kubeconfig · node poolsAKS

az aks list --output tableAll clusters in sub.
az aks create -g RG -n aks --node-count 2 --enable-managed-identity --generate-ssh-keysMinimal cluster create.
az aks get-credentials -g RG -n aks --overwrite-existingMerge into ~/.kube/config.
az aks get-credentials -g RG -n aks --adminLocal-admin kubeconfig (bypasses AAD).
az aks nodepool list --cluster-name aks -g RG --output tableNode-pool inventory.
az aks nodepool scale --cluster-name aks -g RG -n nodepool1 --node-count 4Scale a node pool.
az aks get-upgrades -g RG -n aks --output tableAvailable control-plane versions.
az aks upgrade -g RG -n aks --kubernetes-version 1.30.0 --yesUpgrade.
az aks command invoke -g RG -n aks --command "kubectl get pods -A"Run kubectl against a private cluster without VPN.
az aks delete -g RG -n aks --yes --no-waitDestructive. Drops every pool.
bash
# create an AKS cluster (small, managed identity, single node pool)
az aks create \
  --resource-group rg-prod \
  --name aks-prod \
  --node-count 2 \
  --enable-managed-identity \
  --generate-ssh-keys \
  --enable-cluster-autoscaler --min-count 1 --max-count 5

# wire kubectl to it (--admin uses the local-admin kubeconfig)
az aks get-credentials -g rg-prod -n aks-prod --overwrite-existing
kubectl get nodes

# scale node pool
az aks nodepool scale -g rg-prod --cluster-name aks-prod --name nodepool1 --node-count 4

# upgrade control plane + nodes
az aks get-upgrades -g rg-prod -n aks-prod --output table
az aks upgrade -g rg-prod -n aks-prod --kubernetes-version 1.30.0 --yes

webapp · plan · functionappApp Service & Functions

az appservice plan create -g RG -n plan --is-linux --sku B1Hosting plan (Linux, Basic tier).
az webapp create -g RG -p plan -n APP --runtime "PYTHON:3.12"New web app on a code-based runtime.
az webapp create -g RG -p plan -n APP --deployment-container-image-name acr.azurecr.io/app:v1Container-based web app.
az webapp up -g RG -n APP --runtime "PYTHON:3.12"Zip-deploy current dir end-to-end.
az webapp config appsettings set -g RG -n APP --settings KEY=VALUESet env vars (visible to the app process).
az webapp config appsettings set -g RG -n APP --settings KEY="@Microsoft.KeyVault(VaultName=KV;SecretName=s)"Key Vault reference.
az webapp identity assign -g RG -n APPTurn on system-assigned managed identity.
az webapp restart -g RG -n APPRestart all instances.
az webapp log tail -g RG -n APPLive tail stdout/stderr.
az webapp ssh -g RG -n APPSSH into the running container.
az functionapp create -g RG -p plan -n FN --runtime python --storage-account ACCT --functions-version 4Function app (consumption or plan).
az functionapp deployment source config-zip -g RG -n FN --src fn.zipPush a packaged function.

secrets · logs · metricsKey Vault & Monitor

az keyvault create -g RG -n KV --enable-rbac-authorization truePreferred RBAC-mode KV (no legacy access policies).
az keyvault secret set --vault-name KV -n api-key --value "s3cr3t"Store / update a secret.
az keyvault secret show --vault-name KV -n api-key --query value -o tsvRead just the value.
az keyvault secret list --vault-name KV --output tableInventory.
az keyvault secret set-attributes --vault-name KV -n api-key --enabled falseDisable without deleting.
az keyvault key create --vault-name KV -n signer --kty RSA --size 2048Mint a managed RSA key.
az monitor log-analytics query -w WORKSPACE_ID --analytics-query "ContainerLog | take 50"Kusto query against Log Analytics.
az monitor activity-log list --resource-group RG --max-events 50 --output tableControl-plane audit log for an RG.
az monitor metrics list --resource ID --metric "Percentage CPU" --interval PT1MPull a metric series.
az monitor alert-rule create -g RG -n hi-cpu --condition "avg Percentage CPU > 80" --target-resource-id IDThreshold alert.

acr · webapp · kv · identityEnd-to-end · Containerized web app

Build an image in ACR, deploy it to App Service, mint a managed identity, store an API key in Key Vault, and let the app read it through a Key Vault reference — no secrets in env files.

bash
# end-to-end: ship a containerized web app to App Service with Key Vault secret
RG=rg-prod
LOC=eastus
ACR=myregistry$RANDOM
APP=hello-app
PLAN=plan-linux
KV=kv-prod-$RANDOM

# 1) create RG, registry, App Service plan
az group create -n $RG -l $LOC
az acr create -g $RG -n $ACR --sku Basic --admin-enabled false
az appservice plan create -g $RG -n $PLAN --is-linux --sku B1

# 2) build + push the image inside ACR (no local Docker needed)
az acr build -r $ACR -t app:v1 .

# 3) put the API key in Key Vault, let the app read it
az keyvault create -g $RG -n $KV --enable-rbac-authorization true
az keyvault secret set --vault-name $KV --name api-key --value "s3cr3t"

# 4) create the web app, attach managed identity, grant KV access
az webapp create -g $RG -p $PLAN -n $APP --deployment-container-image-name $ACR.azurecr.io/app:v1
az webapp identity assign -g $RG -n $APP
PRINCIPAL=$(az webapp identity show -g $RG -n $APP --query principalId -o tsv)
az role assignment create --assignee "$PRINCIPAL" \
  --role "Key Vault Secrets User" \
  --scope "$(az keyvault show -n $KV --query id -o tsv)"

# 5) wire the secret as an env var (KV reference)
az webapp config appsettings set -g $RG -n $APP --settings \
  API_KEY="@Microsoft.KeyVault(VaultName=$KV;SecretName=api-key)"

# 6) tail the logs
az webapp log tail -g $RG -n $APP

Best practiceGood to know

Set az configure --defaults group= location= per project. Half of the verbosity in az is repeating the same RG and region. Set them once and drop -g from most commands.
Prefer az deployment group what-if before create. It diffs the Bicep/ARM template against current state and shows resource-level adds/changes/deletes. Cheap insurance against accidentally rebuilding a database.
Use managed identities + Key Vault references, not connection strings in appsettings. @Microsoft.KeyVault(VaultName=…;SecretName=…) turns App Service env vars into rotation-safe pointers. Rotate the secret, no redeploy needed.

Common trapsWatch out for

Stopped VMs may still be billing. az vm stop halts the OS but keeps compute reserved. Use az vm deallocate to release the underlying compute and stop charges.
JMESPath strings need single quotes, double quotes are for the shell. --query "[?tags.env=='prod']" is right. Swap the quoting and the shell eats the $ — or worse, the filter silently matches nothing.
SP secrets expire — usually one or two years. az ad sp create-for-rbac issues a password with a default lifetime. Rotate with az ad sp credential reset on a schedule, or move to federated credentials (OIDC) for GitHub / GitLab CI.

Go deeperSee also

Azure CLI FAQ

What is the Azure CLI?

The Azure CLI (`az`) is Microsoft's cross-platform command-line tool for managing Azure resources. It runs on Linux, macOS, and Windows, outputs JSON by default, and supports JMESPath filtering with `--query`, making it easy to script Azure infrastructure and automation pipelines.

How do I log in to Azure with the CLI?

Run `az login` to open a browser and authenticate with your Microsoft account. For service principals use `az login --service-principal -u <app-id> -p <secret> --tenant <tenant-id>`. In headless environments, `az login --use-device-code` prints a code you enter in a browser on any machine.

How do I switch between Azure subscriptions in the CLI?

List all accessible subscriptions with `az account list --output table`, then activate the one you want with `az account set --subscription <id-or-name>`. Every subsequent command targets that subscription until you switch again or start a new session.

How do I filter Azure CLI output with JMESPath?

Pass a JMESPath expression to `--query`. For example, `az vm list --query '[].{name:name, state:powerState}' -o table` extracts name and power state from every VM. Combine with `-o json`, `-o tsv`, or `-o table` to get the exact format you need for scripting or display.

How do I manage AKS clusters with the Azure CLI?

Create a cluster with `az aks create`, then pull its kubeconfig with `az aks get-credentials --resource-group <rg> --name <cluster>`. After that, standard `kubectl` commands target the AKS cluster. Scale node pools with `az aks scale` and upgrade the Kubernetes version with `az aks upgrade`.

How do I automate Azure CLI commands in CI/CD without storing passwords?

Use a service principal with az login --service-principal --tenant $TENANT --username $APP_ID --password $CLIENT_SECRET, or better — use federated identity credentials (az ad app federated-credential create) to exchange GitHub or Azure DevOps OIDC tokens for short-lived credentials with no secret to rotate. Assign only the minimum RBAC role the pipeline needs.