4.2 Deploy Workspaces and Resources with Bicep and Azure CLI

Key Takeaways

  • Bicep is Azure Resource Manager (ARM) with a concise syntax: one template can create the workspace plus Azure Storage, Key Vault, Application Insights, Azure Container Registry, virtual networks, and private endpoints. ARM JSON is what Bicep compiles to. Terraform is common in the MLOps v2 accelerator. az ml CLI v2 manages workspace YAML and ML assets.
  • Create a workspace from YAML with az ml workspace create -f workspace.yml (or az ml workspace create -n -g to auto-create dependents). Create compute with az ml compute create. Pin a default workspace with az configure --defaults.
  • The default storage account cannot be Premium_LRS or Premium_GRS and cannot enable hierarchical namespace (Azure Data Lake Storage Gen2). After Azure Container Registry is attached, do not delete it — the workspace becomes inoperative.
  • IaC is idempotent: redeploying the same Bicep parameters converges on the same resources. Parameterize environment (dev/test/prod) for names, SKUs, publicNetworkAccess, and managed-network isolation. Do not hard-code a single workspaceName in source.
  • Register Microsoft.MachineLearningServices in any subscription that holds dependent resources. For managed virtual networks also register Microsoft.Network. ACR behind a virtual network requires the Premium SKU. Application Insights is not deployed inside a virtual network.
Last updated: August 2026

Deploy Workspaces and Resources with Bicep and Azure CLI

Quick Answer: Bicep (compiled Azure Resource Manager (ARM) JSON) declares the workspace and Azure dependents — storage, Key Vault, Application Insights, Azure Container Registry (ACR), virtual networks, private endpoints. az ml workspace create -f workspace.yml and az ml compute create are CLI v2 for workspace settings and ML compute. Parameterize dev / test / prod. Do not use Premium or hierarchical-namespace storage as the default account.

Exam AI-300 Domain 1 asks you to deploy Machine Learning workspaces and resources by using Bicep and Azure CLI. Clicking Create in the portal is how you learn the resource graph once. Production repeats that graph with infrastructure as code (IaC) so a reviewer can see that prod has publicNetworkAccess: Disabled and that dev does not share the prod Key Vault.

Four tools — pick by layer

ToolWhat it isWhat you use it for in AI-300
BicepMicrosoft DSL that compiles to ARM. Native modules, parameters, existing resource referencesWorkspace + storage + Key Vault + App Insights + ACR + VNet + private endpoints. az deployment group create --template-file main.bicep
ARM templateJSON. Bicep’s compilation target. Quickstart azuredeploy.json in microsoft.machinelearningservices/machine-learning-workspace-vnetSame resources when a pipeline already speaks ARM; keep API versions current (Microsoft.MachineLearningServices/workspaces)
TerraformMulti-cloud. The MLOps v2 GitHub demo ships tf-gha-deploy-infra.ymlSame Azure graph if the org standard is Terraform; still in scope as IaC, not a replacement for az ml job YAML
Azure CLI ml extension v2az ml after az extension add -n ml (Azure CLI ≥ 2.38.0). Remove legacy azure-cli-ml firstaz ml workspace create -f workspace.yml, az ml workspace update, az ml compute create, then jobs, environments, endpoints

Bicep/ARM/Terraform own Azure control-plane resources. az ml owns workspace-shaped objects: the workspace record, compute, datastores, and every asset from Chapter 3. You typically check both into infra/ and jobs/ of the same Git repo (section 4.1). Do not try to express a training component in Bicep; do not try to express a hub virtual network only with az ml job.

az ml commands talk to Azure Resource Manager over HTTPS/TLS 1.2. That is expected for v2. If the workspace has a private endpoint and you refuse public ARM, you need an ARM private link (subscription Owner plus root management group Owner/Contributor) — a later networking concern, not a reason to stay on CLI v1.

Dependent resources the workspace always has

A workspace is not a single resource. Create in a resource group (az group create -n rg -l eastus) in a region where Azure Machine Learning exists.

  • Azure Storage — default datastore (workspaceblobstore, workspacefilestore). Default account rules: not Premium_LRS or Premium_GRS; hierarchical namespace must be off (no Azure Data Lake Storage Gen2 on the default account). Blob and Azure Files must be available. Premium or HNS storage can still be non-default datastores (Chapter 2).
  • Azure Key Vault — secrets, compute SSH creds, some connection strings.
  • Application Insights — endpoint and workspace telemetry. Created with the workspace. If you delete it, the documented recovery is delete and recreate the workspace. App Insights is not deployed behind a virtual network.
  • Azure Container Registry — Docker images for environments. The workspace can lazy-create ACR on first image build. After ACR exists, do not delete it. Behind a virtual network, ACR must be Premium SKU. You may bring an existing registry; enable the admin account or (preferred) managed identity access.

If dependents live in another subscription, register Microsoft.MachineLearningServices in that subscription before the workspace can use them.

Minimal CLI create that auto-provisions dependents:

az extension add -n ml
az ml workspace create -n mlw-claims-dev -g rg-claims-dev -l eastus
az configure --defaults group=rg-claims-dev workspace=mlw-claims-dev location=eastus

Bring-your-own dependents with workspace YAML:

$schema: https://azuremlschemas.azureedge.net/latest/workspace.schema.json
name: mlw-claims-prod
location: eastus
storage_account: /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<sa>
key_vault: /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/<kv>
container_registry: /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.ContainerRegistry/registries/<acr>
application_insights: /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.insights/components/<ai>
public_network_access: Disabled
image_build_compute: cpu-build

Deploy with az ml workspace create -g rg-claims-prod -f workspace.yml. You may specify only some ARM IDs and let the CLI create the rest. Get IDs with az storage account show --query id, az keyvault show --query id, az acr show --query id, az monitor app-insights component show --query id.

Bicep for the Azure graph

Bicep declares Microsoft.Storage/storageAccounts, Microsoft.KeyVault/vaults, Microsoft.Insights/components, Microsoft.ContainerRegistry/registries, then:

resource workspace 'Microsoft.MachineLearningServices/workspaces@2024-10-01' = {
  name: workspaceName
  location: location
  identity: { type: 'SystemAssigned' }
  properties: {
    friendlyName: workspaceName
    storageAccount: storageAccount.id
    keyVault: keyVault.id
    applicationInsights: appInsights.id
    containerRegistry: acr.id
    publicNetworkAccess: 'Disabled'
  }
}

Use a current API version from the REST docs; Quickstart samples lag. Deploy:

az deployment group create -g rg-claims-prod --template-file main.bicep --parameters env=prod workspaceName=mlw-claims-prod

The Azure Quickstart machine-learning-workspace-vnet template also wires private endpoints, vnetOption new or existing, storageAccountBehindVNet, keyVaultBehindVNet, containerRegistryBehindVNet, and privateEndpointType AutoApproval or ManualApproval. It does not support multiple workspaces in the same VNet in one naive run because it creates DNS zones; export a portal deployment if you must share a VNet.

Customer-managed keys and high business impact (hbi_workspace) are create-time only in YAML (customer_managed_key.key_vault + key_uri; hbi_workspace: true). You cannot flip them later — you create a new workspace.

Compute and other workspace resources as code

After the workspace exists:

az ml compute create -f compute-cluster.yml
az ml compute create -f compute-instance.yml

YAML names the cluster, SKU, min/max nodes, and identity. Bicep can also emit compute child resources, but teams usually keep cluster size next to job YAML so data scientists can review it in the same pull request. Idempotence: az deployment group create with the same Bicep is safe to rerun. az ml workspace create on an existing name fails; use az ml workspace update -f workspace.yml for mutable settings (--public-network-access, --image-build-compute, --managed-network). az ml compute create is the create path; updates have their own commands.

Parameter files keep environments honest:

  • dev.bicepparam — public access enabled, small Standard_DS2_v2 cluster, no private endpoints.
  • prod.bicepparampublicNetworkAccess: Disabled, managed network allow_only_approved_outbound (section 4.4), Premium ACR, private endpoints.

Never copy-paste a prod workspace name into a dev template. Names, locations, and SKUs are parameters.

Traps that break “idempotent” templates

ARM/Bicep redeploys of Key Vault can clear access policies if the template specifies an empty accessPolicies array. Notebook VMs and other workspace features then fail against that vault. Microsoft’s template article says: do not redeploy the same Key Vault blindly; pass existing accessPolicies, or reuse the vault by resource ID and do not recreate it. That is why many production templates take keyVaultId as a parameter after the first create.

Soft-delete on the workspace means az ml workspace delete is recoverable unless you purge. Deleting the resource group deletes dependents too — storage, vault, ACR — which is usually not what you want if other services share them.

Exam scenario

Contoso needs identical dev and prod Azure Machine Learning landing zones. An engineer clicks through the portal for prod, then runs az ml workspace create -n mlw-dev with auto dependents. Prod uses a Premium_LRS storage account “for speed.” Training fails on the default datastore. The MLOps fix is a Bicep module with parameters env, workspaceName, and publicNetworkAccess; Standard_LRS (or Standard_GRS) without HNS for default storage; az ml workspace create -f workspace.yml only to attach those ARM IDs; az ml compute create for a named cpu-build cluster used as image_build_compute when ACR is private.

Common trap

Do not answer “Premium storage for the workspace default account” or “turn on Data Lake hierarchical namespace on the default store.” Those SKUs are unsupported for the default account. Do not delete ACR “to save money.” Do not put environment-specific workspace names in Bicep without parameters. Do not confuse az ml workspace create (workspace + optional dependents) with az deployment group create (full Azure graph including VNets).

Test Your Knowledge

You must create a production Azure Machine Learning workspace, a Standard_LRS storage account, Key Vault, Application Insights, Premium ACR, and a private endpoint on a virtual network, then create a CPU cluster. Which split matches Microsoft’s tools?

A
B
C
D
Test Your Knowledge

A template sets the workspace default storage account to an Azure Data Lake Storage Gen2 account (hierarchical namespace on) with SKU Premium_LRS. What is the documented constraint?

A
B
C
D
Test Your Knowledge

Dev and prod must reuse one Bicep file. Prod disables public network access and uses a larger cluster. What is the IaC pattern?

A
B
C
D