Architecture Azure

Azure Enterprise Architecture: Zero-Trust Web Application

Most “secure” web applications on Azure are still built on an implicit-trust model: the app is reachable on a public hostname, the database has a firewall rule that says “allow Azure services,” and the security story is a single TLS certificate and a hope that nobody guesses the admin password. Zero Trust inverts that. It assumes the network is already hostile, that credentials will leak, and that every request — from a browser, a daemon, or a developer’s laptop — must be authenticated, authorized, and inspected on its own merits. This article is a complete, reusable Azure reference architecture for a Zero-Trust web application, anchored on four pillars: Application Gateway with WAF at the edge, Microsoft Entra ID + Conditional Access for identity, Private Endpoints to collapse the data-plane attack surface, and managed identities to eliminate stored secrets.

The business scenario

The pattern below is deliberately scale-agnostic. The same topology serves a 40-person fintech startup and a 40,000-person regulated insurer; only the SKUs, the number of spokes, and the operational rigor change.

Concretely, the recurring problem looks like this. An organization runs a customer- or employee-facing web application — a claims portal, an internal HR system, a B2B partner dashboard, a SaaS product. The business needs it on the internet (or at least reachable by remote staff), but the security, risk, and compliance teams have hard requirements that a naive “App Service with a public endpoint” design cannot meet:

The architecture that follows satisfies all of these with first-party Azure services and no third-party security appliances.

Architecture overview

The end-to-end request path flows north-to-south through progressively higher-trust zones, and the data path never touches the public internet at all.

A user opens https://portal.contoso.com. Public DNS resolves that name to the public IP of an Azure Application Gateway v2 (WAF_v2 SKU) — the only public ingress in the entire system. Optionally Azure Front Door sits in front of App Gateway for global anycast, CDN, and edge WAF; in a single-region design App Gateway alone is the edge. The Application Gateway terminates TLS, evaluates the WAF policy (OWASP Core Rule Set 3.2 + bot protection) against the request, and — only if the request survives inspection — forwards it over the private network to the application tier.

The application tier is an App Service (or Container Apps) on a regional VNet, injected into a dedicated subnet via VNet integration for outbound traffic, and fronted by a Private Endpoint for inbound. The App Service’s public access is disabled; it is reachable only from the App Gateway’s subnet through that private endpoint. The first thing the app does is authentication: either App Service Easy Auth or MSAL in code redirects the user to Microsoft Entra ID. Entra evaluates Conditional Access — is MFA satisfied, is the device compliant/managed, is the sign-in risk low, is the location allowed — and only then issues tokens. The user is now authenticated and the session is governed by policy.

When the application needs data, it calls Azure SQL Database, Blob Storage, and Key Vault, each exposed exclusively through its own Private Endpoint in a dedicated snet-data subnet. There are no firewall allowlists to maintain and public network access is set to Disabled on every PaaS resource. DNS for *.database.windows.net, *.blob.core.windows.net, and *.vault.azure.net is overridden by Azure Private DNS zones linked to the VNet, so those hostnames resolve to private 10.x addresses. Authentication to SQL and Storage uses the App Service’s system-assigned managed identity and Entra-issued tokens — there are no passwords or connection strings with secrets anywhere. Key Vault holds only the residual material that genuinely must be a secret (a third-party API key, a signing cert), and even that is fetched at runtime via managed identity, never stored in app config.

Outbound and east-west traffic is governed by a hub-and-spoke topology: an Azure Firewall (or the WAF subnet’s NSGs plus a firewall in the hub) sits in the hub, all spoke egress is force-tunneled through it via UDR, and NSGs on every subnet enforce least-privilege L4 segmentation. The result is a system where the network grants no trust, identity is continuously evaluated, the edge inspects every request, the data plane is unroutable from the internet, and no secret sits at rest in the application.

Picture the diagram as four stacked bands. Band 1 (Internet/Edge): users and bots hit Front Door → App Gateway WAF_v2 (the single public IP). Band 2 (Identity, off to the side, touching every layer): Entra ID + Conditional Access issuing tokens. Band 3 (Application spoke): snet-appgw → private endpoint → App Service with VNet integration, plus the managed identity badge. Band 4 (Data spoke): snet-data holding private endpoints for SQL, Storage, and Key Vault, each wired to a Private DNS zone, with a dashed line back to the App Service showing the private, token-authenticated data path. The hub (Firewall + Bastion + Private DNS) underlays bands 3 and 4, and Log Analytics/Defender sit to the right collecting from all of them.

Azure Zero-Trust web application reference architecture: edge App Gateway WAF_v2 re-encrypts to the App Service Private Endpoint, Entra ID Conditional Access gates identity, and a managed identity reaches SQL, Blob and Key Vault over Private Endpoints with hub Firewall/Bastion and Log Analytics/Defender/Sentinel observability.

Component breakdown

Component Role in the architecture Why it’s here (Zero-Trust principle) Key configuration choices
Application Gateway WAF_v2 Public L7 ingress; TLS termination; OWASP + bot inspection; path-based routing “Assume breach / inspect every request” — nothing reaches the app un-inspected WAF policy in Prevention mode, OWASP CRS 3.2 + bot manager ruleset; autoscaling (min 2 instances) zone-redundant; end-to-end TLS to the backend; custom health probe on /healthz
Azure Front Door (optional) Global anycast entry, CDN, edge WAF, fast failover across regions Edge offload + DDoS posture for multi-region Premium SKU for Private Link origin to App Gateway; WAF policy mirrored at the edge; caching for static assets only
Microsoft Entra ID Identity provider; token issuance (OIDC/OAuth2) “Verify explicitly” — identity is the perimeter App registration with redirect URIs; group/app-role claims; token lifetime and Continuous Access Evaluation (CAE) enabled
Conditional Access Policy engine that gates token issuance “Least privilege + adaptive trust” Require MFA; require compliant or Entra-joined device; block legacy auth; sign-in-risk and user-risk policies (require password change / block); named locations
App Service / Container Apps The web application runtime Workload tier with no public exposure and no stored secrets Public access Disabled; VNet integration (outbound) + Private Endpoint (inbound); system-assigned managed identity; HTTPS-only; minTlsVersion 1.2; Easy Auth or MSAL
Private Endpoints Private NICs that map PaaS services into the VNet “Never trust the network” — removes public data-plane One PE per resource (SQL, Blob, Key Vault, App Service, Front Door origin) in snet-data/snet-pe; public network access Disabled on each PaaS resource
Azure Private DNS zones Override public hostnames to resolve privately Makes private endpoints transparent to the app privatelink.database.windows.net, privatelink.blob.core.windows.net, privatelink.vaultcore.azure.net, privatelink.azurewebsites.net, linked to the VNet with auto-registration off
Azure SQL Database Relational data store Data tier, Entra-auth, no SQL logins Entra-only authentication; managed-identity DB user; TDE; Public network access = Disabled; private endpoint only
Azure Storage (Blob) Object/blob storage Data tier Managed-identity RBAC (no account keys, no SAS); Public network access = Disabled; private endpoint; shared key auth disabled
Azure Key Vault Secret/cert/key store for residual secrets Centralize the few secrets that remain; managed-identity access RBAC authorization (not access policies); private endpoint; purge protection + soft delete; managed identity granted Key Vault Secrets User
Azure Firewall (hub) Egress control + east-west L4/L7 filtering “Assume breach” for outbound; exfiltration control Forced tunneling via UDR from spokes; FQDN/application rules allowlisting only required egress; DNS proxy for FQDN rules
NSGs Per-subnet L4 microsegmentation Least-privilege network paths App Gateway subnet: allow 65200-65535 mgmt + 443 inbound; snet-data: allow only from app subnet on 1433/443; deny-all defaults
Azure Bastion Browser-based admin access to jump hosts Removes public RDP/SSH; admin plane Zero Trust Standard SKU; no public IPs on VMs; native client + just-in-time where used
Log Analytics + Defender for Cloud + Sentinel Observability, posture, and threat detection “Continuously monitor” Diagnostic settings from every resource; Defender plans for App Service/SQL/Storage/Key Vault; WAF and sign-in logs streamed to Sentinel

A few configuration choices deserve emphasis because they are where most “Zero-Trust” designs quietly cheat:

Implementation guidance

Resource topology. Provision a hub-and-spoke layout: a hub VNet (vnet-hub, e.g. 10.0.0.0/22) containing AzureFirewallSubnet, AzureBastionSubnet, and the Private DNS zone links; and an application spoke (vnet-app, e.g. 10.1.0.0/22) with snet-appgw (App Gateway, /24), snet-app (App Service VNet-integration delegation, /24), and snet-data (private endpoints, /24). Peer the spoke to the hub and apply a UDR on snet-app and snet-data with a 0.0.0.0/0 next hop of the Azure Firewall private IP to force-tunnel egress.

IaC. Treat the whole thing as code; this architecture has too many interdependent private-DNS and RBAC wirings to click through reliably.

Identity wiring. Register the app in Entra ID; configure the redirect URI to the App Gateway hostname (not the App Service default hostname). Turn on Easy Auth with the Entra provider (requireAuthentication: true, unauthenticatedClientAction: RedirectToLoginPage) so unauthenticated requests never reach app code, or implement MSAL in-app if you need fine-grained control. Author Conditional Access as code through Microsoft Graph / Terraform azuread: a policy targeting the app’s enterprise application that requires MFA + compliant device, plus tenant-wide policies blocking legacy auth and acting on sign-in risk. Enable Continuous Access Evaluation so token revocation (user disabled, risk detected) propagates in near-real-time instead of waiting for token expiry.

Managed-identity data access. Enable the system-assigned managed identity on the App Service. Grant it:

In code, use DefaultAzureCredential (Azure SDK) so the same code path uses the managed identity in Azure and the developer’s az login locally — no connection strings, no secrets in appsettings.

App Gateway + WAF. Deploy WAF_v2 with a separate Microsoft.Network/applicationGatewayWebApplicationFirewallPolicies resource in Prevention mode, OWASP CRS 3.2 plus the Bot Manager ruleset. Configure the HTTP settings for end-to-end TLS (backend protocol HTTPS), a health probe, and cookieBasedAffinity only if the app is not stateless. Reference the App Service via its private endpoint FQDN as the backend pool target (the App Gateway resolves it through the linked Private DNS zone).

Enterprise considerations

Security & Zero Trust. This architecture implements all five Zero-Trust signals: verify explicitly (Entra + Conditional Access on every sign-in, CAE for continuous re-evaluation), least privilege (RBAC + PIM for admins, managed-identity-scoped data grants), assume breach (WAF inspection, Azure Firewall egress control, deny-by-default NSGs), no implicit network trust (private endpoints + Public access Disabled everywhere), and no standing secrets (managed identities; Key Vault only for irreducible secrets, fetched at runtime). The single most valuable property: a leaked SQL connection string — the exact incident class this org has suffered before — is now useless, because SQL is Entra-only and unreachable from the public internet.

Cost optimization. The dominant line items are App Gateway WAF_v2 (fixed instance + capacity-unit charges), private endpoints (a per-endpoint hourly charge plus data processing), and Azure Firewall (the most expensive single component). Tactics: in smaller estates, drop Azure Firewall and rely on NSGs + a NAT Gateway for egress, or use Azure Firewall Basic; share private endpoints and DNS zones across multiple apps in the same platform landing zone rather than per-app; right-size App Gateway autoscale floor to 2 in prod and 0–1 in non-prod; and use Front Door only when you genuinely need multi-region or global edge — a single-region app does not. For non-prod, collapse the data tier to public-access-disabled + service endpoints to save private-endpoint cost while keeping the data plane off the internet.

Scalability. App Gateway WAF_v2 autoscales on capacity units; the App Service/Container Apps tier scales horizontally (and Container Apps scales to zero for spiky workloads). SQL scales via vCore tiers or Hyperscale; storage is effectively unbounded. Because the data plane is private-endpoint-based, scaling out the app tier needs no firewall-rule changes — new instances inherit VNet integration and the same managed-identity grants.

Reliability & DR (RTO/RPO). Make App Gateway, App Service, and SQL zone-redundant within the region for an in-region RTO of near-zero and RPO of zero for zonal failures. For regional DR: deploy the spoke into a secondary region, use SQL active geo-replication or a failover group (RPO seconds, RTO minutes), GZRS/RA-GRS storage, and Front Door to health-probe and fail traffic over. A typical posture: RPO ≤ 5 s (failover group) and RTO ≤ 15 min (automated Front Door failover + warm secondary). Private endpoints and Private DNS must be pre-provisioned in the secondary region, since they are the slowest things to stand up during an incident.

Observability. Stream diagnostic settings from every component to Log Analytics: App Gateway access + WAF logs (blocked rule IDs, matched OWASP rules), App Service logs, SQL auditing, Key Vault access, and NSG flow logs. Defender for Cloud scores posture and flags drift (e.g., if someone re-enables public access). Sentinel correlates WAF blocks with Entra risky sign-ins to detect coordinated attacks. Alert on: WAF block-rate spikes, Conditional Access failures, managed-identity token failures, and any change to publicNetworkAccess.

Governance. Enforce the architecture with Azure Policy: deny resources where publicNetworkAccess != Disabled, deny Storage accounts with shared-key auth enabled, require private endpoints on SQL/Storage/Key Vault, require diagnostic settings, and audit Conditional Access coverage. Manage admin access with PIM (just-in-time, approval-gated, time-boxed roles). Wrap the whole thing in a landing zone so every new app inherits the policy set, the shared DNS zones, and the hub by default.

Reference enterprise example

NorthBridge Mutual, a mid-sized regional insurer (~3,200 employees, ~1.1M policyholders), is moving its legacy on-prem claims portal to Azure. The portal lets policyholders file and track claims and lets ~600 internal adjusters work cases. Drivers: a state regulator now requires that “customer PII data stores have no public network exposure,” and the security team is still smarting from a prior incident where a connection string leaked in a contractor’s Git push — exactly the scenario the new design must neutralize.

Decisions.

Realistic numbers. Steady state runs ~6 Container Apps replicas, bursting to ~40 after a major weather event. SQL Hyperscale at 8 vCores. The platform team measured a representative monthly bill of roughly ₹1.95–2.4 lakh for the production estate (App Gateway WAF_v2 ~₹38k, Container Apps ~₹55k, SQL Hyperscale ~₹70k, private endpoints + DNS ~₹9k, Firewall Basic share ~₹18k, Storage + egress + Defender/Sentinel ~₹25k), with non-prod at roughly a third of that thanks to scale-to-zero and service-endpoint data tiers. DR posture validated at RPO ~5 s / RTO ~12 min in a game-day failover test.

Outcome. The regulator’s auditor accepted the design on the first pass: every PII store returned Public network access: Disabled, and the auditor’s own attempt to resolve nbm-claims-sql.database.windows.net from outside the VNet returned a private 10.1.x address that didn’t route. Three months later, a penetration-test vendor was given a valid-looking SQL connection string (seeded to simulate the old leak) and could do nothing with it — SQL was Entra-only and unreachable. The WAF blocked ~14,000 OWASP/bot hits in its first month with zero false-positive escalations after a two-week tuning window. The platform team operates the whole thing with a 4-person crew and no dedicated 24/7 SOC, relying on Defender + Sentinel analytics rules and on-call alerting.

When to use it

Use this architecture when you have a web application handling sensitive or regulated data, an organization that has standardized (or wants to standardize) on Entra ID, a compliance mandate to remove public data-plane exposure, and a platform team capable of operating IaC and a VNet. It scales down to a single app and up to a landing-zone-wide standard.

Trade-offs. It is more expensive and more operationally involved than a public App Service + SQL firewall rule. Private endpoints add per-endpoint cost and DNS complexity — the number-one operational footgun is a missing or mis-linked Private DNS zone, which produces baffling “works from the portal, fails from the app” connectivity bugs. Local development requires az login + DefaultAzureCredential discipline (or a dev VNet) because the data plane isn’t reachable from a laptop.

Anti-patterns to avoid.

Alternatives. For a low-sensitivity public marketing site, this is over-engineered — a public Static Web App or App Service with Front Door WAF is fine. If you need the app itself fully air-gapped from the internet for internal users only, replace the public App Gateway with an internal (private) App Gateway reachable over ExpressRoute/VPN — the rest of the data-plane pattern is identical. If you’re multi-cloud or want the WAF and identity decoupled from Azure, an external IdP + a third-party WAF can substitute, at the cost of losing the tight Entra/Conditional Access/managed-identity integration that makes this design cohesive. And if your scale is genuinely tiny and budget is the hard constraint, the EasyAuth-on-SWA pattern (Static Web Apps with built-in Entra auth, no App Gateway, service-endpoint data tier) is a lighter on-ramp that you can graduate from into this full topology later.

AzureArchitectureEnterpriseReference Architecture
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

Keep Reading