Appearance
NSG Rules
Each environment VNet contains two subnets with dedicated Network Security Groups: one for the public-facing Container App Environment (Gateway + Keycloak) and one for the private internal CAE (all other microservices).
NSG Architecture
x= environment octet: dev=0, stage=1, preprod=6, uat=5, prod=2- Internet traffic may only enter through Azure Front Door
- privateApps subnet is unreachable directly from the internet
- privateEndpoints subnet only accepts connections from privateApps and publicApps subnets
Public Subnet NSG (mic-erp-be-{env}-public-nsg)
The public NSG protects the subnet hosting Gateway and Keycloak Container App Environments.
Inbound Rules
| Priority | Name | Source | Source Port | Destination | Dest Port | Protocol | Action |
|---|---|---|---|---|---|---|---|
| 100 | AllowAFDHttps | AzureFrontDoor.Backend | * | VirtualNetwork | 443 | TCP | Allow |
| 110 | AllowAFDHttp | AzureFrontDoor.Backend | * | VirtualNetwork | 80 | TCP | Allow |
| 120 | AllowHealthProbe | AzureLoadBalancer | * | * | * | * | Allow |
| 200 | AllowVnetInbound | VirtualNetwork | * | VirtualNetwork | * | * | Allow |
| 4096 | DenyAllInbound | * | * | * | * | * | Deny |
AFD Service Tag
AzureFrontDoor.Backend is an Azure-managed service tag that automatically resolves to the IP ranges used by Azure Front Door's backend probes and forwarded traffic. This ensures only AFD-proxied traffic reaches the public CAE, preventing direct IP bypass.
Outbound Rules
| Priority | Name | Source | Destination | Dest Port | Protocol | Action |
|---|---|---|---|---|---|---|
| 100 | AllowVnetOutbound | VirtualNetwork | VirtualNetwork | * | * | Allow |
| 110 | AllowAzureServices | * | AzureCloud | 443 | TCP | Allow |
| 200 | AllowInternetHttps | * | Internet | 443 | TCP | Allow |
| 4096 | DenyAllOutbound | * | * | * | * | Deny |
Private Subnet NSG (mic-erp-be-{env}-private-nsg)
The private NSG protects all internal microservices. These services are never directly accessible from the internet.
Inbound Rules
| Priority | Name | Source | Source Port | Destination | Dest Port | Protocol | Action |
|---|---|---|---|---|---|---|---|
| 100 | AllowFromPublicSubnet | 10.x.1.0/24 | * | VirtualNetwork | * | TCP | Allow |
| 105 | AllowFromPrivateApps | 10.x.2.0/23 | * | VirtualNetwork | * | TCP | Allow |
| 110 | AllowVnetInternal | VirtualNetwork | * | VirtualNetwork | * | * | Allow |
| 120 | AllowHealthProbe | AzureLoadBalancer | * | * | * | * | Allow |
| 4096 | DenyAllInbound | * | * | * | * | * | Deny |
No Direct Internet Access to Private CAE
Rule priority 4096 (DenyAllInbound) blocks all traffic that does not match the preceding allow rules. The only path into the private CAE from outside the VNet is through the public subnet (Gateway → private service). This enforces the hub-and-spoke pattern where Gateway is the single ingress.
Outbound Rules
| Priority | Name | Source | Destination | Dest Port | Protocol | Action |
|---|---|---|---|---|---|---|
| 100 | AllowVnetOutbound | VirtualNetwork | VirtualNetwork | * | * | Allow |
| 110 | AllowAzureServices | * | AzureCloud | 443 | TCP | Allow |
| 120 | AllowSqlPrivateEndpoint | VirtualNetwork | 10.x.6.0/24 | 1433 | TCP | Allow |
| 130 | AllowRedisPrivateEndpoint | VirtualNetwork | 10.x.6.0/24 | 10000 | TCP | Allow |
| 200 | AllowInternetHttps | * | Internet | 443 | TCP | Allow |
| 4096 | DenyAllOutbound | * | * | * | * | Deny |
Private Endpoints Subnet NSG (mic-erp-be-{env}-pe-nsg)
The privateEndpoints subnet (10.x.6.0/24) hosts the private endpoint NICs for Azure SQL, Redis, Key Vault, and ACR. Only traffic originating from within the VNet is accepted.
Inbound Rules
| Priority | Name | Source | Dest Port | Protocol | Action |
|---|---|---|---|---|---|
| 100 | AllowSqlFromPrivateApps | 10.x.2.0/23 | 1433 | TCP | Allow |
| 110 | AllowRedisFromPrivateApps | 10.x.2.0/23 | 10000 | TCP | Allow |
| 115 | AllowFromPublicApps | 10.x.1.0/24 | 443 | TCP | Allow |
| 120 | AllowKvFromAll | VirtualNetwork | 443 | TCP | Allow |
| 130 | AllowAcrFromAll | VirtualNetwork | 443 | TCP | Allow |
| 4096 | DenyAllInbound | * | * | * | Deny |
Outbound Rules
| Priority | Name | Destination | Action |
|---|---|---|---|
| 100 | AllowVnetOutbound | VirtualNetwork | Allow |
| 4096 | DenyAllOutbound | * | Deny |
mTLS Between CAEs
The private CAE has mTLS enforced at the Container Apps Environment level. All service-to-service communication within the private CAE is automatically encrypted and mutually authenticated using certificates managed by the CAE. NSG rules permit all VNet-internal traffic on any port within the private subnet to accommodate dynamic CAE-assigned ports.
Applying NSG Changes
NSG rules are defined in Bicep at Devops/azure/infrastructure/modules/networking.bicep. Changes follow the standard infrastructure PR → review → az deployment sub create pipeline.
Test NSG Changes in Dev First
Incorrect NSG rules can silently drop traffic. Always apply and validate NSG changes in the dev environment before promoting to stage. Use Network Watcher → IP Flow Verify to test rule evaluation without sending real traffic.
bash
az network watcher test-ip-flow \
--watcher-resource-group NetworkWatcherRG \
--vm mic-erp-be-dev-gateway \
--direction Inbound \
--protocol TCP \
--local 10.0.1.10:443 \
# publicApps subnet: 10.0.1.0/24, privateApps subnet: 10.0.2.0/23, privateEndpoints: 10.0.6.0/24
--remote 1.2.3.4:12345