8. Interview Questions
Three tiers, with answer keys. Write your own answer before opening the block — the gap between what you said and what's written is the thing worth studying.
Tier 1 — Conceptual
1. What is an Azure Virtual Network, and what problem does it solve?
Answer
A VNet is a regional, software-defined private network: you declare one or more private CIDR address ranges, carve them into subnets, and every resource placed in those subnets gets a private IP and can communicate with its neighbours.
The problem it solves is that networks used to be physical and therefore slow to change — VLANs, cabling, appliances, change windows. A VNet makes network topology a set of ARM resources you can create, review in a pull request, and destroy.
The structurally important part is that isolation is the default. Two VNets you haven't explicitly connected cannot reach each other, even in the same subscription and region. Compare a flat on-premises network, where "everything reaches everything" is the starting state and segmentation is a project.
The other thing worth saying: there's no device. Enforcement happens in the hypervisor host's software-defined networking stack on every machine, which is why NSG rules cost no bandwidth and why there's nothing to log into.
2. Explain the resource hierarchy — VNet, subnet, NIC — and how it relates to resource groups and subscriptions.
Answer
A VNet is a regional ARM resource in a resource group, in a subscription, in a tenant. It owns
one or more CIDR address ranges. Subnets are child resources of the VNet
(Microsoft.Network/virtualNetworks/subnets), each holding a block inside the VNet's address space.
A NIC is a separate, top-level ARM resource — not a child of the subnet — that references one
subnet and carries one or more IP configurations.
Two things worth calling out:
- The VNet is regional and spans all availability zones in that region. A subnet is not zonal. Zone placement is a property of the VM or load balancer, never of the subnet.
- The NIC being its own resource means it survives the VM, can be detached, and can carry its own NSG separate from the subnet's.
Resource groups don't constrain networking: a NIC can be in a different resource group from the VNet it joins, and a VNet in one subscription can peer with one in another. What the subscription does constrain is quota — most networking limits are counted per subscription per region — and RBAC scope.
3. What are the five reserved addresses in every subnet, and how many usable addresses does a /24 give you?
Answer
For 10.0.1.0/24: .0 is the network address, .1 is the default gateway, .2 and .3 are
reserved by Azure to map the platform DNS service into the subnet, and .255 is the broadcast
address. So a /24 gives 251 usable addresses, not 254.
The practical consequences: the smallest usable subnet is a /29 (three usable addresses)
⚠️ verify the current minimum against current Azure docs, and small subnets waste a large proportion
of their space — a /29 loses five of eight.
4. When would you use VNet peering versus Azure Virtual WAN?
Answer
Peering for a small number of VNets with a simple hub. It's the cheapest, lowest-latency option, it's just a pair of resources, and it's the right default up to roughly a couple of dozen spokes.
Virtual WAN when you'd otherwise be hand-building the thing it gives you: transitive any-to-any routing across regions, branch-office VPN termination at scale, integrated ExpressRoute, and managed routing that doesn't require a UDR in every spoke.
The forcing function is non-transitivity. Peering A↔H and B↔H does not give you A↔B. To make spoke-to-spoke work with plain peering you need a routing device in the hub — Azure Firewall, an NVA, or Route Server — plus a UDR in each spoke pointing at it. Once you're managing dozens of peerings and their UDRs by hand, Virtual WAN is doing that for you and is worth the price.
5. What are you billed for in Azure networking, and what keeps billing when nothing is using it?
Answer
Free: the VNet, subnets, NSGs, ASGs, route tables. That's genuinely misleading — the free part is the part you design.
Billed: Azure Firewall (per deployment-hour plus per GB — usually the largest line), VPN and ExpressRoute gateways (per hour by SKU), Bastion (per hour), NAT Gateway (hour + GB), Standard public IPs (hourly, attached or not), private endpoints (hourly each + GB), peering data (per GB, charged on both sides, more across regions), and internet/cross-region egress.
What keeps billing when idle: essentially all of it. Firewalls, gateways, Bastion, NAT Gateways, public IPs, and private endpoints are hourly resources that run continuously. This is the opposite shape from compute — turning off dev VMs barely moves an Azure network bill.
The two findings I'd look for first in any subscription: orphaned Standard public IPs from deleted VMs, and a firewall or gateway per spoke instead of one shared in a hub.
Tier 2 — Technical depth
1. Walk me through what happens when a VM sends a packet to a private endpoint in the same VNet.
Answer
- DNS. The VM resolves the public hostname via
168.63.129.16. The public name CNAMEs to*.privatelink.*, and if a matching Private DNS zone is linked to this VNet, that resolves to the endpoint's private IP. If the zone isn't linked, it falls through to the public IP and everything after this is wrong. This is the most common private endpoint failure. - Route lookup on the host. The destination is inside the VNet's address space, so the
VirtualNetworksystem route wins — unless a UDR is at least as specific. - Outbound NSG evaluation: NIC NSG first, then subnet NSG. Both must allow.
- Encapsulation. The host's virtual filtering platform maps the private IP to a physical host address and sends it across the fabric. No virtual router is involved.
- Inbound NSG evaluation: subnet NSG then NIC NSG. Note private endpoint NICs ignore NSGs unless network policies for private endpoints are enabled on the subnet.
- Data-plane authorisation. Reaching the endpoint is not reading the data. Azure Storage still
evaluates the caller's Entra ID token against the
Storage Blob Data Readerrole, or a SAS, or the account key. Network reach and authorisation are independent gates.
2. How does Azure choose between multiple matching routes, and how do you force VNet-internal traffic through a firewall?
Answer
Longest prefix match wins, regardless of source. On a tie, precedence is UDR > BGP > system route.
That combination is why a 0.0.0.0/0 → VirtualAppliance UDR does not send VNet-internal traffic
to the firewall: the system route for the VNet's own prefix (say /20) is longer than /0, so it
wins.
To force internal traffic through a firewall you must write a UDR at least as specific as the
system route — typically a per-subnet route, 10.20.2.0/24 → VirtualAppliance → 10.0.0.4, in the
route table attached to snet-app. And you need the mirror route in the other direction, or you get
asymmetric routing and the stateful firewall drops the return flow.
Also relevant: if on-premises advertises 0.0.0.0/0 over BGP, it beats the system internet route
and silently forces-tunnels your whole subnet. A UDR beats BGP, so a UDR is how you exempt what you
need to.
The command that settles all of this without argument is az network watcher show-next-hop.
3. How are NSG rules evaluated, and what happens when a subnet NSG and a NIC NSG disagree?
Answer
Within one NSG: rules are evaluated in ascending priority order and the first match wins. There's no most-specific-rule logic and no implicit precedence for Deny — a Deny at 200 loses to an Allow at 100. NSGs are stateful, so return traffic is permitted automatically and you never write the reverse rule.
Across the two attachment points: inbound is subnet NSG then NIC NSG; outbound is NIC NSG then subnet NSG. Both must allow. A subnet NSG that allows and a NIC NSG that denies produces a silent drop indistinguishable from a routing failure.
Two things I'd add:
Every NSG has six undeletable default rules, and they mean the default posture is flat inside the
VNet (AllowVnetInBound/Outbound at 65000) and open outbound to the internet
(AllowInternetOutBound at 65001). Segmentation and egress control are things you build.
To debug this without guessing, use Network Watcher's IP flow verify — it returns Allow/Deny plus the name of the deciding rule — or effective security rules, which shows the merged view a NIC actually sees.
4. Service endpoint versus private endpoint — what's the actual difference, and which do you pick?
Answer
A service endpoint is a route optimisation. It adds a system route so traffic to a PaaS service leaves via Azure's backbone and presents the VM's private IP as the source to the service's firewall. The destination is still the service's public IP. It's free, applies to a whole service at subnet granularity, and doesn't work from on-premises.
A private endpoint creates a NIC with a private IP in your subnet mapped to one specific
resource and one specific sub-resource (blob, vault, sqlServer). It's reachable from
on-premises over VPN/ExpressRoute, it requires a Private DNS zone or the name still resolves
publicly, and it's billed hourly plus per GB.
Pick private endpoints for anything that matters. The security argument is decisive: a service endpoint lets the subnet reach any account in that service, including an attacker's, which is an exfiltration path. A private endpoint reaches exactly one resource.
Service endpoints are still reasonable when you want something free and coarse with no on-premises requirement — and if you use them, add service endpoint policies to constrain the accounts.
5. Control plane versus data plane for a VNet — which RBAC roles govern which, and what's the classic mistake?
Answer
The control plane is ARM: creating VNets, subnets, NSG rules, route tables, peerings. Governed
by Azure RBAC — Network Contributor for full networking management, Reader for view.
The data plane is the packet path, and it has no RBAC at all. There is no identity on a TCP SYN. Packets are permitted or dropped by NSG rules, routes, and firewall policy. Azure RBAC governs who may change the rules, never who may traverse them. This is the cleanest example in Azure of network controls and identity controls being genuinely orthogonal.
The classic mistake is Microsoft.Network/virtualNetworks/subnets/join/action. Deploying a VM
or private endpoint into a subnet requires that permission on the VNet, not on the VM's resource
group. In hub-and-spoke the VNet usually lives in a central networking resource group or another
subscription, so an application team with Contributor on their own resource group gets:
Resource 'vnet-hub-prod' does not exist or one of its queried
reference-property objects are not present.
which reads as "the VNet is missing" and actually means "you can't see it". The fix is a role
assignment scoped to the subnet — ideally a custom role with just join/action and read, not
Network Contributor on the whole VNet.
The second classic mistake is the mirror image: assuming a private endpoint secures the data. It doesn't authenticate anyone. Storage still checks the Entra token against the data-plane role.
6. Which changes to a VNet or subnet force replacement rather than an in-place update, and what does that cost you?
Answer
In-place and safe: NSG rules, routes in a route table, adding a subnet, adding an address range, peering flags, NAT Gateway association, tags, DNS server list.
Force replacement:
- Changing a subnet's address prefix. Terraform must delete and recreate it — and the delete fails if anything is in the subnet, leaving state and reality diverged mid-apply. Cost: every NIC, private endpoint, and service association link in that subnet.
- Changing a subnet's delegation while the delegated service is running.
- Changing a VPN Gateway's SKU family. Recreates the gateway, so you get a new public IP and every on-premises peer needs reconfiguring.
The costs are unusually asymmetric here. A replaced VM is an outage for one workload. A replaced
subnet is an outage for every team that put something in it, and for a VNet there is no soft
delete — unlike Key Vault or storage, a deleted VNet is simply gone. No recovery window, no purge,
no support ticket. Your only copy is the git history, which is why the state storage account gets
blob versioning and a CanNotDelete lock.
Two Azure-specific complications that make this fail confusingly: a resource lock on the VNet or its resource group turns any replacement into an authorization-shaped error that looks like an RBAC bug; and peerings you don't own must be removed from the far side, which may be in a subscription you can't see.
The mitigation is a CI gate: parse terraform show -json and fail the pull request if the plan
deletes an azurerm_subnet, azurerm_virtual_network, or azurerm_virtual_network_peering without
an explicit override label.
Tier 3 — Scenario and design
1. "Our application intermittently fails to reach a third-party payment API at peak, with timeouts. Nothing changed. Diagnose it."
Answer
The shape of this — timeouts, only at peak, only to one destination, application logs blaming the remote service — is SNAT port exhaustion until proven otherwise.
Why it happens: outbound SNAT mappings are allocated per destination IP-and-port. A workload making many short-lived connections to a single destination burns through its port allocation, while a workload spreading calls across many destinations never notices. That's why it's this one API and not the internet generally.
How I'd confirm it:
- If there's a NAT Gateway, check the SNAT connection count and dropped packets metrics — drops above zero is the answer.
- If outbound goes via a Standard Load Balancer's outbound rules, check allocated versus used SNAT ports; LB pre-allocates a fixed block per instance, which is where the ceiling comes from.
- Correlate with flow logs: allowed flows to that destination with no return traffic.
- Confirm the timing lines up with peak concurrency, not peak data volume.
Fixes, in the order I'd actually apply them:
- Connection pooling and keep-alive in the application. This is the real fix and the one people
skip. A
HttpClientcreated per request in .NET, or a Pythonrequestscall without a session, opens a new TCP connection every time and is the usual root cause. - A NAT Gateway if there isn't one — it allocates ports on demand rather than pre-allocating a fixed block, and gives far more headroom per IP.
- More public IPs on the NAT Gateway, or a public IP prefix — multiplies the port pool.
- A private endpoint or service endpoint to the destination if it's an Azure service, so the traffic never needs SNAT at all. Doesn't apply to a third-party API, but it's the right answer when the destination is Azure Storage or SQL.
- Reduce the idle timeout so ports are returned faster — a mitigation, not a fix.
And the alert I'd leave behind: NAT Gateway dropped packets > 0, which fires hours before users notice.
2. "Design the network for a regulated workload: no public exposure, all egress inspected and logged, on-premises connectivity, and a second region for DR."
Answer
Address plan first, because it's the irreversible decision. Reserve a /12 or /13 for the
organisation, give each region-plus-environment a /16, and each VNet a /20 with contiguous free
space after it. UK South prod 10.20.0.0/20, West Europe prod 10.21.0.0/20 — reserved on day one
even though DR is phase two, because retrofitting a non-overlapping range is a renumbering project.
Topology: hub-and-spoke per region.
Hub (platform subscription): AzureFirewallSubnet (/26, firewall deployed across all three
zones), GatewaySubnet (/27, ExpressRoute with an AZ-SKU gateway), AzureBastionSubnet
(/26), and a subnet for the DNS Private Resolver inbound endpoint.
Spokes (per-application subscriptions, one subscription per environment — the blast-radius and quota boundary, since most networking limits are per subscription per region): application, data, private-endpoint, and integration subnets, each with its own NSG.
No public exposure: no public IPs in spokes at all, enforced by an Azure Policy Deny, not a
convention. All PaaS reached by private endpoints with publicNetworkAccess disabled on every
target resource. Inbound from the internet, if any, only through Front Door or Application Gateway
with WAF in the hub.
Egress inspected: a UDR in every spoke sending 0.0.0.0/0 to the firewall's private IP, with
allowForwardedTraffic on both sides of each peering. Firewall application rules allowlist FQDNs;
its diagnostics go to Log Analytics. Deny-all outbound NSG rules on top, rolled out gradually using
flow logs to discover what actually talks.
On-premises: ExpressRoute terminating in the hub, allowGatewayTransit on the hub peering and
useRemoteGateways on each spoke. Corporate DNS gets a conditional forwarder to the Private
Resolver so on-premises resolves the private endpoint names.
DNS: Private DNS zones in the hub, linked to every spoke VNet individually — links don't inherit through peering, and that catches people.
DR: the mirror topology in region two, global peering or Virtual WAN between hubs, Front Door for global entry, and data-tier replication chosen per service. The network is the easy half; the data replication is the design.
Governance: Policy at the management group above the environment subscriptions — deny public IPs, deny management ports from the internet, deny subnets without an NSG, DeployIfNotExists for flow logs and diagnostic settings. Terraform governs what's in state; Policy governs what isn't.
And the honest caveat: this design has a firewall as a single point of failure for all egress and a meaningful monthly cost. Both are deliberate trades for inspection and logging, and both should be stated explicitly rather than discovered.
3. "A deployment half-applied and left the network in an inconsistent state. Walk me through rollback and blast radius."
Answer
First, classify the change, because rollback differs completely:
- NSG rules, routes, peering flags — re-apply the previous commit. Genuinely undone.
- NSG association removed — reversible in seconds, but the exposure already happened. Check flow logs for what reached the subnet during the window.
- A UDR added — if the appliance wasn't ready or return routing is asymmetric, every flow in the subnet died at once, including my own SSH session. This is why you need an out-of-band path (Bastion in another subnet, or serial console) before applying route changes.
- A subnet or VNet deleted — not recoverable. No soft delete for VNets.
Then check what's actually blocking the re-apply, because half-applied network changes fail in predictable ways:
- A resource lock (
CanNotDelete) inherited from the resource group or subscription — presents as an authorization error that looks like an RBAC bug. - A subnet in use — a NIC or private endpoint from another team's deployment prevents deletion.
- A dangling peering on the far side, in a subscription I may not be able to see.
- State divergence — if the apply died mid-flight,
terraform state listversus reality is the first thing I'd reconcile, withterraform importfor anything created but unrecorded.
Blast radius reasoning. For a VNet it's measured in teams, not resources. Re-applying from the last good commit recreates the topology but not the NICs, private endpoints, and gateway connections other teams placed inside it — every consuming team has to redeploy. That's the number worth knowing in advance, which is why the drill in Production is "delete a spoke in dev and time the full rebuild".
The Azure-specific version of this question: if the deployment was Bicep or ARM, ask what
mode it ran in. Incremental (the default) leaves unmentioned resources alone. Complete
mode deletes every resource in the resource group that isn't in the template — in a shared
networking resource group that means the NICs, private endpoints, and gateways other teams created,
because your template doesn't declare them. That's a multi-team outage from one flag. Always pass
--mode Incremental explicitly and always run what-if first; it does show the deletions.
4. "Someone added an NSG rule in the portal during an incident three weeks ago. How would you have found out, and how do you get back to a clean plan?"
Answer
How I'd find out — four layers, and I'd want all of them:
A scheduled
terraform plan -detailed-exitcodein CI on weekday mornings. Exit code 2 means drift. This is the backstop, but it's up to a day late.An activity log alert on the operations that matter, filtered to exclude the pipeline's own identity — that filter is what turns it from noise into signal, because every remaining row is a human change that bypassed the pipeline:
AzureActivity | where OperationNameValue has_any ("SECURITYRULES/WRITE", "ROUTES/WRITE", "SUBNETS/WRITE", "VIRTUALNETWORKPEERINGS/WRITE") | where ActivityStatusValue == "Success" | where Caller !endswith "terraform-prod" | project TimeGenerated, Caller, OperationNameValue, _ResourceIdThis fires in minutes, not overnight.
Azure Policy compliance state — catches resources that were never in Terraform at all, which
planstructurally cannot see.az deployment group what-ifon a schedule for anything managed in Bicep.
Getting back to a clean plan — and the part people get wrong: do not revert it blindly. That rule may be the only thing keeping production up, and reverting emergency fixes is how you teach people to disable the pipeline, which is worse than the drift.
The workflow is: identify the caller from the activity log, ask what it was for, then make a
decision — either codify it in the module (add it to nsg_rules in the .tfvars and let apply
converge), or remove it deliberately with the incident owner's agreement and a note on the
ticket. Either way it ends up in git.
Preventing the recurrence is a separate conversation, and the honest answer is that people click
during incidents because the pipeline is too slow to use at 3 a.m. So: an emergency path that's
still auditable — a break-glass pipeline run with -target, or an Ansible playbook like the one in
Deployment that's committed and reviewable — plus PIM so the standing
permission to edit prod NSGs doesn't exist in the first place and has to be activated with a
justification.
Next: Glossary & Cheatsheet →
← Back to the Virtual Network overview · ← Previous: Production