Build a Segmented Azure Network

Build a private Azure network and diagnose NSG and route failures.

Introduction

30 Second Summary

Private networks feel straightforward until a connection fails. Without a clear trail, every setting starts to look suspicious.

In this project, you will build a private two-tier virtual network in Microsoft Azure. You will use Azure diagnostics to identify deliberate security failures before proving each repair.

What You'll Build

You will watch web traffic change from denied to allowed while remote-login traffic remains blocked.

By the end of this project, you'll have:

  • A visible private topology where you can show both machines running on separate network segments without public internet exposure.
  • A repeatable traffic check that changes from Deny to Allow for TCP 80 after a higher-priority rule takes effect.
  • An Azure Network Watcher workflow that names the blocking security rule. The same workflow proves TCP 22 remains denied.
  • Secret Mission: Add a blackhole user-defined route. Use Next Hop to identify None before restoring the VirtualNetwork path.

Are there any prerequisites?

This project requires an active Azure subscription with permission to create its lab resources. Azure Portal launches the Bash environment in Azure Cloud Shell without a local installation.

Before We Start

Before the hands-on work begins, commit to the private segmented Azure two-tier network you are about to build. Your goal is to prove denied paths before showing that only the intended traffic can pass.

Verify Azure and Create the Lab Boundary

A command sent to the wrong Microsoft Azure subscription can place resources outside the account you meant to use. An unavailable VM size can stop the build after you have started.

A resource group gives the lab one boundary for cleanup. This step confirms the active session before creating that boundary.

In this step, get ready to:
  • Confirm the Azure Cloud Shell session targets your intended subscription.
  • Confirm Standard_B2ts_v2 availability in the selected region.
  • Create the tagged rg-azure-network-lab resource group.
Verify Cloud Shell and your subscription

Azure Cloud Shell provides a browser-based Bash environment with Azure commands already available. The az commands come from Azure CLI.

  • Open Azure Portal in your browser.
  • Sign in with the account that owns your intended personal subscription.
  • Select the Cloud Shell icon in the portal toolbar.
  • Select Bash when Cloud Shell asks you to choose an environment.
  • Verify the Azure CLI runtime and active subscription by running:
az version
az account show --output table

What do these checks prove?

  • The az version command confirms that Azure CLI is available in the Cloud Shell session.
  • The az account show --output table command identifies the default subscription for the current session.

You should see Azure CLI version details followed by a table for your intended personal subscription.

  • Keep this Bash session open for the remaining lab commands.

Seeing the wrong subscription?

  • Stop before creating any resources.
  • Return to Azure Portal to choose your intended personal subscription.
  • Return to the Bash session.
  • Repeat the subscription check above.

Help me verify the active Azure subscription in Cloud Shell. You can also share the non-sensitive table output with the NextWork community.

Set the lab variables and verify VM size

A VM size can vary by subscription or region. This check proves Standard_B2ts_v2 is available before the network build depends on it.

  • Set the reusable lab values and check VM size availability by running:
RG=rg-azure-network-lab
LOCATION=eastus
VM_SIZE=Standard_B2ts_v2

az vm list-skus \
  --location "$LOCATION" \
  --size "$VM_SIZE" \
  --output table

What do these values control?

  • The RG variable holds the resource group name used throughout the lab.
  • The LOCATION variable starts with eastus as the preferred region.
  • The VM_SIZE variable holds the required Standard_B2ts_v2 size.
  • The az vm list-skus command checks whether your subscription can use that size in the selected region.
  • Choose the tab that matches the table in Cloud Shell.

✔️ I see Standard_B2ts_v2

Good, your subscription can use Standard_B2ts_v2 in eastus. The active LOCATION value remains eastus.

ⓧ The table has no row

An empty table means this subscription did not return the required size in eastus. The lab uses eastus2 as the fallback region.

  • Change the active region and repeat the availability check by running:
LOCATION=eastus2

az vm list-skus \
  --location "$LOCATION" \
  --size "$VM_SIZE" \
  --output table

Why update the location?

Setting LOCATION=eastus2 directs later commands to the fallback region. The repeated check confirms the VM size before any resources are created.

You should now see a row containing Standard_B2ts_v2.

Still no VM size row?

Do not create the resource group in an unverified region. Your subscription may have a regional availability restriction.

Help me diagnose why Standard_B2ts_v2 is unavailable in eastus and eastus2. You can also share the non-sensitive command output with the NextWork community.

Create the tagged resource group

Azure uses the resource group to hold related lab resources under one name. The project=azure-network-lab tag records the group's purpose.

Creating your first lab resource can feel like the point where costs begin. These commands create the boundary only, so no VM compute or managed disks are added in this step.

Before you run this, predict the name and location that the resource group table will show.

  • Create the tagged resource group and display its details by running:
az group create \
  --name "$RG" \
  --location "$LOCATION" \
  --tags project=azure-network-lab

az group show --name "$RG" --output table

What do these commands do?

  • The first command creates rg-azure-network-lab in the confirmed location.
  • The project=azure-network-lab tag identifies the group as this project's lab boundary.
  • The second command returns the resource group details as a table.

You should see rg-azure-network-lab in a table with your confirmed location. That result proves the lab boundary exists in the active subscription.

Resource group missing?

  • Check the creation response for a permission problem.
  • Repeat the active subscription check from the first substep.
  • Repeat the resource group commands from the same Cloud Shell session.

Help me troubleshoot why rg-azure-network-lab was not created. You can also share the non-sensitive output with the NextWork community.

Your lab boundary is ready in a verified subscription. Next, you will build the private two-tier topology inside it.

Build the Private Two-Tier Network

The lab boundary from the previous step keeps this Microsoft Azure build contained in one resource group. Now you'll fill that boundary with a private admin tier plus a private app tier.

A virtual network supplies one private address space. Two subnets divide that space by role.

Fixed private IP addresses give later diagnostics stable endpoints. Application security groups label each network interface by workload role.

In this step, get ready to:
  • Create a virtual network with separate admin and app subnets.
  • Group the network interfaces by workload role.
  • Create two private virtual machines with Ubuntu Server.
Create the virtual network and subnets

CIDR notation defines the addresses available inside each network segment. The larger 10.20.0.0/16 range contains both smaller subnet ranges.

  • In the Cloud Shell session from earlier, assign the network address ranges by running these commands:
az network vnet create \
  --resource-group "$RG" \
  --location "$LOCATION" \
  --name vnet-lab \
  --address-prefixes 10.20.0.0/16 \
  --subnet-name snet-admin \
  --subnet-prefixes 10.20.1.0/24

az network vnet subnet create \
  --resource-group "$RG" \
  --vnet-name vnet-lab \
  --name snet-app \
  --address-prefixes 10.20.2.0/24

What do these commands create?

  • The first command creates vnet-lab with the private address space 10.20.0.0/16.
  • The same command creates snet-admin with the range 10.20.1.0/24.
  • The second command adds snet-app with the range 10.20.2.0/24.
  • Review the result from the second command.

You should see a successful result for snet-app inside vnet-lab. The network now has a dedicated segment for each workload role.

Network creation failed?

Confirm that RG still contains rg-azure-network-lab. Confirm that LOCATION still contains the region you verified earlier.

If Azure reports an overlapping address range, compare each prefix with the commands above. Each subnet must occupy its own range inside 10.20.0.0/16.

Help me fix the virtual network creation problem.

Create role groups and private NICs

An application security group acts as a role label for network policy. A network interface joins each VM to the correct subnet.

  • Create the admin and app role groups by running these commands:
az network asg create \
  --resource-group "$RG" \
  --location "$LOCATION" \
  --name asg-admin

az network asg create \
  --resource-group "$RG" \
  --location "$LOCATION" \
  --name asg-app

What do these role groups do?

The asg-admin group represents the admin role. The asg-app group represents the application role.

Later security rules can refer to these roles instead of listing individual IP addresses. That keeps the policy tied to workload purpose.

  • Review the result from each role-group command.

You should see a successful result with the matching group name after each command. The two role labels are ready for their network interfaces.

Role groups missing?

Check that both commands use the same RG value. Check that both commands use the verified LOCATION value.

Help me troubleshoot the missing application security groups.

  • Create the private network interfaces with fixed addresses by running these commands:
az network nic create \
  --resource-group "$RG" \
  --name nic-admin \
  --vnet-name vnet-lab \
  --subnet snet-admin \
  --private-ip-address 10.20.1.4 \
  --application-security-groups asg-admin

az network nic create \
  --resource-group "$RG" \
  --name nic-app \
  --vnet-name vnet-lab \
  --subnet snet-app \
  --private-ip-address 10.20.2.4 \
  --application-security-groups asg-app

How are the NICs separated?

  • The nic-admin interface joins snet-admin with the fixed address 10.20.1.4.
  • The nic-app interface joins snet-app with the fixed address 10.20.2.4.
  • Each interface receives the application security group that matches its workload role.
  • Review the result from the nic-app command.

You should see nic-app associated with snet-app at 10.20.2.4. Your two private endpoints now have stable addresses plus role membership.

NIC creation failed?

Confirm that the subnet names match snet-admin and snet-app exactly. Confirm that the role-group names match asg-admin and asg-app exactly.

If Azure reports an address conflict, confirm that each NIC uses the private address assigned in the commands above.

Help me diagnose the NIC creation failure.

Attach two private Linux VMs

The next action creates the lab's two billable VMs plus their managed OS disks. You can deallocate or delete them during cleanup, so you stay in control of ongoing charges.

Each command may take a few minutes while Azure allocates compute. Azure also attaches the OS disk during this process.

  • Create the two private VMs from their existing network interfaces by running these commands:
az vm create \
  --resource-group "$RG" \
  --name vm-admin \
  --nics nic-admin \
  --image Ubuntu2404 \
  --size "$VM_SIZE" \
  --admin-username azureuser \
  --generate-ssh-keys \
  --storage-sku Standard_LRS \
  --os-disk-delete-option Delete

az vm create \
  --resource-group "$RG" \
  --name vm-app \
  --nics nic-app \
  --image Ubuntu2404 \
  --size "$VM_SIZE" \
  --admin-username azureuser \
  --generate-ssh-keys \
  --storage-sku Standard_LRS \
  --os-disk-delete-option Delete

What do these VM settings control?

  • The --nics values attach each VM to the private interface created for its role.
  • The Ubuntu2404 image creates the Linux operating system for each VM.
  • The Standard_LRS value selects Standard HDD storage for each managed OS disk.
  • The --os-disk-delete-option Delete setting removes the matching OS disk when its VM is deleted.
  • Review the result from each VM creation command.

Each command should complete with a successful VM result. The VMs use the existing private NICs, so the lab does not create public IP resources for them.

VM creation still failing?

Confirm that VM_SIZE still contains Standard_B2ts_v2. Confirm that LOCATION still matches the region where you verified that size.

If a NIC cannot be attached, check whether its matching VM was already created during an earlier attempt. Each NIC can be attached to only one VM in this lab.

Help me troubleshoot the VM creation failure.

Before you run the final check, do you expect both VMs to show private addresses only?

  • Verify the running VMs plus their network addresses by running this command:
az vm list \
  --resource-group "$RG" \
  --show-details \
  --output table

What should I see?

  • The table contains rows for vm-admin and vm-app.
  • Both rows show VM running.
  • The admin VM shows the private address 10.20.1.4.
  • The app VM shows the private address 10.20.2.4.
  • Neither row shows a public IP address.

VM status not ready?

If one VM is missing, review the creation result for that VM above. Rerun its creation command after correcting the reported problem.

If a VM has not reached the running state, allow Azure to finish provisioning it. Rerun the final listing command afterward.

Help me understand the VM status table.

That's the network foundation complete. Both workload roles now have a running private VM on a dedicated subnet.

✔️ Awesome, I've got everything!

Great. Your two-tier network contains both private subnets, both role groups, both NICs, plus two running VMs.

ⓧ I'd like to double check the full code

  • Compare your Cloud Shell command history with this complete sequence:
az network vnet create \
  --resource-group "$RG" \
  --location "$LOCATION" \
  --name vnet-lab \
  --address-prefixes 10.20.0.0/16 \
  --subnet-name snet-admin \
  --subnet-prefixes 10.20.1.0/24

az network vnet subnet create \
  --resource-group "$RG" \
  --vnet-name vnet-lab \
  --name snet-app \
  --address-prefixes 10.20.2.0/24

az network asg create \
  --resource-group "$RG" \
  --location "$LOCATION" \
  --name asg-admin

az network asg create \
  --resource-group "$RG" \
  --location "$LOCATION" \
  --name asg-app

az network nic create \
  --resource-group "$RG" \
  --name nic-admin \
  --vnet-name vnet-lab \
  --subnet snet-admin \
  --private-ip-address 10.20.1.4 \
  --application-security-groups asg-admin

az network nic create \
  --resource-group "$RG" \
  --name nic-app \
  --vnet-name vnet-lab \
  --subnet snet-app \
  --private-ip-address 10.20.2.4 \
  --application-security-groups asg-app

az vm create \
  --resource-group "$RG" \
  --name vm-admin \
  --nics nic-admin \
  --image Ubuntu2404 \
  --size "$VM_SIZE" \
  --admin-username azureuser \
  --generate-ssh-keys \
  --storage-sku Standard_LRS \
  --os-disk-delete-option Delete

az vm create \
  --resource-group "$RG" \
  --name vm-app \
  --nics nic-app \
  --image Ubuntu2404 \
  --size "$VM_SIZE" \
  --admin-username azureuser \
  --generate-ssh-keys \
  --storage-sku Standard_LRS \
  --os-disk-delete-option Delete

az vm list \
  --resource-group "$RG" \
  --show-details \
  --output table

What does the full sequence build?

The commands build the two-subnet address plan first. They then add role-based NICs plus the two private VMs.

The final command displays the running state plus the private addresses. That table is your end-to-end topology check.

Your private topology is live. Next, you'll apply a subnet-level security policy that deliberately blocks the admin-to-app flow.

Make the Security Failure Visible

Your private Azure Virtual Network now separates the admin tier from the application tier. Both VMs are running on fixed private IP addresses.

A blanket role-to-role deny creates a clear security baseline. Its broad scope also blocks the required admin-to-app HTTP flow.

In this step, get ready to:
  • Protect the application subnet with a subnet-level NSG.
  • Create a blanket deny rule between the admin role and the application role.
  • Run IP flow verify to reveal the rule blocking inbound TCP 80.
Protect the application subnet

A network security group contains rules that allow or deny network traffic. Attaching one to snet-app applies its rules to resources in that subnet.

  • Switch back to Azure Cloud Shell.
  • Create nsg-app and attach it to snet-app by running these commands:
az network nsg create \
  --resource-group "$RG" \
  --location "$LOCATION" \
  --name nsg-app

az network vnet subnet update \
  --resource-group "$RG" \
  --vnet-name vnet-lab \
  --name snet-app \
  --network-security-group nsg-app

What do these commands do?

  • The first command creates the security policy container inside the resource group stored in RG.
  • The second command associates that policy with snet-app.
  • The subnet association extends the policy to nic-app because that NIC belongs to snet-app.
  • Confirm the NSG creation output names nsg-app.
  • Confirm the subnet update output references nsg-app on snet-app.

Good progress. Your application subnet now has a dedicated security boundary for the traffic test.

NSG association missing?

  • Check that RG still contains rg-azure-network-lab.
  • Check that the subnet name is snet-app.
  • Check that the virtual network name is vnet-lab.

Help me troubleshoot the missing NSG association.

Add the blanket deny rule

The existing application security groups let the policy target VM roles without listing individual IP addresses. Azure evaluates lower priority numbers before higher priority numbers.

Priority 200 places this custom deny before the default VNet inbound allowance at priority 65000.

  • Create the inbound role-to-role deny by running this command:
az network nsg rule create \
  --resource-group "$RG" \
  --nsg-name nsg-app \
  --name Deny-Admin-to-App \
  --priority 200 \
  --access Deny \
  --protocol "*" \
  --direction Inbound \
  --source-asgs asg-admin \
  --source-port-ranges "*" \
  --destination-asgs asg-app \
  --destination-port-ranges "*"

How does the deny rule work?

  • The source setting matches NICs in asg-admin.
  • The destination setting matches NICs in asg-app.
  • The wildcard protocol covers every supported protocol.
  • The wildcard port ranges cover every source port and destination port.
  • Priority 200 makes this rule take effect before the default VNet allowance.
  • Confirm the returned rule name is Deny-Admin-to-App.
  • Confirm the returned priority is 200.
  • Confirm the returned direction is inbound.
  • Confirm the returned access decision is deny.

The deliberate restriction is ready. Traffic from the admin role to the application role now meets a custom deny rule.

Rule creation failed?

  • Check that nsg-app exists in the resource group stored in RG.
  • Check that the source group is named asg-admin.
  • Check that the destination group is named asg-app.

Help me troubleshoot the NSG rule creation.

Prove the HTTP failure

Azure Network Watcher includes IP flow verify for evaluating security policy against a proposed packet. The result identifies the access decision plus the responsible rule.

  • List the available Network Watchers by running this command:
az network watcher list --output table

What does this check do?

The command lists the Network Watchers available to your subscription. IP flow verify needs one in the same region as vm-app.

✔️ A Network Watcher is listed in LOCATION

The table lists a Network Watcher in the region stored in LOCATION. Your region is ready for the diagnostic.

ⓧ No Network Watcher is listed in LOCATION

The table does not list a Network Watcher in the region stored in LOCATION. Enable one before running the diagnostic.

  • Enable Network Watcher inside the lab resource group by running this command:
az network watcher configure \
  --resource-group "$RG" \
  --locations "$LOCATION" \
  --enabled true

What does this command do?

The command enables Network Watcher in the region stored in LOCATION. It places the regional Network Watcher inside the resource group stored in RG.

  • Confirm the command output shows Network Watcher enabled in your selected region.

Your region can now run the traffic diagnostic against vm-app.

Network Watcher not enabling?

  • Check that your active subscription allows you to create networking resources.
  • Check that LOCATION matches the region containing vm-app.
  • Check that the resource group stored in RG still exists.

Help me enable Network Watcher in my VM region.

Before you run the test, which decision do you expect for inbound TCP traffic on port 80?

  • Test the admin-to-app flow by running this command:
az network watcher test-ip-flow \
  --resource-group "$RG" \
  --direction Inbound \
  --protocol TCP \
  --local 10.20.2.4:80 \
  --remote 10.20.1.4:60000 \
  --vm vm-app \
  --nic nic-app \
  --output table

What does this test evaluate?

  • The local endpoint represents port 80 on vm-app.
  • The remote endpoint represents a temporary source port on vm-admin.
  • The inbound direction evaluates traffic entering nic-app.
  • The table output identifies the rule that controls the proposed packet.

The table returns Deny. It names Deny-Admin-to-App as the matching rule.

This is the intended shortfall. The blanket rule blocks the required admin-to-app HTTP flow.

What has this test proved?

IP flow verify has proved that the network policy denies the proposed packet. It has also identified the exact rule responsible.

The diagnostic does not test whether an application is listening on port 80. This result focuses on traffic filtering.

Seeing an unexpected result?

  • Wait briefly for Azure to finish applying the NSG association.
  • Rerun the same IP flow verify command.
  • Check that the local endpoint is 10.20.2.4:80.
  • Check that the remote endpoint is 10.20.1.4:60000.
  • Check that nic-app still belongs to asg-app.

Help me diagnose the unexpected IP flow result.

You made the security failure visible and traced it to one custom rule. Next, you will inspect the effective policy before allowing only the required port.

Diagnose and Fix the NSG Rule

The denied TCP 80 result proves that the Deny-Admin-to-App network security group rule blocks the required flow. That result becomes useful once you can trace the rule to the effective policy on nic-app.

Azure Network Watcher gives you the evidence needed to trace the failure. You will use that evidence to add a narrower HTTP rule while preserving the deny for SSH.

In this step, get ready to:
  • Inspect the effective security rules applied to the application NIC.
  • Add a higher-priority exception for admin-to-app TCP 80 traffic.
  • Prove the exception allows HTTP while SSH remains denied.
Inspect the effective security rules

Effective security rules reveal every security policy that reaches a network interface. This view lets you confirm that the subnet-level nsg-app policy applies to nic-app.

  • Inspect the effective policy on nic-app by running this command:
az network nic list-effective-nsg \
  --resource-group "$RG" \
  --name nic-app \
  --output jsonc

What does this diagnostic show?

  • The list-effective-nsg diagnostic calculates the security rules that reach the running nic-app interface.
  • The output identifies nsg-app as the policy associated with snet-app.
  • The custom Deny-Admin-to-App entry confirms which rule produced the denied flow.
  • Find Deny-Admin-to-App in the output.
  • Confirm the surrounding association links nsg-app to snet-app.
  • Trace the subnet association through to nic-app.

That path proves the blanket deny reaches the application NIC through the application subnet.

Can't find the custom rule?

  • Wait briefly if the custom rule is missing from the effective output.
  • Run the diagnostic again after Azure finishes applying the subnet policy.
  • Confirm that the command targets nic-app inside $RG.

Help me trace the effective NSG applied to nic-app.

Add the narrow HTTP exception

Application security groups let a rule target the admin role and application role directly. A priority of 100 makes the narrow allow rule run before the blanket deny at priority 200.

  • Add the admin-to-app HTTP exception by running this command:
az network nsg rule create \
  --resource-group "$RG" \
  --nsg-name nsg-app \
  --name Allow-Admin-HTTP \
  --priority 100 \
  --access Allow \
  --protocol Tcp \
  --direction Inbound \
  --source-asgs asg-admin \
  --source-port-ranges "*" \
  --destination-asgs asg-app \
  --destination-port-ranges 80

How does the exception stay narrow?

  • Azure evaluates priority 100 before priority 200 because lower priority numbers run first.
  • Allow-Admin-HTTP applies only to inbound Tcp traffic with destination port 80.
  • asg-admin limits the source to the admin role.
  • asg-app limits the destination to the application role.

The Azure CLI response should show Allow-Admin-HTTP with priority 100, access Allow, protocol Tcp, and destination port 80.

Rule creation not completing?

  • Review the Cloud Shell response for a failed request.
  • Confirm that no existing custom rule in nsg-app uses priority 100.
  • Confirm that both asg-admin and asg-app still exist in $RG.

Help me diagnose why the NSG rule was not created.

Prove the intended access

Two tests reveal whether the new policy follows least privilege. The first checks HTTP while the second checks SSH with the same source role.

Before you run these checks, ask yourself which port the lower priority number will allow.

  • Run both port checks through Network Watcher by running these commands:
az network watcher test-ip-flow \
  --resource-group "$RG" \
  --direction Inbound \
  --protocol TCP \
  --local 10.20.2.4:80 \
  --remote 10.20.1.4:60000 \
  --vm vm-app \
  --nic nic-app \
  --output table

az network watcher test-ip-flow \
  --resource-group "$RG" \
  --direction Inbound \
  --protocol TCP \
  --local 10.20.2.4:22 \
  --remote 10.20.1.4:60000 \
  --vm vm-app \
  --nic nic-app \
  --output table

What do these checks compare?

  • The first diagnostic evaluates inbound TCP traffic from 10.20.1.4:60000 to 10.20.2.4:80.
  • The second diagnostic evaluates the same source against 10.20.2.4:22.
  • Each result identifies the first matching rule that decides the flow.

The TCP 80 result should show Allow through Allow-Admin-HTTP. The TCP 22 result should show Deny through Deny-Admin-to-App.

Still seeing the earlier result?

  • Wait briefly if either diagnostic still reports the policy state from the previous step.
  • Run both checks again after Azure finishes applying the new rule.
  • Compare the local port in each command against 80 and 22.

Help me troubleshoot the two IP flow verify results.

That is the key proof: your HTTP path is open while SSH remains blocked.

Secret mission

Break and Repair the Route

Create a temporary blackhole route. Use Azure Network Watcher to expose the None next hop. Remove the bad route to restore the VirtualNetwork path.

Clean Up Your Resources

Clean Up Your Resources

Choose whether to keep the lab available, pause its compute, or delete every Microsoft Azure resource in one action. The two virtual machines and managed OS disks can continue to incur charges.

Cost warning

The running vm-admin and vm-app VMs can continue to generate compute charges. Their managed OS disks are billed separately.

Deallocation stops VM compute charges. Disk charges continue until you delete the resource group.

  • Choose the pause option if you plan to return to the lab.
  • Choose the delete option when you have finished using the lab.

Resources you used:

  • Azure resource group rg-azure-network-lab containing the complete lab boundary.
  • Private virtual network vnet-lab with the address space 10.20.0.0/16.
  • Two subnets named snet-admin and snet-app.
  • Two application security groups named asg-admin and asg-app.
  • Subnet-level network security group nsg-app with its allow and deny rules.
  • Two private network interfaces named nic-admin and nic-app.
  • Two Ubuntu virtual machines named vm-admin and vm-app with their managed OS disks.
  • Route table rt-admin attached to snet-admin.

Keep everything running

No action needed. Choose this if you are still using the network or want to repeat the diagnostics later.

  • Keep vm-admin and vm-app running when you want immediate access to the lab.
  • Monitor your Azure costs while both VMs remain active.
  • Delete the resource group as soon as you finish using the lab.

Pause - I'll come back to this later

Shut down the running VMs to stop compute charges while preserving the lab. This is reversible, so you can start the VMs again later.

  • In the Azure Cloud Shell session from earlier, deallocate both VMs by running these commands:
az vm deallocate --resource-group "$RG" --name vm-admin
az vm deallocate --resource-group "$RG" --name vm-app

What does deallocation change?

The az vm deallocate command moves each VM to Stopped (Deallocated). Compute charges stop in that state.

Both managed disks remain allocated. Their storage charges continue.

Good call. Your VM compute is paused while the network configuration and disks stay ready for another session.

Delete - I don't want to use this again

Deleting the resource group is permanent. The single command removes the entire lab boundary, which prevents chargeable VMs or disks from being left behind.

  • In the Cloud Shell session from earlier, delete rg-azure-network-lab by running this command:
az group delete \
  --name "$RG" \
  --yes \
  --no-wait

What does this command remove?

The az group delete command removes rg-azure-network-lab plus every resource it contains. This includes both VMs and their managed OS disks.

The same deletion removes the virtual network, subnets, security groups, network interfaces, and route table. One cleanup boundary prevents leftover resources.

Your cleanup request is submitted. Azure now removes the complete networking lab.

Nice Work!

Nice Work!

You did it! You built a private two-tier network in Microsoft Azure. Your segmented virtual network now demonstrates secure traffic filtering through repeatable diagnostics.

What you learned:

  • Built a private two-tier virtual network with separate admin and application subnets. Deployed two Ubuntu virtual machines with fixed private IP addresses. Kept both machines private by omitting public IP resources.
  • Used application security groups to assign admin and application roles to each NIC. Applied a subnet-level network security group whose priorities allow TCP 80 while TCP 22 stays denied.
  • Used Azure Network Watcher IP flow verify to trace the denied flow to Deny-Admin-to-App. Confirmed the applied subnet policy with effective security rules.
  • Secret Mission: diagnosed a blackhole user-defined route with Next Hop and effective routes. Deleted Blackhole-App to restore the VirtualNetwork path.

Ready to quiz yourself?