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.65Microsoft Entra IDRBAC
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 login
Interactive browser login.
az login --use-device-code
Headless / remote-shell flow.
az login --tenant TENANT_ID
Pin to a specific tenant.
az login --service-principal -u APP_ID -p PWD --tenant T
CI login with SP secret.
az login --identity
Managed identity from inside an Azure resource.
az login --identity --client-id CID
User-assigned managed identity.
az logout
Drop cached creds.
az account show
Active sub + tenant + user.
az account list --output table
All subs you can see.
az account set --subscription "Prod"
Switch active sub (name or ID).
az account get-access-token --resource https://management.azure.com
Bearer token for ad-hoc curl.
az ad signed-in-user show
UPN / object-id of the logged-in user.
--query · --output · --filterOutput & queries
--output json
Default. Pipe into jq.
--output jsonc
Colourized JSON for terminals.
--output table
Eyeball-friendly grid.
--output tsv
Tab-separated. Friendly to xargs.
--output yaml
Round-trips with manifests.
--output none
Suppress — 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 --verbose
Full HTTP + token traces. Best debug aid.
--only-show-errors
Hide 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 table
Resource groups in sub.
az group create -n rg-prod -l eastus
Create an RG.
az group show -n rg-prod
Metadata, tags, provisioning state.
az group delete -n rg-prod --yes --no-wait
Destructive. Tears down every resource inside.
az resource list -g rg-prod --output table
Everything 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 ID
Replace tags.
az deployment group create -g RG --template-file main.bicep --parameters env=prod
Apply a Bicep template (or ARM JSON).
az deployment group what-if -g RG --template-file main.bicep
Preferred Preview a deployment diff before applying.
az deployment group list -g RG --output table
Past deployment history.
az resource lock create --name no-delete --resource-group RG --lock-type CanNotDelete
Soft-block accidental deletes.
az tag list --resource-id ID
Tags 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-keys
Launch a VM.
az vm start -g RG -n web
Power on.
az vm deallocate -g RG -n web
Stop + release compute (no more charges).
az vm stop -g RG -n web
Stop only (still billed).
az vm delete -g RG -n web --yes
Destructive. Disks may survive depending on flag.
az vm resize -g RG -n web --size Standard_D4s_v5
Change SKU. Requires restart.
az ssh vm --resource-group RG --name web
Preferred 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 table
Public + private IPs.
az vm extension set -g RG --vm-name web --name CustomScript --publisher Microsoft.Azure.Extensions --settings '{}'
Preferred Fastest data movement; azcopy ships separately.
SPs · roles · assignmentsEntra & RBAC
az ad sp list --display-name svc
Service principals by prefix.
az ad sp create-for-rbac --name ci --role Contributor --scopes /subscriptions/SUB/resourceGroups/RG --json-auth
Preferred Mints SP scoped to one RG, prints JSON for CI.
az ad sp credential reset --id APP_ID
Rotate the SP secret.
az ad user list --query "[].{n:displayName, u:userPrincipalName}" --output table
Directory users.
az ad group list / member list / member add
Group lifecycle.
az role definition list --query "[].roleName" --output tsv
All built-in role names.
az role definition list --name Contributor
Full permission list of a role.
az role assignment create --assignee EMAIL_OR_OID --role Reader --scope /subscriptions/SUB
Grant.
az role assignment list --all --assignee EMAIL --output table
Blast-radius lookup for a principal.
az role assignment delete --assignee EMAIL --role Reader --scope /subscriptions/SUB
Revoke.
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 table
All clusters in sub.
az aks create -g RG -n aks --node-count 2 --enable-managed-identity --generate-ssh-keys
Minimal cluster create.
az aks get-credentials -g RG -n aks --overwrite-existing
Merge into ~/.kube/config.
az aks get-credentials -g RG -n aks --admin
Local-admin kubeconfig (bypasses AAD).
az aks nodepool list --cluster-name aks -g RG --output table
Node-pool inventory.
az aks nodepool scale --cluster-name aks -g RG -n nodepool1 --node-count 4
Scale a node pool.
az aks get-upgrades -g RG -n aks --output table
Available control-plane versions.
az aks upgrade -g RG -n aks --kubernetes-version 1.30.0 --yes
Upgrade.
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-wait
Destructive. 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 B1
Hosting 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:v1
Container-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=VALUE
Set 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 APP
Turn on system-assigned managed identity.
az webapp restart -g RG -n APP
Restart all instances.
az webapp log tail -g RG -n APP
Live tail stdout/stderr.
az webapp ssh -g RG -n APP
SSH into the running container.
az functionapp create -g RG -p plan -n FN --runtime python --storage-account ACCT --functions-version 4
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.
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.