Azure Front Door & CDN
Key Points
- Azure Front Door (AFD) is a global L7 load balancer + CDN + WAF, anycast-routed via Microsoft's edge POPs.
- Standard vs Premium: Standard for basic CDN + WAF; Premium adds private-link to origins, advanced WAF (bot protection, managed rules), private DDoS, security insights.
- Azure CDN (the older standalone product, with Akamai/Verizon/Microsoft variants) is deprecated for new deployments; Front Door subsumes its role.
- WAF evaluates managed rule sets (OWASP CRS, Microsoft Default), bot-manager, custom rules, rate-limit — at the edge, before traffic hits origin.
- Compare: AFD = global edge L7. App Gateway = regional L7 inside VNet. Often combined: AFD → App Gateway → AKS.
Concepts (deep dive)
What AFD is
Front Door is a global L7 entry point that sits between your users and your origins. It exists because a single-region web app has two structural problems: users in Sydney pay the same latency penalty as users in the same region, and the entire app fails when the region does. AFD solves both by accepting traffic at hundreds of POPs near the user (anycast routing), terminating TLS at the edge, running WAF and caching before the request ever crosses an ocean, and then routing to whichever origin is currently healthy. The Microsoft-owned backbone between POP and origin is the underrated bonus — cache misses don't have to traverse the public internet.
Internet
│
anycast IP (one IP,
many POPs answer)
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ POP-NYC │ │ POP-AMS │ │ POP-SYD │ AFD edge:
│ TLS │ │ TLS │ │ TLS │ - terminate TLS
│ WAF │ │ WAF │ │ WAF │ - filter (WAF)
│ cache │ │ cache │ │ cache │ - cache static
└────┬────┘ └────┬────┘ └────┬────┘ - route to origin
│ │ │
└───────────────┴───────────────┘
│
Microsoft backbone (not public internet)
│
┌──────────┴──────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ origin group │ │ origin group │ priority/weight,
│ (region 1) │ │ (region 2) │ health probes,
│ App Service │ │ App Service │ active failover
└──────────────┘ └──────────────┘
A globally-distributed reverse proxy: clients hit Microsoft's nearest POP via anycast IP, AFD terminates TLS, runs WAF, caches responses, and forwards to your origin (App Service, Container Apps, Storage, AKS, third-party).
anycast IP
client (US) ─────────────────► POP-EastUS ──► WAF ──► cache ──► origin
client (EU) ─────────────────► POP-Amsterdam┘
client (AU) ─────────────────► POP-Sydney ┘
300+ POPs worldwide; clients reach the nearest by BGP.
Tiers
| Feature | Standard | Premium |
|---|---|---|
| Global L7 LB | ✅ | ✅ |
| CDN caching | ✅ | ✅ |
| Managed certs | ✅ | ✅ |
| WAF (custom rules) | ✅ | ✅ |
| WAF managed rule sets (OWASP, MSDefault) | ❌ | ✅ |
| Bot protection | ❌ | ✅ |
| Private Link to origins | ❌ | ✅ |
| Security Insights (analytics) | ❌ | ✅ |
| Per-rule rate limit | Limited | Full |
For anything internet-facing in production, Premium. The WAF managed rules and bot manager are the real differentiators.
Anycast routing
A single IP is announced from every POP. BGP routes the client to the topologically nearest POP. From there, AFD picks an origin based on health + routing rules.
1. Client DNS → AFD endpoint (e.g., myapp-abc.z01.azurefd.net)
2. AFD endpoint resolves to anycast IP
3. BGP delivers to nearest POP
4. POP picks healthy origin (priority + weight)
5. POP→origin over Microsoft backbone (not public internet)
Microsoft backbone between POP and origin is the under-appreciated win — even cache misses are fast because POP-to-origin doesn't traverse the public internet.
Origin health probes
HTTP probe → /health → expects 2xx → mark healthy
fails N times → mark unhealthy → stop sending traffic
Configure path, interval (default 100s, can go to 30s), HTTP method, expected status. Probes come from all POPs — don't whitelist a single IP.
Routing rules
Each route binds: a hostname/path pattern → an origin group → optional rule set → caching config.
Route 1: /api/* → origin-group-api (no cache)
Route 2: /static/* → origin-group-blob (cache 1d)
Route 3: /* → origin-group-spa (cache 1h)
Rule engine actions: URL rewrite, request-header modify, response-header modify, redirect, set caching, route override.
match: $url.path matches /api/v1/(.*)
action:
url_rewrite: /v1/$1
request_headers_add: X-Forwarded-By: AFD
TLS / SSL
| Mode | What |
|---|---|
| AFD-managed cert | Free, auto-rotated, for custom domains. Default. |
| Bring your own cert | From Key Vault. AFD reads via managed identity. |
| End-to-end TLS | AFD → origin re-encrypts (recommended). |
| HTTP→HTTPS redirect | A rule on the route. |
resource cert 'Microsoft.Cdn/profiles/secrets@2023-05-01' = {
parent: profile
name: 'corp-com-cert'
properties: {
parameters: {
type: 'CustomerCertificate'
secretSource: { id: kvSecret.id }
useLatestVersion: true
}
}
}
Caching
Cache key = hostname + path + selected query params + selected headers.
Cache key:
hostname: www.example.com
path: /products/42
query: ?lang=en (if "lang" in cache_query_string list)
vary: Accept-Encoding
Controls:
- Query string handling: ignore all / use all / use specified / use all except specified.
- Compression: gzip/brotli for text MIME types.
- Cache duration: from origin
Cache-Control, or override in rule engine. - ETag / Last-Modified: passthrough; AFD revalidates with origin on expiry.
- Purge API:
az afd endpoint purge— wildcard or single path.
WAF (Premium really shines here)
[ Managed rule sets ]
- Microsoft Default Rule Set (DRS) ← recommended
- OWASP Core Rule Set 3.x
- Bot Manager (Premium)
[ Custom rules ]
- rate-limit per IP / per cookie / per header
- geomatch (block country codes)
- IP allow/deny lists
- signature matches on body / header / URL
Modes: Detection (log only) | Prevention (block 403)
Standard rollout: deploy in Detection mode for days, review logs (Log Analytics), tune false positives, then flip to Prevention.
resource waf 'Microsoft.Network/FrontDoorWebApplicationFirewallPolicies@2024-02-01' = {
name: 'wafpol'
location: 'global'
sku: { name: 'Premium_AzureFrontDoor' }
properties: {
policySettings: { mode: 'Prevention', enabledState: 'Enabled' }
managedRules: {
managedRuleSets: [
{ ruleSetType: 'Microsoft_DefaultRuleSet', ruleSetVersion: '2.1' }
{ ruleSetType: 'Microsoft_BotManagerRuleSet', ruleSetVersion: '1.0' }
]
}
customRules: {
rules: [{
name: 'RateLimit'
priority: 1
ruleType: 'RateLimitRule'
rateLimitDurationInMinutes: 1
rateLimitThreshold: 100
action: 'Block'
matchConditions: [{
matchVariable: 'RemoteAddr'
operator: 'IPMatch'
matchValue: ['0.0.0.0/0']
}]
}]
}
}
}
WebSocket / long-poll
AFD supports HTTP/1.1 Upgrade to WebSocket and long-polling. Idle timeout default ~4 minutes — for long-running sockets, send keepalive pings.
vs Azure CDN (legacy)
Azure CDN (the standalone product with Akamai, Verizon, Microsoft variants) was the older offering. Microsoft has been retiring those: Edgio (Verizon) was retired Jan 2025, Akamai SKUs are deprecated. New CDN-only deployments are routed through Front Door Standard. If you have legacy *.azureedge.net endpoints, plan migration to AFD.
vs cloud peers
| AFD Premium | AWS CloudFront + WAF | Cloudflare | |
|---|---|---|---|
| POPs | 300+ | 600+ | 320+ |
| Native cloud integration | Azure | AWS | Cloud-agnostic |
| Pricing model | Per-GB + per-rule | Per-GB + per-request | Tiered SaaS |
| WAF maturity | Strong | Strong (AWS WAFv2) | Best-of-breed |
| DDoS | Included L¾; Premium adds L7 | Shield Std incl; Adv paid | Built in |
For an Azure-resident app, AFD is usually the right choice — origins on Microsoft backbone, Entra ID, single bill.
vs Application Gateway
| Front Door | App Gateway | |
|---|---|---|
| Scope | Global edge | Regional, in-VNet |
| LB layer | L7 | L7 |
| WAF | Yes | Yes (different engine) |
| Private IPs | No (public-only) | Public + private |
| Routes to private VMs | No (public origin or PE) | Yes (VNet-native) |
| Caching / CDN | Yes | No |
Combined pattern (very common in regulated shops):
AFD does global routing + DDoS + cache; AGW does the inside-VNet, path-based routing to internal services. Some compliance frameworks (FedRAMP, PCI) prefer this layered model.
Custom domains
1. Add custom domain (www.example.com) to AFD endpoint
2. AFD shows a TXT/CNAME validation token
3. Add to your DNS (Azure DNS or external)
4. Approve domain → AFD provisions managed cert (~30 min)
5. Switch DNS to CNAME to AFD endpoint
Apex domain (example.com without www) — use Azure DNS Alias record to ALIAS the AFD endpoint, since CNAMEs aren't valid at the apex.
Origins
| Origin | Notes |
|---|---|
| App Service | Restrict access to AFD via service tag + AFD ID header |
| Container Apps | Same — lock to AFD origin only |
| Storage (static site) | Public blob endpoint or origin-PE (Premium) |
| AKS / AGW | Public IP or via Private Link Service (Premium) |
| Third-party / on-prem | Public hostname + IP allowlist |
Lock origin to AFD only — origin shouldn't accept public traffic that bypasses AFD/WAF. Two ways:
- IP service tag
AzureFrontDoor.Backendin NSG / App Service access restriction. X-Azure-FDIDheader check — AFD adds your Front Door ID; origin rejects requests without it.
Cost shape
- Per-GB egress from POPs to clients (the dominant cost for high-traffic sites).
- Per-request (small, but adds up at scale).
- WAF: per-policy + per-million-requests evaluated.
- Routing rules engine: per-evaluation.
- Managed certs: free.
Caching at the edge is the biggest cost lever — a 90% cache hit rate on static assets cuts origin egress and origin compute.
Minimal Bicep
param profileName string = 'afd-prod'
param endpointName string = 'web-prod'
param originHost string = 'myapp.azurewebsites.net'
resource profile 'Microsoft.Cdn/profiles@2023-05-01' = {
name: profileName
location: 'global'
sku: { name: 'Premium_AzureFrontDoor' }
}
resource endpoint 'Microsoft.Cdn/profiles/afdEndpoints@2023-05-01' = {
parent: profile
name: endpointName
location: 'global'
properties: { enabledState: 'Enabled' }
}
resource originGroup 'Microsoft.Cdn/profiles/originGroups@2023-05-01' = {
parent: profile
name: 'og-app'
properties: {
loadBalancingSettings: { sampleSize: 4, successfulSamplesRequired: 3 }
healthProbeSettings: {
probePath: '/health'
probeProtocol: 'Https'
probeIntervalInSeconds: 60
probeRequestType: 'GET'
}
}
}
resource origin 'Microsoft.Cdn/profiles/originGroups/origins@2023-05-01' = {
parent: originGroup
name: 'origin-app'
properties: {
hostName: originHost
httpsPort: 443
originHostHeader: originHost
priority: 1
weight: 1000
enabledState: 'Enabled'
}
}
resource route 'Microsoft.Cdn/profiles/afdEndpoints/routes@2023-05-01' = {
parent: endpoint
name: 'default'
properties: {
originGroup: { id: originGroup.id }
supportedProtocols: ['Http', 'Https']
patternsToMatch: ['/*']
forwardingProtocol: 'HttpsOnly'
httpsRedirect: 'Enabled'
linkToDefaultDomain: 'Enabled'
}
}
Code: correct vs wrong
❌ Wrong: origin accepts public traffic
App Service open to the world; users can bypass AFD/WAF by hitting *.azurewebsites.net directly.
✅ Correct: lock origin to AFD
App Service Access Restrictions:
Allow: service-tag AzureFrontDoor.Backend (with X-Azure-FDID header check)
Deny: all others
❌ Wrong: WAF straight to Prevention
False positives blocking real users.
✅ Correct: Detection mode → tune → Prevention
Run in detect for 1-2 weeks; review WAF logs; tune false positives; then flip.
❌ Wrong: caching API responses by default
Authenticated user data leaks to other users.
✅ Correct: only cache safe paths
Route /api/*: cache_disabled
Route /static/*: cache 1d
Route /*: cache 1h with Vary on Accept-Encoding
Design patterns for this topic
Pattern 1 — "AFD Premium + WAF managed rules + bot manager"
- Intent: edge security baseline.
Pattern 2 — "Detection-first WAF rollout"
- Intent: avoid blocking real users; tune before prevention.
Pattern 3 — "Lock origin to AFD only"
- Intent: no bypass paths.
Pattern 4 — "AFD → App Gateway → AKS"
- Intent: layered global + regional WAF; internal-only origins.
Pattern 5 — "Cache-by-path strategy"
- Intent: cache static, never cache API responses.
Pros & cons / trade-offs
| Aspect | Pros | Cons |
|---|---|---|
| AFD | Global, MS backbone, integrated WAF | No private IPs |
| Premium | Best WAF, private link, bot manager | Higher per-day cost |
| Caching | Cheap, fast | Stale-content risk |
| WAF | Edge-blocking SQLi/XSS | False positives until tuned |
| Combined AFD+AGW | Defense-in-depth | Double hops, two WAF rule sets |
When to use / when to avoid
- Use for any internet-facing app that wants edge caching + WAF.
- Use Premium for production (managed rules, bot manager, private link).
- Use AFD + AGW for regulated workloads.
- Avoid for purely internal apps — App Gateway alone suffices.
- Avoid legacy Azure CDN endpoints for new deployments.
Interview Q&A
Q1. Front Door vs App Gateway? AFD: global edge, anycast, CDN + WAF, public-only. AGW: regional, in-VNet, can route to private IPs. Often combined.
Q2. Standard vs Premium AFD? Premium adds managed WAF rule sets, bot manager, Private Link to origins, security insights.
Q3. How does anycast routing work? Single IP advertised from every POP; BGP delivers client to topologically nearest POP.
Q4. WAF rollout best practice? Start in Detection mode; review logs; tune false positives; flip to Prevention.
Q5. How to lock origin to AFD? Service-tag access restriction (AzureFrontDoor.Backend) + check X-Azure-FDID header.
Q6. Cache key composition? Host + path + configured query strings + Vary headers.
Q7. End-to-end TLS? Client→AFD encrypted; AFD→origin re-encrypted. Configure forwarding protocol HttpsOnly.
Q8. Apex domain? Use Azure DNS Alias record (CNAME isn't valid at apex).
Q9. Azure CDN status? Standalone CDN (Akamai/Verizon SKUs) deprecated; new deployments use AFD.
Q10. WAF rule sets? Microsoft Default Rule Set (DRS), OWASP CRS, Bot Manager (Premium).
Q11. Custom domain managed cert? Free, AFD-issued, auto-rotated. ~30 min provision after DNS validation.
Q12. Origin health probe constraints? Probes come from all POPs — can't whitelist by IP. Use service tag.
Gotchas / common mistakes
- ⚠️ Origin open to public — bypass AFD entirely.
- ⚠️ WAF straight to Prevention — blocks legit users.
- ⚠️ Caching authenticated responses — cross-user data leak.
- ⚠️ Mutable images in container apps with cache — old code keeps serving.
- ⚠️ Forgot DNS Alias for apex — CNAME at apex fails.
- ⚠️ Idle timeout on WebSockets — 4-min default; send keepalives.
- ⚠️ Mixing legacy Azure CDN + AFD for the same domain — confusing routing.