Skip to content

Azure CLI Setup

Companion: deployment, prod-launch-runbook.

1. Two accounts, one machine

The dev machine has two unrelated Azure accounts logged in:

  • The personal account lives in ~/.azure/ (the default location).
  • The FTL account lives in an isolated config directory: ~/.azure-ftl/.

Every az command for FTL must use AZURE_CONFIG_DIR=~/.azure-ftl. A bare az command without this prefix goes to the wrong account and risks accidental mutation of a personal subscription.

2. FTL account details

Field Value
User jetafifa2026@gmail.com
Subscription name FootbalTradeLeage
Subscription ID 8c48ba4e-7384-4579-a6e2-9aeb6c5a5de9
Tenant Default Directory (599ce68b-…)
Config dir ~/.azure-ftl/
Credit $200 Azure free credit (time-boxed)

Subscription spelling

The sub name is FootbalTradeLeageone l in Football, no u in League. This is the exact spelling in Azure. Match it literally when scripting filters.

3. First-time login — use device code

Device-code authentication is the recommended path for any dev machine, headless server, or CI runner. It opens a browser tab (or shows a URL + code you paste into any browser) so you can sign in with the FTL Google identity without typing the password locally.

AZURE_CONFIG_DIR=~/.azure-ftl az login --use-device-code

The CLI prints something like:

To sign in, use a web browser to open the page https://microsoft.com/devicelogin
and enter the code <CODE> to authenticate.

Steps:

  1. Open https://microsoft.com/devicelogin in a browser logged in to the FTL Google identity.
  2. Paste the 9-character code.
  3. Sign in as jetafifa2026@gmail.com.
  4. The CLI session completes and shows the FTL subscription as the active context.

If a different sub becomes default after login, set the FTL one explicitly:

AZURE_CONFIG_DIR=~/.azure-ftl az account set \
  --subscription 8c48ba4e-7384-4579-a6e2-9aeb6c5a5de9

Why not regular az login?

Regular az login opens a browser via OAuth callback on localhost. On WSL, headless servers, or any machine without a default browser this fails silently. Device-code works everywhere. Use it as the default.

4. Verify identity before any Azure operation

Run this every session before the first az command that touches FTL:

AZURE_CONFIG_DIR=~/.azure-ftl az account show \
  --query '{user:user.name, sub:name, id:id}' -o json

Expected output:

{"user": "jetafifa2026@gmail.com", "sub": "FootbalTradeLeage", "id": "8c48ba4e-7384-4579-a6e2-9aeb6c5a5de9"}

If any field differs:

  • Wrong sub: you're scoped to a different one. Run az account set --subscription 8c48ba4e-....
  • Wrong user: token expired or the personal account is bleeding in. Re-login (see §3).
  • Auth error: the access token is stale. Re-login.

5. Running az safely — three valid patterns

AZURE_CONFIG_DIR=~/.azure-ftl az account show
AZURE_CONFIG_DIR=~/.azure-ftl az containerapp show -g ftl-prd-rg-cin -n ftl-prd-api
AZURE_CONFIG_DIR=~/.azure-ftl az postgres flexible-server show -g ftl-prd-rg-cin -n ftl-prd-pg-cin

Use this in scripts, runbook snippets, and one-off Slack-quoted commands. Never depends on shell state.

export AZURE_CONFIG_DIR=~/.azure-ftl

az account show    # now scoped to FTL for the rest of this shell

Convenient for an interactive session. Risk: forgetting you exported it. Open a fresh shell for personal Azure work.

source ftl-infra/env.stg.sh    # exports AZURE_CONFIG_DIR + sub + naming vars
az account show                # implicitly scoped to FTL

Used in the staging deploy runbook. Equivalent to Pattern B with extra env vars.

6. The wrong way

az account show    # bare command in a shell that did NOT export
                    # AZURE_CONFIG_DIR — goes to the PERSONAL account

Any mutation (create, update, delete) executed bare against the personal sub is a bug. Read-only show / list against the personal account on purpose is OK.

7. Budget + cost reference

FTL has $200 of Azure free credit, time-boxed. Check remaining:

AZURE_CONFIG_DIR=~/.azure-ftl az consumption budget list

Latest measured burn (June 2026) lives in cost-estimate-audit-2026-06-11 and prod-snapshot-2026-06-11. Highlights:

Environment MTD INR (11 days) Run-rate (monthly) Top driver
Staging ~3 484 ~9 500 Redis Standard C1
Production ~6 389 ~17 425 PostgreSQL B2ms

8. Useful identity commands

# Who am I?
AZURE_CONFIG_DIR=~/.azure-ftl az account show --query 'user.name' -o tsv

# Token age (re-login if older than ~12 h)
AZURE_CONFIG_DIR=~/.azure-ftl az account get-access-token --query 'expiresOn' -o tsv

# Log out (next az call will require re-login)
AZURE_CONFIG_DIR=~/.azure-ftl az logout

# List subscriptions visible to my login
AZURE_CONFIG_DIR=~/.azure-ftl az account list --query '[].{name:name, id:id, isDefault:isDefault}' -o table

9. CI authentication (different from above)

GitHub Actions deploys use OIDC federated credentials, not device-code login. The workflow's azure/login@v2 step exchanges a GitHub-issued JWT for an Azure token using these GitHub env vars:

  • AZURE_CLIENT_ID
  • AZURE_TENANT_ID
  • AZURE_SUBSCRIPTION_ID

These are set on the staging and production GitHub Environments. No secret is involved on the CI side — the JWT is short-lived. See github-env-audit-2026-06-11 for the current state.

10. When to ask for help

Symptom First check If still stuck
az login shows wrong sub by default az account set --subscription <id> Drop ~/.azure-ftl/ and re-login
All az commands return 403 Token expired → re-login Verify with az account get-access-token
Mutation succeeds against wrong RG Stop, take a backup, file an incident Use az resource lock to freeze the resource
MissingSubscriptionRegistration Some resource providers need explicit registration; az provider register --namespace <ns> Confirm subscription has the SKU available in centralindia