Azure setup
Audience: operator · Profile:
both· Read this when: you are giving the dashboard an Azure subscription to deploy into.
Part of the Onboarding Guide.
The dashboard deploys Azure VMs into your Azure subscription using a service principal (SP) scoped to a single resource group.
1. Log in and pick a subscription
az login
az account show --query id -o tsv
Copy the subscription id.
2. Create the resource group and pick a region
az group create --name dashboard-rg --location eastus
The AZURE_RESOURCE_GROUP value in .env becomes the default RG for deployed
VMs, and AZURE_LOCATION its region (e.g. centralus, eastus,
westeurope). Create it now rather than letting the first deploy create it —
the SP in the next step is scoped to this resource group, so it has to exist
first.
3. Create the service principal
az ad sp create-for-rbac `
--name "dashboard-dev" `
--role Contributor `
--scopes /subscriptions/<your-subscription-id>/resourceGroups/dashboard-rg
The output includes appId, password, and tenant — you need all three
(plus the subscription id) for .env.
Scope it to the resource group, not the subscription. The sandbox scripts scope
Contributorto a single RG, and so should you; a subscription-wide grant hands the dashboard every resource you own. Widen it only if you deliberately want deploys landing outsidedashboard-rg.Security note: the client secret (
password) rotates. Azure will warn you when it nears expiry; create a new one and update.env.
4. Grant the additional roles
Contributor on the RG is not sufficient on its own. It is a control-plane
role, so it cannot write blob data — and Terraform state is blob data. Add the
grants for the features you intend to use:
| Feature | Grant | Scope |
|---|---|---|
| Terraform state + storage backend | Storage Blob Data Contributor |
the storage account |
| Secrets backend (Key Vault) | secret permissions get list set delete |
the vault |
| Kubernetes clusters (AKS) | User Access Administrator |
the resource group |
| Cloud Costs | Cost Management Reader |
the subscription |
| Container registry pulls | AcrPull |
the registry |
| Image promote into a Compute Gallery | a custom role with the gallery/image actions, or Contributor |
the gallery's RG |
# Terraform state and the azure_blob storage backend — data plane, required
az role assignment create `
--assignee <appId> `
--role "Storage Blob Data Contributor" `
--scope /subscriptions/<sub-id>/resourceGroups/dashboard-rg/providers/Microsoft.Storage/storageAccounts/<account>
# Key Vault secrets backend — write is required so per-VM admin passwords can
# be vaulted and removed again on teardown
az keyvault set-policy --name <vault> `
--object-id <sp-object-id> `
--secret-permissions get list set delete
# AKS only: the cluster module creates its own role assignment, which
# Contributor cannot do (it lacks Microsoft.Authorization/roleAssignments/write)
az role assignment create `
--assignee <appId> `
--role "User Access Administrator" `
--scope /subscriptions/<sub-id>/resourceGroups/dashboard-rg
# Cloud Costs only: cost data is queried at subscription scope
az role assignment create `
--assignee <appId> `
--role "Cost Management Reader" `
--scope /subscriptions/<sub-id>
Key Vault: access policy or RBAC. The command above uses a vault access policy, which is what the sandbox scripts do. If your vault uses the RBAC permission model instead, the equivalent is the Key Vault Secrets Officer role — see secrets-management.md.
For the authoritative list, see the role assignments in
scripts/sandbox/Linux/setup-azure.sh;
that script is the source of truth.