Skip to content

CLZ-390 - Final Windows Reference Architecture

Final Windows Reference Architecture architecture
Service or workflow illustration. The lesson defines the exact resource settings. Open at full size.

Goal

Combine reusable network and Windows VMSS modules with a Standard Load Balancer, explicit outbound behavior, subnet NSG, Azure Bastion, Key Vault, and Log Analytics into one reviewable capstone.

CLZ-390 learning sequence
Arrows show the learning sequence, not service traffic. Capstone Azure deployment. Open at full size.

Prerequisites

  • Complete CLZ-210, CLZ-260, CLZ-340, and CLZ-360.
  • Quota and budget for Bastion plus the selected VMSS maximum size/count.
  • Your current public IPv4 /32 for Key Vault access.
  • Destroy older capstone deployments before adopting the suffixed Key Vault name.

Architecture

CLZ-390 — Public HTTP passes through the Standard Load Balancer and web NSG to private IIS VMSS instances; Bastion supplies the separately admitted RDP path. A generated password feeds VMSS and Key Vault and remains in state. Outbound SNAT is explicit. Log Analytics is a workspace without telemetry wiring; autoscale and managed TLS are production additions.
Lesson-specific teaching diagram. Read the arrow legend and the accompanying architecture explanation. Capstone Azure deployment. On narrow screens, scroll the diagram horizontally. Open at full size.

The network module creates the VNet and workload subnets. A web-subnet NSG admits public HTTP for the Standard Load Balancer path and RDP only from AzureBastionSubnet. The VMSS module supplies IIS, probe, inbound rule, and explicit outbound rule. Bastion provides private administration; Key Vault stores the generated credential; Log Analytics creates the observability boundary.

Resources And Cost

Relative cost: High. Bastion and VMSS instances dominate; disks, public IPs, Log Analytics ingestion, Key Vault operations, and outbound traffic also contribute.

Component Purpose and principal cost driver
Network module and web NSG VNet/subnets plus explicit HTTP and Bastion-only RDP policy.
Windows IIS VMSS module Validated size/count, Standard Load Balancer, health probe, and explicit outbound rule.
Azure Bastion and public IP Private RDP management path with an hourly charge.
Key Vault and generated secret Stable suffixed vault restricted to the supplied /32; sensitive value remains in state.
Log Analytics workspace Monitoring foundation; ingestion/retention determines ongoing cost.

Inputs

Input Required substitution or decision
subscription_id Required for Azure plan, apply, and destroy; use the exact subscription GUID.
environment Keep dev for an ephemeral lab unless testing another environment boundary.
location Choose a supported region with sufficient quota.
name_prefix Use a short lowercase prefix for derived names.
admin_username Nonreserved administrator name used by VMSS.
vm_size Small Windows size supported in the selected region.
instance_count Positive integer; keep the capstone small because it multiplies VM/disk cost.
key_vault_access_cidr Required current public IPv4 /32 for lab secret administration.

Keep real subscription IDs, CIDRs, endpoint names, and secrets in untracked local files or protected repository settings.

Deploy

Review the plan and lesson-specific gates before deliberate execution. Local-only and read-only lessons create no Azure resources.
Review the plan and lesson-specific gates before deliberate execution. Local-only and read-only lessons create no Azure resources. Open at full size.

Run from the repository root in PowerShell 7:

Set-Location CLZ-390-final-windows-reference-architecture
if (-not (Test-Path terraform.tfvars)) {
  Copy-Item terraform.tfvars.example terraform.tfvars
}
$subscriptionId = az account show --query id --output tsv
terraform init -lockfile=readonly
terraform fmt -check
terraform validate
terraform plan -var "subscription_id=$subscriptionId" -out tfplan
terraform show tfplan
terraform apply tfplan

Validate

The shared VMSS module uses a Manual upgrade policy. An IIS extension added to the model may require explicitly updating existing instances. Review the instance model and extension status before expecting healthy HTTP responses:

$resourceGroup = terraform output -raw resource_group_name
$scaleSetName = az vmss list --resource-group $resourceGroup --query '[0].name' --output tsv
az vmss list-instances --resource-group $resourceGroup --name $scaleSetName --expand instanceView --output json
# Deliberate Azure change: update these lab instances to the latest model after review.
az vmss update-instances --resource-group $resourceGroup --name $scaleSetName --instance-ids '*'

Follow Microsoft's VMSS application deployment guidance. Wait for successful extension execution and probe health before checking HTTP.

$resourceGroup = terraform output -raw resource_group_name
$url = terraform output -raw capstone_load_balancer_url
(Invoke-WebRequest -Uri $url -UseBasicParsing).StatusCode
$nsg = terraform output -raw web_network_security_group_name
az network nsg rule list --resource-group $resourceGroup --nsg-name $nsg --query '[].{name:name,source:sourceAddressPrefix,port:destinationPortRange,access:access}' --output table
az network bastion list --resource-group $resourceGroup --query '[].provisioningState' --output tsv
az keyvault show --name (terraform output -raw key_vault_name) --query properties.provisioningState --output tsv
$lb = az network lb list --resource-group $resourceGroup --query '[0].name' -o tsv
az network lb outbound-rule list --resource-group $resourceGroup --lb-name $lb --output table

Expected result:

  • HTTP returns 200 through the Load Balancer and healthy VMSS.
  • The web NSG contains the HTTP path and RDP is restricted to the Bastion subnet rather than an Internet CIDR.
  • Bastion and Key Vault are Succeeded, and the Load Balancer has an explicit outbound rule.

Troubleshooting

Gather evidence, repair the cause, and rerun verification.
Gather evidence, repair the cause, and rerun verification. Open at full size.
Symptom Resolution
HTTP fails after apply Wait for VMSS extension/probe health, then inspect NSG, backend pool, and instance view.
Bastion cannot reach an instance Check the Bastion subnet, web NSG RDP source, VMSS instance health, and credentials.
Key Vault returns Forbidden Update the required /32, verify applying identity/policy, and allow propagation time.

Cleanup

Use the lesson state and cleanup instructions. Preserve remote-state dependencies until consumers are removed.
Use the lesson state and cleanup instructions. Preserve remote-state dependencies until consumers are removed. Open at full size.
$resourceGroup = terraform output -raw resource_group_name
terraform destroy -var "subscription_id=$subscriptionId"
terraform state list
az group exists --name $resourceGroup

All high-cost Bastion, VMSS, Load Balancer, public IP, disk, vault, workspace, and network resources are removed; Azure CLI returns false.

Production Delta

  • Enable Key Vault purge protection, RBAC/private access, managed identity secret retrieval, rotation, and protected remote state.
  • Add filtered egress, TLS/application gateway or Front Door as required, hardened images, patching, backup, zone resilience, autoscale, diagnostics, alerts, and tested recovery.
  • Split platform, network, security, data, and workload lifecycles/states with reviewed module versions and least-privilege deployment identities.

Exercises

  1. Use CLI-only evidence to prove every acceptance criterion without relying on the portal.
  2. Produce a production gap list ranked by security risk, availability impact, operational effort, and cost.

← CLZ-380 - Azure SQL Private Access | Curriculum | Curriculum →