Capstone: place three workloads by service type, under a budget and a location rule
Task
A small company is moving three workloads to Azure: a legacy Linux server that needs its operating system under the company's control, a simple public website, and staff email. Place each one in the right service type and build the first two for real, inside one tagged resource group with a governance rule that keeps everything in one region. The server is IaaS: one small virtual machine with no public IP address and no inbound rule, whose pending operating system updates you read yourself. The website is PaaS: an App Service web app on the F1 Free tier. Email is SaaS, which you describe rather than build. Along the way you use the consumption-based model by deallocating the VM, and you finish with a shared responsibility table for all three workloads. This capstone draws on lessons 1 to 4, and the clean-up removes everything it made.
Steps
- Confirm your safety net and record one starting fact. In Cloud Shell (Bash), check that lesson 1's budget is still there, and whether your subscription already has the resource group Azure uses for Network Watcher:
az consumption budget show --budget-name az900-monthly-budget --query name -o tsv
az group exists --name NetworkWatcherRG
The first prints az900-monthly-budget; if it does not, do lesson 1's lab first. Write down what the second prints, true or false. When the first virtual network in a region appears, Azure turns on Network Watcher, a free network monitoring service, in a resource group of its own, and the clean-up uses your note. Then create the lab's resource group, with tags that say what it is for:
az group create --name az900-cap1-rg --location eastus --tags project=az900-cap1 costcentre=training
- Add the governance rule before anything is built (lesson 3). Assign the built-in policy "Allowed locations" to this resource group, allowing
eastusonly:
az policy assignment create --name az900-cap1-allowed-locations --display-name "Allowed locations: eastus only" --policy e56962a6-4747-49cd-b67b-bf8b01975c4c --resource-group az900-cap1-rg --params '{"listOfAllowedLocations": {"value": ["eastus"]}}'
It can take some minutes to start denying requests; step 6 tests it. 3. Build the legacy server's network (IaaS). Create a virtual network with one subnet, a network security group (NSG), and attach the NSG to the subnet:
az network vnet create --resource-group az900-cap1-rg --name az900-cap1-vnet --location eastus --address-prefixes 10.10.0.0/16 --subnet-name legacy --subnet-prefixes 10.10.1.0/24
az network nsg create --resource-group az900-cap1-rg --name az900-cap1-nsg --location eastus
az network vnet subnet update --resource-group az900-cap1-rg --vnet-name az900-cap1-vnet --name legacy --network-security-group az900-cap1-nsg
az network nsg rule list --resource-group az900-cap1-rg --nsg-name az900-cap1-nsg --query 'length(@)' -o tsv
The last command prints 0: you add no rule, because this server needs no inbound access. The NSG's built-in default rules still deny inbound traffic from outside the virtual network. Deciding which traffic may reach the company's machines is the customer's job in IaaS, even though Microsoft owns the network hardware. 4. Create the server: one small Linux VM with no public IP address and no inbound rule. SSH keys are generated inside your Cloud Shell session, and you never need them, because nothing will sign in over the network:
az vm create --resource-group az900-cap1-rg --name az900-cap1-vm --location eastus --image Ubuntu2204 --size Standard_B1s --vnet-name az900-cap1-vnet --subnet legacy --public-ip-address "" --nsg-rule NONE --storage-sku Standard_LRS --admin-username azureuser --generate-ssh-keys --tags workload=legacy servicetype=IaaS
It takes a few minutes and ends with "publicIpAddress": "". If Azure replies that the size is not available in your region (SkuNotAvailable), run the same command with --size Standard_B2s and expect that size in Verify. 5. Do the customer's IaaS duty, then use the consumption model. Ask the VM's agent how many lines of pending updates the guest operating system lists, without signing in to it:
az vm run-command invoke --resource-group az900-cap1-rg --name az900-cap1-vm --command-id RunShellScript --scripts "apt list --upgradable 2>/dev/null | wc -l" --query 'value[0].message' -o tsv
The output shows [stdout] and a number. Whatever it is, applying those updates is the company's job on IaaS, not Microsoft's; this lab reads them and installs nothing. Now stop paying for the VM's compute while it is not needed:
az vm deallocate --resource-group az900-cap1-rg --name az900-cap1-vm
az vm show --resource-group az900-cap1-rg --name az900-cap1-vm --show-details --query powerState -o tsv
It prints VM deallocated. Compute charges stop, but the OS disk is still billed for as long as it exists: only deleting it ends that, which the clean-up does. 6. Build the website (PaaS), then test the governance rule. Create an F1 plan and a web app on it, make it HTTPS only, and request it:
az appservice plan create --name az900-cap1-plan --resource-group az900-cap1-rg --location eastus --sku F1 --tags servicetype=PaaS
az webapp create --name az900cap1webNNNNN --resource-group az900-cap1-rg --plan az900-cap1-plan --tags workload=web servicetype=PaaS
az webapp update --name az900cap1webNNNNN --resource-group az900-cap1-rg --https-only true
curl -s -o /dev/null -w '%{http_code}' https://$(az webapp show --name az900cap1webNNNNN --resource-group az900-cap1-rg --query defaultHostName -o tsv)
The last command prints 200. You chose no operating system and will patch none. Now try to put a plan in another region:
az appservice plan create --name az900-cap1-plan-west --resource-group az900-cap1-rg --location westus --sku F1
Azure refuses it with RequestDisallowedByPolicy. If it is created instead, the assignment had not taken effect yet, and the group delete at the end removes it. 7. Place the third workload, staff email, without building it. It is SaaS: a finished product such as Microsoft 365, bought on a subscription, and this capstone signs up for nothing. Read the identity that SaaS would still leave to the company, then list what you built with its service type tag:
az ad signed-in-user show --query userPrincipalName -o tsv
az resource list --resource-group az900-cap1-rg --query '[].{name:name, type:type, servicetype:tags.servicetype}' -o table
Now write a table with three columns, the legacy server (VM), the website (App Service) and staff email (Microsoft 365), and six rows: who patches the operating system, who writes the application code, who sets which network traffic is allowed, who decides who can sign in, who owns the data, and who secures the datacenter. Write Microsoft, Customer or Shared in each cell, then check your answers in the Notes. 8. Look at the cost side. In the portal, open Cost Management > Cost analysis with your subscription as the scope and group by resource group. Costs usually appear some hours after use, so today's minutes may not show yet; look again tomorrow, after the clean-up, to see what this capstone cost. In the Azure pricing calculator, add a Virtual Machines estimate for one B1s Linux VM and compare a whole month with the minutes you actually ran it: under the consumption-based model you pay for the time it ran. Write down no figures, because prices change.
Verify
Check each part of the build:
az vm show --resource-group az900-cap1-rg --name az900-cap1-vm --query hardwareProfile.vmSize -o tsv
Expected output: Standard_B1s (or Standard_B2s if you used it in step 4).
az network public-ip list --resource-group az900-cap1-rg --query 'length(@)' -o tsv
Expected output: 0: nothing in the lab has a public IP address.
az network nsg rule list --resource-group az900-cap1-rg --nsg-name az900-cap1-nsg --query 'length(@)' -o tsv
az network nsg rule list --resource-group az900-cap1-rg --nsg-name az900-cap1-vmNSG --query 'length(@)' -o tsv
Expected output: 0 from each: neither network security group has a custom rule.
az vm show --resource-group az900-cap1-rg --name az900-cap1-vm --show-details --query powerState -o tsv
Expected output: VM deallocated.
az webapp show --name az900cap1webNNNNN --resource-group az900-cap1-rg --query httpsOnly -o tsv
Expected output: true.
az policy assignment show --name az900-cap1-allowed-locations --resource-group az900-cap1-rg --query 'parameters.listOfAllowedLocations.value[0]' -o tsv
Expected output: eastus.
Cost and clean-up
Charges are possible, and this is the one lab in the first skill area that runs a virtual machine. The B1s VM is billed for compute while it runs and its OS disk for as long as it exists, until the clean-up deletes them. The F1 plan, the virtual network, the network security groups, the tags and the policy assignment carry no charge. Do the clean-up in the same sitting, and use the pricing calculator rather than this page for rates.
Created by this lab: the resource group az900-cap1-rg, tagged; the policy assignment az900-cap1-allowed-locations on it; the virtual network az900-cap1-vnet with its subnet legacy; the network security group az900-cap1-nsg, attached to the subnet; the VM az900-cap1-vm with its OS disk, its network interface and the network security group az900-cap1-vmNSG the CLI made for that interface; the App Service plan az900-cap1-plan and the web app az900cap1webNNNNN; the App Service plan az900-cap1-plan-west, only if step 6 ran before the policy took effect; the resource group NetworkWatcherRG and the Network Watcher in it, only if step 1 printed false for it.
- Delete the policy assignment first. It is not an ordinary resource in the group, so remove it by name:
az policy assignment delete --name az900-cap1-allowed-locations --resource-group az900-cap1-rg
- Delete the resource group. This deletes the VM
az900-cap1-vmtogether with its OS disk and network interface, the network security groupsaz900-cap1-nsgandaz900-cap1-vmNSG, the virtual networkaz900-cap1-vnetand its subnetlegacy, the plansaz900-cap1-planand, if it exists,az900-cap1-plan-west, and the web appaz900cap1webNNNNN. Deleting the group, rather than the VM alone, is what removes the disk and the network interface, which would otherwise stay and be billed. It takes several minutes:
az group delete --name az900-cap1-rg --yes
- Only if step 1 printed
falseforNetworkWatcherRG: Azure created it for this lab's virtual network, so delete it as well. If step 1 printedtrue, it was there before and other networks may use it, so leave it alone.
az group delete --name NetworkWatcherRG --yes
Check it is gone
az group exists --name az900-cap1-rg
Expected output: false.
If you ran clean-up step 3, az group exists --name NetworkWatcherRG also prints false.
Notes
Step 7 answers, in the order VM, App Service, Microsoft 365. Patching the operating system: Customer, Microsoft, Microsoft. Writing the application code: Customer, Customer (the company's code on Microsoft's runtime, so Shared is also a fair answer), Microsoft. Network traffic rules: Customer, Shared, Microsoft. Who can sign in: Customer in all three. The data: Customer in all three. Securing the datacenter: Microsoft in all three. The customer's share is largest with IaaS and shrinks as the service becomes more managed, but data, devices, and accounts and identities never leave it.
Why each workload landed where it did: the legacy server needs control of its operating system, which only IaaS gives; the website needs no server management, which is PaaS; email is a standard need someone already sells, which is SaaS. One organisation running all three at once is normal, because service types are chosen per workload.
Deallocating the VM in step 5 is the consumption-based model from lesson 2 at work: compute stops being billed when you stop using it. A reservation would have charged for the whole term whether the VM ran or not.
This is an independent study companion for the Microsoft Azure Fundamentals (AZ-900) exam and is not produced by or endorsed by Microsoft. Microsoft, Azure and Microsoft Entra are trademarks of the Microsoft group of companies.
This is an independent study companion for Microsoft Azure Fundamentals AZ-900 and is not produced by or endorsed by CompTIA.