Chapter 6
Secure access, security & load balancing
Your two web servers are running but nobody can reach them. In this chapter you open exactly one port with an NSG, get admin access through Bastion without public IPs, and put a load balancer in front of them. Then you step back and look at security as a whole: Zero Trust, defense in depth, encryption and Key Vault, and Microsoft Defender for Cloud.
Theory
Network security groups
A network security group (NSG) is a stateful packet filter: a list of allow and deny rules for traffic to and from a subnet or a NIC. "Stateful" means that if a request is allowed in, the reply is automatically allowed out; you don't need a rule for the return traffic.
Rule properties
- Priority: 100 to 4096. Lower numbers are processed first, and processing stops at the first match.
- Source and destination: an IP address or CIDR range, a service tag, or an application security group.
- Port ranges and protocol (TCP, UDP, ICMP or Any).
- Action: Allow or Deny. Direction: Inbound or Outbound.
Default rules
Every NSG has six default rules that you can't delete, only override with a lower priority number:
| Priority | Inbound | Outbound |
|---|---|---|
| 65000 | AllowVnetInBound: VirtualNetwork β VirtualNetwork | AllowVnetOutBound |
| 65001 | AllowAzureLoadBalancerInBound: health probes | AllowInternetOutBound |
| 65500 | DenyAllInBound | DenyAllOutBound |
So by default: traffic inside the VNet (including peered VNets and on-premises via a gateway) is allowed, internet inbound is blocked, and internet outbound is allowed.
Service tags
A service tag is a Microsoft-maintained group of IP ranges, so you don't have to track IPs yourself. The ones you'll meet most:
Internet: everything outside the VNet address space and Azure's public ranges.VirtualNetwork: the VNet, peered VNets, connected on-premises ranges.AzureLoadBalancer: the source of load balancer health probes (168.63.129.16).Storage,Sql,AzureMonitor,AzureCloudβ¦, optionally per region, likeStorage.WestEurope.
Subnet NSG, NIC NSG, or both
You can associate an NSG with a subnet, a NIC, or both. When both exist, traffic must be allowed by both:
An NSG must be in the same region as the subnet or NIC, and one NSG can be associated with many subnets and NICs.
Application security groups
An application security group (ASG) is a label you put on NICs, like asg-web or asg-db. You then write NSG rules with ASGs as source or destination: "allow TCP 1433 from asg-web to asg-db". When you add a new web server, you only add its NIC to asg-web; no rule changes.
Limits: all NICs in an ASG must be in the same VNet, and if a rule uses two ASGs, both must be in the same VNet.
Evaluating effective rules
The exam loves "here are three NSG rules, is this traffic allowed?" questions. Work like ARM does:
- Pick the right direction and the right NSG(s) (subnet, NIC, or both).
- Go through the rules from the lowest priority number up. The first rule that matches source, destination, port and protocol decides.
- If nothing matches, the default rules decide.
In Azure you can check this with NIC β Effective security rules (the merged view of subnet and NIC NSGs) and Network Watcher β IP flow verify (tests one packet and names the rule that allowed or denied it).
Rule 100 Deny TCP 80 from Internet and rule 200 Allow TCP 80 from 203.0.113.10. Is traffic from 203.0.113.10 allowed? No: that address is also part of Internet, and rule 100 is evaluated first. Specific allows need a lower number than broad denies.
Azure Bastion
Azure Bastion gives you RDP and SSH in the browser (over HTTPS 443) to VMs that have no public IP. You don't open 22 or 3389 to the internet, and you don't need a jump box.
| SKU | Key points |
|---|---|
| Developer | Free, shared infrastructure, no dedicated subnet, one VNet only (no peered VNets), portal only, one session at a time. |
| Basic | Dedicated hosts in AzureBastionSubnet (/26 minimum) with a Standard public IP. Reaches VMs in peered VNets. |
| Standard | Adds native client support (az network bastion ssh/rdp), host scaling, IP-based connection (e.g. on-prem servers via VPN), file transfer, shareable links. |
| Premium | Adds session recording and private-only deployment (no public IP). |
The usual design is one Bastion in the hub (Basic or higher) that serves all peered spokes. If you put an NSG on AzureBastionSubnet, it needs specific rules (inbound 443 from Internet and GatewayManager, outbound 22/3389 to VirtualNetwork, and a few more), so most people don't.
"Admins must use their own SSH client (not the browser) through Bastion." That needs Standard or higher with native client support enabled. "Connect to an on-premises server by IP through Bastion" also needs Standard.
Azure Load Balancer
Azure Load Balancer distributes TCP and UDP traffic (layer 4) across healthy backend instances. It doesn't look at HTTP, so no URL routing and no TLS termination; that's what Application Gateway is for.
- Public load balancer: has a public IP frontend; balances internet traffic to VMs, and provides outbound internet access through outbound rules.
- Internal load balancer: has a private IP frontend in a subnet; balances traffic inside the VNet, for example from a web tier to an app tier, or from on-premises.
Use the Standard SKU. Basic was retired in September 2025. Standard is zone-redundant (or zonal), supports up to 1,000 backend instances, has an SLA, and is closed by default: an NSG must allow the traffic to the backends.
The parts of a load balancer
- Frontend IP configuration: the public or private IP clients connect to. One LB can have several.
- Backend pool: the VMs or scale set instances, by NIC or by IP address. All backends must be in the same VNet.
- Health probe: TCP, HTTP or HTTPS check on each backend. HTTP/HTTPS probes need a 200 OK. An instance that fails is taken out of rotation; existing connections continue.
- Load-balancing rule: maps a frontend IP and port to the backend pool and port, using a probe.
- Inbound NAT rule: port forwarding to one specific backend, e.g. frontend port 50001 β
vm-web1port 22. - Outbound rule: lets backends reach the internet via the frontend's public IP (SNAT), with explicit port allocation. When you use one, set the LB rule to not use implicit outbound SNAT.
Distribution and special options
- Session persistence: None (default; 5-tuple hash: source IP, source port, destination IP, destination port, protocol), Client IP (2-tuple: same client goes to the same backend), Client IP and protocol (3-tuple).
- HA ports (internal Standard LB only): one rule for all ports and protocols. Used to load-balance NVAs/firewalls.
- Floating IP (direct server return): needed for SQL Server Always On listeners.
- Cross-region load balancer: a global frontend in front of regional Standard LBs.
Which load balancing service?
| Service | Layer | Scope | Choose it when |
|---|---|---|---|
| Load Balancer | 4 (TCP/UDP) | Regional (or cross-region) | Any TCP/UDP app, internal tiers, NVAs, very high throughput |
| Application Gateway | 7 (HTTP/S) | Regional | URL path routing, TLS termination, WAF, cookie affinity |
| Front Door | 7 (HTTP/S) | Global | Global web apps, CDN caching, WAF at the edge |
| Traffic Manager | DNS | Global | DNS-based failover or geo-routing, any protocol |
Troubleshooting a load balancer
When the frontend doesn't answer or only some backends get traffic, check in this order:
- Health probe status (LB β Monitoring β Metrics β Health Probe Status, or Insights). Are the backends healthy?
- Is the app listening on the probe port and returning 200 on the probe path?
- Does an NSG block the probe? The default rule
AllowAzureLoadBalancerInBoundallows it, but a custom Deny all with a lower number would block it. - Does an NSG allow the client traffic? Standard LB needs an explicit allow.
- Are you testing from a backend VM to its own LB frontend? That doesn't work for an internal LB (the flow hairpins back to the same VM and fails).
Zero Trust
The old security model was a castle with a moat: everything inside the corporate network was trusted, everything outside wasn't. With cloud apps, home working and personal devices, there is no clear "inside" any more. Zero Trust replaces the moat with one rule: never trust, always verify. Every request is checked as if it came from an open network.
Zero Trust has three principles. Each one maps to things you already use in this guide:
| Principle | Meaning | In Azure |
|---|---|---|
| Verify explicitly | Authenticate and authorise every request using all available signals: identity, location, device health, risk. | MFA, passwordless and Conditional Access (chapter 1) |
| Use least-privilege access | Give only the access needed, only for as long as needed (just-in-time and just-enough access). | RBAC at the smallest scope (chapter 2), PIM, SAS with short expiry (chapter 7), JIT VM access |
| Assume breach | Design as if an attacker is already inside: limit the blast radius, segment, encrypt everything, and watch for anomalies. | NSGs and segmentation (this chapter), private endpoints (chapter 7), encryption, monitoring (chapter 9), Defender for Cloud |
Microsoft applies these principles across six areas, often called the pillars of Zero Trust: identities, endpoints (devices), applications, data, infrastructure and network, with visibility and automation across all of them.
Defense in depth
Defense in depth means stacking several layers of protection, so that if one layer fails, the next one still stops or slows down the attacker. No single control is trusted to do the whole job.
Two perimeter services you haven't met yet in this guide:
- Azure DDoS Protection: every Azure public IP gets basic infrastructure protection for free. The paid tiers (DDoS Network Protection per VNet, or DDoS IP Protection per public IP) add tuning to your traffic, attack reports, and cost protection during an attack.
- Azure Firewall: a managed, stateful firewall as a service, usually placed in the hub VNet. Spokes send their traffic to it with a UDR (chapter 3). It filters by FQDN and application rules, adds threat intelligence, and in the Premium SKU does TLS inspection and IDPS. NSGs filter within a VNet; Azure Firewall controls traffic between networks and to the internet.
Who secures which layer depends on the service model. Microsoft always owns physical security. You always own your data, identities, accounts and devices. In between, the split moves: with IaaS (VMs) you patch the OS and secure the network; with PaaS (App Service, Functions) Microsoft takes the OS; with SaaS Microsoft runs almost everything.
Encryption and Azure Key Vault
Data needs protecting in three states:
- At rest: on disk. Azure encrypts storage, managed disks and databases by default with platform-managed keys (chapters 5 and 7). You can switch to customer-managed keys if you must control or revoke the key.
- In transit: on the network. Use TLS 1.2 or later (enforce a minimum TLS version on storage and App Service), "secure transfer required" on storage, IPsec for VPNs. Traffic between Azure datacenters is also encrypted at the link layer by Microsoft.
- In use: in memory while being processed. Confidential computing (confidential VMs, chapter 5's security type) keeps data encrypted inside a hardware-based trusted execution environment.
Azure Key Vault
Key Vault is the central, secure store for three kinds of objects:
- Secrets: passwords, connection strings, API keys.
- Keys: cryptographic keys for encryption and signing, e.g. the customer-managed keys for storage and disks.
- Certificates: TLS certificates, with automatic renewal from integrated CAs.
| Option | Protection | Choose it when |
|---|---|---|
| Key Vault Standard | Keys protected by software | Secrets and certificates, most workloads |
| Key Vault Premium | Keys can be HSM-protected (hardware security module), multi-tenant | Compliance asks for hardware-protected keys |
| Managed HSM | Single-tenant, FIPS 140 Level 3 validated HSM pool, keys only | Strict regulation; you must control the HSM security domain yourself |
Things the exam likes about Key Vault:
- Two permission models. Azure RBAC (recommended, default for new vaults) uses data roles such as Key Vault Secrets User (read secrets), Key Vault Secrets Officer, Key Vault Crypto Officer and Key Vault Administrator. The legacy access policies model sets permissions per vault.
- Management plane vs data plane, as with storage (chapter 2): Owner or Contributor on a vault can't read its secrets in the RBAC model. They need a data role.
- Soft delete is always on: a deleted vault or secret can be recovered for 7β90 days (default 90), and its name stays reserved until it's purged. Purge protection blocks even a purge until the retention ends; it's required for customer-managed keys and can't be turned off once on.
- Apps read secrets with a managed identity, so no credential is stored in code. App Service and Functions can use Key Vault references in app settings.
- Like storage, a vault has a firewall and supports private endpoints.
"You're Owner of the subscription but get Forbidden when you read a secret." In a vault with the RBAC permission model, Owner is control plane only. Assign yourself Key Vault Secrets User (or Officer) on the vault. "You must enable customer-managed keys for a storage account" β the vault needs soft delete and purge protection.
Microsoft Defender for Cloud
Microsoft Defender for Cloud is Azure's security posture and threat protection service. It covers Azure, AWS and Google Cloud (through connectors), and on-premises servers (through Azure Arc). It does two jobs:
- Cloud security posture management (CSPM): finds misconfigurations before an attacker does.
- Cloud workload protection (CWP): detects attacks on running workloads and raises security alerts.
| Tier | What you get |
|---|---|
| Foundational CSPM (free, on by default) | Secure score, recommendations based on the Microsoft cloud security benchmark (MCSB), asset inventory |
| Defender CSPM (paid) | Attack path analysis, cloud security explorer, agentless scanning, more regulatory compliance standards |
| Defender plans (paid, per resource type) | Threat detection for Servers (Plan 1/2, includes Defender for Endpoint), Storage (incl. malware scanning), SQL, Containers, App Service, Key Vault, Resource Manager, APIs⦠|
The secure score is a percentage: the more recommendations you fix, the higher it goes. Recommendations are grouped into security controls (like "Enable MFA" or "Restrict unauthorized network access"), and you only get a control's points when all its affected resources are fixed. Many recommendations have a Fix button or can be enforced with Azure Policy, which is what Defender for Cloud uses behind the scenes.
Just-in-time (JIT) VM access, mentioned in chapter 5, is part of Defender for Servers Plan 2: management ports stay closed in the NSG and are opened only for an approved IP, for a limited time, when someone requests access.
"Find misconfigurations across Azure and AWS and get a single security score, at no cost" β Defender for Cloud foundational CSPM with an AWS connector. "Get alerted when malware is uploaded to a storage account" β the paid Defender for Storage plan. "Open RDP only on request for 3 hours" β JIT VM access (Defender for Servers Plan 2).
The "which load balancer" table above is one of the most-used decision trees in AZ-305. Ask: HTTP or not? Global or regional? Need a WAF? Combinations are common: Front Door globally, with Application Gateway or a Standard LB per region.
- Network security groups
- How NSGs filter traffic
- Application security groups
- Service tags
- Azure Bastion overview
- Bastion SKUs and settings
- Azure Load Balancer overview
- Load Balancer components
- Outbound rules
- Troubleshoot Azure Load Balancer
- Load-balancing options (decision guide)
- What is Zero Trust?
- Shared responsibility in the cloud
- Azure DDoS Protection overview
- What is Azure Firewall?
- Azure encryption overview
- About Azure Key Vault
- Key Vault access with Azure RBAC
- Key Vault soft delete and purge protection
- What is Microsoft Defender for Cloud?
- Secure score in Defender for Cloud
Self-check
1. A subnet NSG allows inbound TCP 443 from Internet. The NIC NSG has only default rules. Can clients reach the VM on 443?
B. Both NSGs must allow it. Add the allow rule to the NIC NSG too, or remove the NIC NSG.
2. You add a third web server. With the least effort, how do you make the existing "allow 80 to web servers" rule apply to it?
D. That's exactly what ASGs are for.
3. A firewall appliance pair must receive all TCP and UDP traffic on all ports from an internal load balancer. What do you configure?
A. HA ports load-balance all ports and protocols, which is the standard NVA pattern.
4. Users must connect to a VM through Bastion using their local SSH client. Which SKU is the minimum?
C. Native client support starts at Standard.
5. One backend VM gets no traffic from the load balancer. The VM runs and nginx listens on 80. The probe is HTTP on port 8080. What's wrong?
B. (Then why does the other VM get traffic? It probably listens on 8080. Probes must match what the app serves.)
6. "Give engineers Contributor only for the four hours of a change window, then remove it automatically." Which Zero Trust principle does this apply?
C. Just-in-time access is least privilege in time. (You'd implement it with PIM.)
7. An app's connection string must not be stored in code or config files. What's the recommended approach?
B. Managed identity + Key Vault removes every stored credential.
8. You delete a key vault kv-app, then try to create a new vault with the same name. It fails. Why?
D. Recover it, or purge it (only possible if purge protection is off), or wait for the retention to end.
9. Which Defender for Cloud capability is free and enabled by default on every subscription?
A. The others need Defender for Servers Plan 2, Defender for Storage, or Defender CSPM.
Lab: open the web servers to the world, safely
You open port 80 to the web servers only, put them behind lbe-web with the public IP from chapter 3, give them outbound internet through the load balancer, log in with Bastion, and break and fix the load balancer.
The variables from chapter 0 ($RG, $LOC, $LOC2, $INIT, $ST, $ACR, $MYIP) load automatically in every terminal; if they don't, run . ~/az104.env. Any other variable a task needs is set at the top of that task's Azure CLI solution, so every solution works on its own in a fresh terminal.
Start the VMs first:
az vm start -g $RG -n vm-web1 --no-wait; az vm start -g $RG -n vm-web2 --no-wait
-
Task
Label the web servers
Create an application security group
asg-weband put the network interfaces of both web VMs in it.Done when- Each VM's Networking β Application security groups tab shows
asg-web.
Solution Β· Portal
- Create a resource β Application security group: name
asg-web, your region. vm-web1β Networking β Network settings (or Application security groups) β Add application security groups βasg-web. Repeat forvm-web2.
Solution Β· Azure CLI
az network asg create -g $RG -n asg-web -l $LOC for VM in vm-web1 vm-web2; do NICID=$(az vm show -g $RG -n $VM --query "networkProfile.networkInterfaces[0].id" -o tsv) NICNAME=$(basename $NICID) IPCFG=$(az network nic show --ids $NICID --query "ipConfigurations[0].name" -o tsv) az network nic ip-config update -g $RG --nic-name $NICNAME -n $IPCFG --application-security-groups asg-web done - Each VM's Networking β Application security groups tab shows
-
Task
Allow HTTP to the web servers only
Use
nsg-web(created with Bicep in chapter 4) to allow TCP 80 from the internet to members ofasg-web, and protect the wholesnet-websubnet with it. Don't open SSH.Done whennsg-webis associated withsnet-weband has one custom inbound rule.- The effective security rules of
vm-web1's NIC show your rule above the defaults.
Hint
Source: service tag
Internet. Destination: Application security group. Priority: something low like 100.Solution Β· Portal
nsg-webβ Settings β Inbound security rules β Add: Source Service TagInternet, source ports*, Destination Application security groupasg-web, service HTTP / port80, TCP, Allow, priority100, nameallow-http-internet.- Settings β Subnets β Associate:
vnet-spoke/snet-web. vm-web1β Networking β NIC β Help β Effective security rules.
Solution Β· Azure CLI
az network nsg rule create -g $RG --nsg-name nsg-web -n allow-http-internet --priority 100 \ --direction Inbound --access Allow --protocol Tcp \ --source-address-prefixes Internet --source-port-ranges '*' \ --destination-asgs asg-web --destination-port-ranges 80 az network vnet subnet update -g $RG --vnet-name vnet-spoke -n snet-web --network-security-group nsg-web NIC=$(az vm show -g $RG -n vm-web1 --query "networkProfile.networkInterfaces[0].id" -o tsv) az network nic list-effective-nsg --ids $NIC --query "value[0].effectiveSecurityRules[].{name:name, prio:priority, access:access, dir:direction}" -o table -
Task
Build the public load balancer
Create a Standard public load balancer
lbe-webthat:- uses the existing public IP
pip-lbe-webas frontend (fe-web); - has both web VMs in backend pool
be-web; - checks health with an HTTP probe on port 80, path
/(hp-http); - forwards TCP 80 to port 80 on the backends (
lbr-http); - gives the backends outbound internet through an outbound rule (
obr-web) instead of implicit SNAT.
Done whenhttp://<pip-lbe-web address>in your browser shows "Hello from vm-web1" or "vm-web2". Refresh a few times, or usecurlrepeatedly, to see both.- If you did the optional DNS task in chapter 3:
http://web.lab.yourdomain.comworks too.
Hint
A browser often reuses its connection and keeps hitting the same backend.
for i in $(seq 6); do curl -s http://IP; doneopens a new connection each time.Solution Β· Portal
- Create a resource β Load balancer: name
lbe-web, SKU Standard, type Public, tier Regional. - Frontend IP configuration β Add: name
fe-web, public IP use existingpip-lbe-web. - Backend pools β Add:
be-web, VNetvnet-spoke, configuration NIC, add both VMs. - Inbound rules β Add a load balancing rule:
lbr-http, frontendfe-web, poolbe-web, TCP, port 80, backend port 80, Create new health probehp-http(HTTP, port 80, path/), session persistence None, Outbound SNAT: (Recommended) Use outbound rulesβ¦. - Outbound rules β Add:
obr-web, frontendfe-web, protocol All, poolbe-web, port allocation default. - Review + create, wait a minute, then test.
Solution Β· Azure CLI
az network lb create -g $RG -n lbe-web -l $LOC --sku Standard \ --frontend-ip-name fe-web --public-ip-address pip-lbe-web --backend-pool-name be-web az network lb probe create -g $RG --lb-name lbe-web -n hp-http --protocol Http --port 80 --path / az network lb rule create -g $RG --lb-name lbe-web -n lbr-http --protocol Tcp \ --frontend-port 80 --backend-port 80 --frontend-ip-name fe-web --backend-pool-name be-web \ --probe-name hp-http --disable-outbound-snat true az network lb outbound-rule create -g $RG --lb-name lbe-web -n obr-web --protocol All \ --frontend-ip-configs fe-web --address-pool be-web for VM in vm-web1 vm-web2; do NICNAME=$(basename $(az vm show -g $RG -n $VM --query "networkProfile.networkInterfaces[0].id" -o tsv)) IPCFG=$(az network nic show -g $RG -n $NICNAME --query "ipConfigurations[0].name" -o tsv) az network nic ip-config address-pool add -g $RG --nic-name $NICNAME --ip-config-name $IPCFG \ --lb-name lbe-web --address-pool be-web done PIP=$(az network public-ip show -g $RG -n pip-lbe-web --query ipAddress -o tsv) for i in $(seq 6); do curl -s http://$PIP; done - uses the existing public IP
-
Task
Prove where outbound traffic comes from
Find out which public IP address
vm-web1uses when it browses the internet. Explain why.Done when- The address you see is the address of
pip-lbe-web.
Solution Β· Azure CLI
az vm run-command invoke -g $RG -n vm-web1 --command-id RunShellScript \ --scripts "curl -s https://api.ipify.org" --query "value[0].message" -o tsvThe outbound rule is an explicit outbound method, so it takes precedence over default outbound access. From now on the VMs would still have internet even in a private subnet.
- The address you see is the address of
-
Task
Log in with Bastion
Open an SSH session in your browser to
vm-web1using Azure Bastion, with the free Developer SKU. The VM must keep having no public IP.Done when- You're at a
azureuser@vm-web1prompt in a browser tab. - You can explain why Developer can't reach a VM in
vnet-hub.
Solution Β· Portal
vm-web1β Connect β Connect via Bastion β Deploy Bastion Developer (it attaches tovnet-spoke; takes a few minutes).- Enter
azureuserand your password (or private key) β Connect.
Developer works for one VNet only, without peering. A hub VM would need Bastion Basic or higher.
If Developer isn't offered in your region: add subnet
AzureBastionSubnet10.20.254.0/26tovnet-spokeand deploy Basic. It costs about β¬0.20/hour, so delete it after this chapter. - You're at a
-
Task
Break the load balancer, then fix it
In your Bastion session, stop nginx on
vm-web1. Then find out, from the load balancer, what it thinks about each backend, and check what clients now get. Start nginx again afterwards.Done when- All
curlrequests return "Hello from vm-web2" while nginx is stopped. - You found the probe status in the load balancer's metrics or Insights.
- Both backends serve again.
Solution Β· Portal
- In Bastion:
sudo systemctl stop nginx. lbe-webβ Monitoring β Metrics β metric Health Probe Status, Apply splitting by Backend IP Address:10.20.1.4drops to 0. (Or Monitoring β Insights.)- From your Linux VM, call the public IP of
pip-lbe-web(on its Overview) six times:for i in $(seq 6); do curl -s http://<public-ip>; done. - In Bastion:
sudo systemctl start nginx.
Solution Β· Azure CLI
PIP=$(az network public-ip show -g $RG -n pip-lbe-web --query ipAddress -o tsv) az vm run-command invoke -g $RG -n vm-web1 --command-id RunShellScript --scripts "systemctl stop nginx" sleep 30; for i in $(seq 6); do curl -s http://$PIP; done az vm run-command invoke -g $RG -n vm-web1 --command-id RunShellScript --scripts "systemctl start nginx" - All
-
Task
Prove that SSH from the internet is blocked
Without trying to connect, find out whether an SSH packet (TCP 22) from internet address
198.51.100.10tovm-web1would be allowed, and which rule decides.Done when- You have the answer Deny and the rule name DenyAllInBound.
Hint
Network Watcher has a tool that tests exactly one packet.
Solution Β· Portal
Network Watcher β Network diagnostic tools β IP flow verify: VM
vm-web1, protocol TCP, direction Inbound, local port 22, remote IP198.51.100.10, remote port 60000 β Access denied, ruleDenyAllInBound. Try again with port 80: allowed byallow-http-internet.Solution Β· Azure CLI
IP1=$(az vm show -g $RG -n vm-web1 -d --query privateIps -o tsv) az network watcher test-ip-flow -g $RG --vm vm-web1 --direction Inbound --protocol TCP \ --local $IP1:22 --remote 198.51.100.10:60000 az network watcher test-ip-flow -g $RG --vm vm-web1 --direction Inbound --protocol TCP \ --local $IP1:80 --remote 198.51.100.10:60000 -
Task
Store a secret, the least-privilege way
Create a key vault
kv-az104-xx01inrg-az104-labthat uses the Azure RBAC permission model and keeps deleted items for only 7 days. Then store a secretdemo-secretin it and read it back.Before you give yourself any extra role, try to create the secret first, and note the error.
Done when- Your first attempt failed with Forbidden, although you're Owner of the subscription. You can explain why.
- After a role assignment on the vault only, you can read the secret's value from your Linux VM.
Hint
Vault names are global, 3β24 characters. If yours is taken, add a digit. The role you need to write secrets is Key Vault Secrets Officer; to only read them, Key Vault Secrets User. New role assignments can take a minute to work.
Solution Β· Portal
- Create a resource β Key Vault: RG
rg-az104-lab, namekv-az104-xx01, your region, tier Standard, days to retain deleted vaults: 7, purge protection Disabled. Tab Access configuration: Azure role-based access control. Create. - Vault β Objects β Secrets β Generate/Import: the portal says you're unauthorized to view or create secrets.
- Vault β Access control (IAM) β Add role assignment β Key Vault Secrets Officer β your own account.
- Back in Secrets β Generate/Import: name
demo-secret, any value. Open it and Show Secret Value.
Solution Β· Azure CLI
KV=kv-az104-${INIT}01 az keyvault create -g $RG -n $KV -l $LOC --enable-rbac-authorization true --retention-days 7 az keyvault secret set --vault-name $KV -n demo-secret --value "Hello from Key Vault" # Forbidden KVID=$(az keyvault show -n $KV --query id -o tsv) ME=$(az ad signed-in-user show --query id -o tsv) az role assignment create --assignee $ME --role "Key Vault Secrets Officer" --scope $KVID sleep 60 az keyvault secret set --vault-name $KV -n demo-secret --value "Hello from Key Vault" az keyvault secret show --vault-name $KV -n demo-secret --query value -o tsvOwner is a control-plane role: it manages the vault resource, not what's inside. Reading and writing secrets are DataActions, just like reading blobs in chapter 2.
-
Task
Check your security posture
Open Microsoft Defender for Cloud and find out, without enabling any paid plan:
- your subscription's secure score;
- at least two recommendations that concern a resource in
rg-az104-lab, with their severity; - for one of them, which Zero Trust principle or defense-in-depth layer it belongs to.
Done when- You've noted the score and two recommendations, and you've matched one to a principle or layer.
- All Defender plans in Environment settings are still Off (except free foundational CSPM).
Hint
A brand-new subscription can take up to 24 hours before the score and recommendations appear. If it's still empty, come back to this task at the start of chapter 7.
Solution Β· Portal
- Microsoft Defender for Cloud β Overview: the secure score tile.
- Recommendations: filter Resource group =
rg-az104-lab. Typical results: "Key vaults should have deletion protection enabled", "Storage accounts should restrict network access" or "Machines should have a vulnerability assessment solution". Note the risk level / severity. - Example mapping: "Key vaults should have deletion protection enabled" β data layer / assume breach. "Management ports should be closed" β network/compute layer / least privilege.
- Environment settings β your subscription β Defender plans: check that everything is Off. Don't start the free trial here; it switches on paid plans after 30 days.
Solution Β· Azure CLI
az security secure-scores list --query "[].{name:displayName, current:current, max:max, pct:percentage}" -o table az security assessment list --query "[?contains(id,'rg-az104-lab') && status.code=='Unhealthy'].{rec:displayName, resource:resourceDetails.id}" -o table az security pricing list --query "value[].{plan:name, tier:pricingTier}" -o table
The Standard load balancer costs about β¬0.025/hour plus data. Bastion Developer is free. Key Vault costs a few cents per 10,000 operations, and foundational CSPM in Defender for Cloud is free. Deallocate the VMs when you stop for the day; the load balancer can stay.
nsg-webonsnet-weballows only HTTP from the internet toasg-web.lbe-webserves both VMs onhttp://<pip-lbe-web>and provides their outbound internet.- Bastion Developer on
vnet-spokefor admin access. - Key vault
kv-az104-xx01(RBAC model) withdemo-secret. Chapter 10 deletes and purges it.