Azure Provider
Read this when you are:
- choosing
provider: azure; - debugging Azure VM capacity, quotas, images, or SSH readiness;
- changing
internal/providers/azureor the direct Azure provisioning code.
Azure is a managed provider for Linux, native Windows, and Windows WSL2 leases. Azure provisions the VM, public IP, NIC, and OS disk; Crabbox then owns SSH readiness, optional desktop/VNC or WSL2 bootstrap, sync, command execution, test results, and cleanup.
#When to use Azure
Reach for Azure when your cloud capacity lives in an Azure subscription, or when Microsoft tooling, Entra ID, or Azure-specific networking constraints make AWS or Hetzner a poor fit. Use Hetzner for cheaper Linux-only capacity and AWS for macOS targets — Azure does not provision macOS.
For Windows and Windows WSL2, Azure is a good default when the subscription has healthy credits or reserved capacity. Brokered Azure leases use the same ordered capacity-region fallback model as AWS.
Azure supports both execution modes:
- Direct mode uses local Azure credentials and talks to Azure directly from
- Brokered mode routes lease lifecycle through the coordinator, which
the CLI.
holds an operator-owned Azure service principal. The CLI still does SSH, sync, and command execution directly to the runner host.
#Commands
crabbox warmup --provider azure --class beast
crabbox warmup --provider azure --arch arm64 --class fast
crabbox warmup --provider azure --class beast --azure-os-disk ephemeral
crabbox warmup --provider azure --class beast --azure-os-disk ephemeral-preview
crabbox run --provider azure --class standard -- pnpm test
crabbox run --provider azure --azure-backend dynamic-sessions -- pnpm test
crabbox warmup --provider azure --target windows --class standard
crabbox warmup --provider azure --target windows --desktop --class standard
crabbox warmup --provider azure --target windows --windows-mode wsl2 --class standard
crabbox warmup --provider azure --desktop --browser
crabbox ssh --provider azure --id blue-lobster
crabbox stop --provider azure blue-lobster
crabbox cleanup --provider azure
--type is exact (for example --type Standard_D32ads_v6). Use --class when you want SKU fallback. Azure leases use managed OS disks by default, so native checkpoint/fork works without extra flags. Pass --azure-os-disk ephemeral only for stateless leases that do not need native checkpoint/fork. Pass --azure-os-disk ephemeral-preview to opt into Azure's public-preview full-caching mode for ephemeral OS disks.
#Backend selection
azure.backend (CLI --azure-backend, env CRABBOX_AZURE_BACKEND) selects the Azure-family backend:
vm(default) — Azure Virtual Machines with SSH leases. This is what this pagedynamic-sessions— routes to the
documents.
azure-dynamic-sessions provider for delegated Linux runs inside an Azure Container Apps Dynamic Sessions pool.
#Config
provider: azure
target: linux
architecture: amd64
class: beast
azure:
backend: vm
subscriptionId: 00000000-0000-0000-0000-000000000000
tenantId: 00000000-0000-0000-0000-000000000000
clientId: 00000000-0000-0000-0000-000000000000
location: eastus
resourceGroup: crabbox-leases
image: Canonical:ubuntu-26_04-lts:server:latest
osDisk: managed
vnet: crabbox-vnet
subnet: crabbox-subnet
nsg: crabbox-nsg
sshCIDRs: []
network: public
subscriptionId, tenantId, and clientId may be set in config or sourced from environment variables. The client secret is never read from config — it must come from the environment.
Set architecture: arm64 or pass --arch arm64 for Linux ARM leases. Crabbox then switches class fallback to Azure Cobalt Dpsv6/Dpdsv6 sizes and uses the matching Ubuntu ARM64 Marketplace image unless azure.image is explicitly set. Native Windows ARM64 leases also use Azure Cobalt VM sizes and require an explicit ARM64 Windows Marketplace or custom image. Azure Windows ARM64 WSL2 is not supported because those VM sizes do not support nested virtualization.
azure.network selects which IP the CLI uses for SSH: public (default) uses the VM public IP, private uses the NIC private IP from the vnet. Use private when connecting through a VPN to the Azure virtual network.
azure.osDisk accepts managed, ephemeral, ephemeral-preview, or auto:
managed(default) provisions a managedStandardSSD_LRSOS disk so Azureephemeralopts into a local OS disk. It requires a SKU with ephemeral OS diskephemeral-previewenables Azure ephemeral OS disk full caching with Computeautois accepted for compatibility and resolves tomanaged.
native disk-snapshot checkpoints work.
support, fails during provisioning when the selected SKU cannot support it, and disables native Azure checkpoint/fork.
API 2025-04-01. It is public preview, has the same checkpoint/fork limits as ephemeral, and skips known unsupported 2-core, 4-core, and no-local-disk Azure SKUs from Crabbox fallback lists.
#Environment variables
Direct-mode config can be supplied entirely via environment:
AZURE_SUBSCRIPTION_ID # or CRABBOX_AZURE_SUBSCRIPTION_ID
AZURE_TENANT_ID # or CRABBOX_AZURE_TENANT_ID
AZURE_CLIENT_ID # or CRABBOX_AZURE_CLIENT_ID
AZURE_CLIENT_SECRET # service-principal secret (never read from config)
CRABBOX_AZURE_BACKEND # vm | dynamic-sessions
CRABBOX_AZURE_LOCATION
CRABBOX_AZURE_RESOURCE_GROUP
CRABBOX_AZURE_IMAGE
CRABBOX_AZURE_WINDOWS_ARM64_IMAGE
CRABBOX_AZURE_OS_DISK # managed | ephemeral | ephemeral-preview | auto
CRABBOX_AZURE_VNET
CRABBOX_AZURE_SUBNET
CRABBOX_AZURE_NSG
CRABBOX_AZURE_SSH_CIDRS # comma-separated
CRABBOX_AZURE_NETWORK # public | private
AZURE_* are the standard service-principal variables consumed by DefaultAzureCredential. Crabbox does not read or print the client secret.
#Auth
The simplest setup uses the Azure CLI — no environment variables needed:
az login
crabbox azure login
crabbox warmup --provider azure
crabbox azure login detects the active subscription, validates credentials, and stores the subscription ID, tenant ID, and location (default eastus) in user config. After that, DefaultAzureCredential picks up the az login session automatically.
For service-principal setups (CI, automation, shared environments), use environment variables. If azure.tenantId and azure.clientId (or CRABBOX_AZURE_TENANT_ID / CRABBOX_AZURE_CLIENT_ID) are configured and AZURE_CLIENT_SECRET is set in the environment, Crabbox builds a ClientSecretCredential from those explicit values. Otherwise it falls back to azidentity.NewDefaultAzureCredential, which scans environment, workload identity, managed identity, and CLI credentials in order. The simplest service-principal grant is the Contributor role scoped to the resource group:
export AZURE_TENANT_ID=...
export AZURE_CLIENT_ID=...
export AZURE_CLIENT_SECRET=...
export AZURE_SUBSCRIPTION_ID=...
See Authenticate Go apps to Azure services with service principals.
#Brokered mode
Brokered leases reuse the same Azure service-principal secrets on the coordinator: AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, and AZURE_SUBSCRIPTION_ID. Operators own the resource group, vnet, subnet, NSG, OS disk mode, and SSH CIDR defaults through the CRABBOX_AZURE_* env vars on the Worker. A lease request may override only azureLocation, azureImage, and azureOSDisk. Set CRABBOX_AZURE_WINDOWS_ARM64_IMAGE on the coordinator when brokered Azure Windows ARM64 leases need a default ARM64 Windows image without changing the global CRABBOX_AZURE_IMAGE fallback used by existing custom-image leases.
Set CRABBOX_AZURE_REGIONS on the coordinator for Azure-specific capacity fallback; CRABBOX_CAPACITY_REGIONS remains the AWS region fallback list.
Run crabbox doctor --provider azure --target windows before leasing through the broker. The coordinator readiness check reports missing coordinator secret names without exposing values, and lease creation fails with provider_not_configured until the required service-principal secrets are present.
#Lifecycle
- Resolve credentials per the rules above.
- Ensure the shared resource group, virtual network, subnet, and network
security group exist. Crabbox first issues Get calls against each resource:
- If a resource exists without the
managed_by=crabboxtag, Crabbox refuses - If a resource exists with the tag, it is left alone (Crabbox does not
- If a resource is missing, it is created with Crabbox tags and the configured
to mutate it and returns an adopt-or-rename error.
overwrite tags, address spaces, subnets, or rules on later acquires).
layout. Inbound SSH rules are derived from azure.sshCIDRs, the configured SSH port, and any fallback ports.
- Mint a per-lease SSH key.
- Pick the configured class SKU candidates and try each in order.
- Create a public IP, NIC, and VM. Linux passes cloud-init in
- Choose the OS disk mode (see Config above).
- Tag the VM, NIC, and public IP with Crabbox lease metadata.
- Wait for the public IP to allocate, then for SSH readiness.
- For
--desktopon native Windows, run the shared Windows desktop bootstrap - For
--windows-mode wsl2, run the shared Windows WSL2 bootstrap over SSH: - Let core sync and run over SSH.
- On release/cleanup, cascade-delete VM -> NIC -> public IP -> OS disk. The
osProfile.customData and the SSH key in osProfile.linuxConfiguration.ssh.publicKeys. Native Windows uses a Windows Server small-disk Gen2 image, Windows osProfile fields (adminPassword, computerName, windowsConfiguration), and a non-rebooting Custom Script Extension that runs the initial SSH bootstrap saved in C:\AzureData\CustomData.bin.
over SSH: install TightVNC, configure the generated crabbox Windows login, enable auto-logon, reboot once, and wait for SSH/VNC readiness.
enable WSL/VirtualMachinePlatform/HypervisorPlatform, reboot as needed, import Ubuntu, and wait for the Linux-side crabbox-ready check.
shared infra remains.
#Classes
Default Linux SKU candidates (first that provisions wins):
standard Standard_D32ads_v6, Standard_D32ds_v6, Standard_F32s_v2, Standard_D32ads_v5, Standard_D32ds_v5, then D/F 16-vCPU fallbacks
fast Standard_D64ads_v6, Standard_D64ds_v6, Standard_F64s_v2, Standard_D64ads_v5, Standard_D64ds_v5, then D/F 48-vCPU and 32-vCPU fallbacks
large Standard_D96ads_v6, Standard_D96ds_v6, Standard_D96ads_v5, Standard_D96ds_v5, then D/F 64-vCPU and 48-vCPU fallbacks
beast Standard_D192ds_v6, Standard_D128ds_v6, then D/F 96-vCPU and 64-vCPU fallbacks
Default native Windows and WSL2 SKU candidates:
standard Standard_D2ads_v6, Standard_D2ds_v6, Standard_D2ads_v5, Standard_D2ds_v5, then Standard_D2as_v6
fast Standard_D4ads_v6, Standard_D4ds_v6, Standard_D4ads_v5, Standard_D4ds_v5, then Standard_D4as_v6
large Standard_D8ads_v6, Standard_D8ds_v6, Standard_D8ads_v5, Standard_D8ds_v5, then Standard_D8as_v6
beast Standard_D16ads_v6, Standard_D16ds_v6, Standard_D16ads_v5, Standard_D16ds_v5, then Standard_D8ads_v6
Class-based provisioning falls back across the candidate list when Azure rejects a SKU for capacity or quota (SkuNotAvailable, QuotaExceeded, AllocationFailed, OverconstrainedAllocationRequest). When capacity.regions (or broker-side CRABBOX_AZURE_REGIONS) is set, Crabbox also tries those Azure regions in order and uses region-scoped shared network names for the fallback path. Spot leases fall back to on-demand when capacity.fallback starts with on-demand. Azure Spot VMs use eviction policy Delete and billingProfile.maxPrice: -1, so price alone does not evict a lease while Azure still charges no more than the on-demand price. Explicit --type is exact for size selection but still allows configured region fallback.
#Capabilities
- SSH: yes.
- Crabbox sync: yes.
- Native Windows: SSH, sync, run, and desktop/VNC.
- Windows WSL2: SSH, sync, run, and Actions hydration (through the POSIX WSL
- Desktop: Linux and native Windows.
- Browser / code: Linux only.
- Tailscale: Linux managed leases.
- Cleanup: yes.
- Coordinator (brokered): Linux, native Windows, and WSL2 leases.
contract).
Azure does not provision macOS through this provider. Use AWS or provider: ssh for macOS targets.
#Gotchas
- Azure VM names are constrained to 1-64 characters and cannot contain
- Windows computer names are limited to 15 characters. Crabbox keeps the VM
- The first acquire in an empty subscription pays the cost of creating the shared
- Shared Azure network resources are regional. Leases use the configured
- If you already have a resource group / vnet / NSG with the configured names,
crabbox stop --provider azure <name>only acts on VMs that carrycrabbox=true- When
azure.sshCIDRsis empty on the public network path, direct Azure - Azure costs are not hardcoded in Crabbox. Set
CRABBOX_COST_RATES_JSONwhen you - Azure native Windows uses a Custom Script Extension because Windows custom data
- Direct-mode cleanup is best effort. Use
crabbox cleanup --provider azureto
underscores. The leaseProviderName helper substitutes dashes for underscores; keep that constraint in mind if you customize naming.
resource name stable and derives a shorter Windows computerName.
resource group, vnet, and NSG. Later acquires only create per-lease resources.
azure.vnet/azure.nsg names when they match the target region. If a Crabbox-managed VNet or NSG with that base name already exists in another region, Crabbox automatically uses region-scoped names such as crabbox-vnet-westeurope. Multi-region fallback also uses region-scoped shared network names, so one managed resource group can hold fallback networks safely.
Crabbox refuses to mutate them unless they carry the managed_by=crabbox tag. Tag them to adopt, choose different names in azure.* config, or let Crabbox create dedicated resources.
(and either no provider tag or provider=azure). A manually named VM in the resource group will not be deleted by Crabbox.
provisioning detects the operator's outbound IPv4 and creates a /32 SSH rule. If a shared NSG already has a different managed SSH CIDR, set CRABBOX_AZURE_SSH_CIDRS explicitly to replace or extend it. Private-network leases also require explicit VPN/VNet source CIDRs.
need exact Azure cost guardrails.
is written to disk but not executed by Azure provisioning. Keep that extension path non-rebooting; Windows desktop/VNC setup runs later over SSH.
sweep expired direct leases.