On Azure, an inbound flow goes through two NSGs: the subnet one, then the network interface one. It must be allowed by both. In each NSG, rules are read in ascending priority order and the first one that matches decides.
The audit script added Deny-Internet-Audit (priority 100, source Internet, all ports) to
nsg-snet-web. It comes before Allow-HTTPS-Internet (200): the flow is dropped before it even reaches
the network interface. Hence the timeout (an NSG does not send back a refusal, it ignores the packet).
The other leads are wrong: the interface NSG does allow 443, run-command shows nginx active and
listening, and DNS still points to the static IP 20.199.48.73.
Incident resolved
Analysis and fix
Fix: restrict the offending rule to what the audit really meant to block (administration),
az network nsg rule update -g rg-zitouna-prod --nsg-name nsg-snet-web -n Deny-Internet-Audit --destination-port-ranges 22 3389,
or delete it with az network nsg rule delete.
Verification: az network watcher test-ip-flow … returns Allow (rule Allow-HTTPS-Internet),
then curl -I https://api.zitouna-express.ma/health returns 200.
To prevent it from happening again:
- run audit scripts in report mode (Azure Policy with the
Auditeffect) before anyDenymode; - describe NSGs as infrastructure as code (Bicep/Terraform), reviewed;
- run
test-ip-flowon critical flows after every network change; - an Azure Monitor alert on
securityRules/writein production resource groups.