Last reviewed: May 2026
Build the AWS services on the AZ-120 exam with plain Terraform — one block at a time, each tied back to an exam domain. The same code works on OpenTofu.
By the end of this lab you'll have provisioned, with plain Terraform, the Azure SAP reference architecture scaffolding — a VNet with app and DB subnets, a Proximity Placement Group anchoring co-located resources for low-latency SAP <-> HANA traffic, an Availability Set for the application tier's fault domains, a premium SSD managed disk shape for HANA's storage requirements, and a private DNS zone for the SAP hostnames.
We deliberately don't provision the SAP-certified large VMs (Mv2 / E-series, easily $1000+/month). Once this scaffolding exists, SAP VMs plug into the Availability Set + Proximity Placement Group + disk shape via standard azurerm_linux_virtual_machine resources sized appropriately.
Drop the snippets into a single main.tf, run terraform init, then terraform apply step-by-step.
>= 1.5 or OpenTofu >= 1.6.az login).Lab scaffolding is essentially free (no VMs):
~$20/month idle for the disk alone. If you actually deploy SAP-certified VMs (Mv2 series have 2-12 TB RAM, E-series 64+ GB RAM), expect $1,000–$15,000/month per VM. Don't provision SAP VMs in lab subscriptions unless you've signed a real Azure budget commit.
Standard Azure opener. AZ-120 expects you to pick a region that's certified for SAP and supports the M-series VMs you'll need — eastus2, westeurope, northeurope are the safest bets.
terraform {
required_version = ">= 1.5"
required_providers {
azurerm = { source = "hashicorp/azurerm", version = "~> 4.0" }
}
}
provider "azurerm" {
features {}
}
locals {
tags = {
Project = "certlabpro-az-120"
ManagedBy = "terraform"
Workload = "SAP"
}
}
resource "azurerm_resource_group" "main" {
name = "certlabpro-az-120-rg"
location = "eastus2"
tags = local.tags
}SAP architectures on Azure separate application servers (medium-CPU, modest memory) from the HANA database (very large memory) into distinct subnets — usually with stricter NSGs on the DB tier. AZ-120 tests this tier separation: app subnet exposes SAP services to users (or a load balancer); DB subnet is internal-only, accessible only from the app tier.
We carve app and db subnets out of a /16 VNet. NSGs are out of scope for the lab (would be straightforward to add — same pattern as AZ-104 Step 2).
resource "azurerm_virtual_network" "sap" {
name = "vnet-sap"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
address_space = ["10.0.0.0/16"]
tags = local.tags
}
resource "azurerm_subnet" "app" {
name = "app"
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.sap.name
address_prefixes = ["10.0.1.0/24"]
}
resource "azurerm_subnet" "db" {
name = "db"
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.sap.name
address_prefixes = ["10.0.2.0/24"]
}Proximity Placement Groups (PPGs) are the AZ-120 Design and implement infrastructure to support SAP answer for ultra-low-latency between SAP application servers and HANA. PPG-co-located VMs land in the same datacenter (literally same rack), giving < 1ms inter-VM latency — required for SAP's HANA-app communication.
Availability Sets group VMs across fault domains (separate power/network rails) within a single datacenter. The combination — PPG for latency, Availability Set for fault tolerance — is the AZ-120 reference shape for the SAP application tier. (For zonal availability, Azure now also supports placing all VMs in the same Availability Zone via PPG + zone — the more modern pattern.)
resource "azurerm_proximity_placement_group" "sap" {
name = "ppg-sap"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
tags = local.tags
}
resource "azurerm_availability_set" "app" {
name = "avset-sap-app"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
platform_fault_domain_count = 2 # max for the region
platform_update_domain_count = 5
proximity_placement_group_id = azurerm_proximity_placement_group.sap.id
managed = true
tags = local.tags
}HANA's storage requires premium SSD or higher (P-series tier) for production workloads — the SAP-certified IOPS and throughput specs assume P30+ disks for HANA data/log. AZ-120's Design and implement infrastructure to support SAP tests the disk-tier selection as a recurring cost / performance trade-off.
We provision one P10 (128 GB) managed disk as a shape demonstration — small + cheap, but the same Premium_LRS storage account type a production HANA disk would use. Attaching it to a VM is a separate step (out of scope here). For production HANA, you'd use P30 / P40 disks and stripe multiple together via LVM for the throughput SAP demands.
resource "azurerm_managed_disk" "hana_data_shape" {
name = "disk-hana-data-shape"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
storage_account_type = "Premium_LRS" # SAP-certified storage tier
create_option = "Empty"
disk_size_gb = 128 # P10 size — demonstration only; production HANA uses P30+
tags = local.tags
}SAP installations rely heavily on stable, predictable hostnames (sapha01, sapha02, sapdb01) — the SAPHostAgent and HANA System Replication both require consistent hostname resolution. AZ-120's Design and implement Azure compute and storage solutions tests Private DNS as the answer for intra-VNet hostname stability without manual /etc/hosts editing.
We create the SAP zone and link it to the VNet from Step 2 with registration_enabled = true so SAP VMs auto-register their hostnames. With this final piece in place, the scaffolding is complete: VNet with tiered subnets, PPG anchoring co-location, Availability Set for fault tolerance, premium-disk shape for HANA storage, Private DNS for hostname stability. SAP VMs deploy into this base via standard azurerm_linux_virtual_machine resources.
resource "azurerm_private_dns_zone" "sap" {
name = "sap.internal"
resource_group_name = azurerm_resource_group.main.name
tags = local.tags
}
resource "azurerm_private_dns_zone_virtual_network_link" "sap" {
name = "sap-vnet-link"
resource_group_name = azurerm_resource_group.main.name
private_dns_zone_name = azurerm_private_dns_zone.sap.name
virtual_network_id = azurerm_virtual_network.sap.id
registration_enabled = true
tags = local.tags
}terraform destroy tears down everything. The premium managed disk ($20/month) is the only line item billing 24/7 — destroy promptly. PPG and Availability Set are metadata-only and destroy instantly. Private DNS zones with no records destroy cleanly.
AZ-120 covers SAP-specific surfaces this lab can't fit — the actual SAP VMs (Mv2-series for HANA at $5–$15K/month each, E-series for app servers), HANA Large Instances (bare-metal HANA on Azure-managed hardware), SAP on Azure HA + DR (ASCS/ERS Pacemaker clusters), Azure NetApp Files (premium-tier NFS for /hana/shared), ExpressRoute for hybrid connectivity, Azure Site Recovery for cross-region DR, Azure Backup for SAP HANA, Azure Monitor for SAP solutions (the SAP-specific monitoring add-on), and the Azure Center for SAP Solutions (ACSS) provisioning automation.
We stick to the infrastructure scaffolding because the SAP-specific VM SKUs are cost-prohibitive for a lab subscription. The scaffolding above (VNet, PPG, Availability Set, premium disk, Private DNS) is exactly what every AZ-120 reference architecture starts with — your SAP VMs plug into this base.
For the SAP-VM-specific patterns, see the Browse, Playbook, and Editorial sections of this cert page.