Azure Architecture
What gets deployed when you run infra:deploy on Azure and how traffic flows through the system.
High-Level Architecture
Standard vs Premium Tier
The architecture has two security tiers controlled by the frontdoorPremium toggle in infrastructure.json.
Standard — secure by default
Standard is the default and provides strong security within Azure's constraints. Front Door terminates TLS at the edge, applies WAF rules, and forwards traffic to your origins. Since Azure Standard Front Door doesn't include Microsoft's managed WAF rulesets, tsdevstack generates ~75 custom WAF rules that cover the same ground: SQLi, XSS, path traversal, command injection, SSRF, scanner fingerprints, known CVEs, rate limiting, and protocol abuse.
Origin protection uses App Service Access Restrictions — a platform-level networking feature. The generated Terraform sets ip_restriction_default_action = "Deny" on each App Service, with a single Allow rule for the AzureFrontDoor.Backend service tag filtered by the Front Door instance's FDID (x_azure_fdid header). Traffic that doesn't match is rejected by Azure's platform before it ever reaches your container. The origins do have public endpoints, but the platform denies any request that didn't come through your specific Front Door instance.
Premium — Private Link + managed rulesets (+$295/month)
Premium adds two things. First, Private Link origins — Front Door connects to App Service over Azure's backbone network instead of the public internet. Your origins have zero public surface. Second, Microsoft managed WAF rulesets (DRS 2.1 Default Rule Set + Bot Manager 1.1) — professionally maintained rules updated by Microsoft's security team. With managed rulesets handling SQLi, XSS, and common attack patterns, the custom rule count drops from ~75 to ~31 (covering rate limiting, restricted paths, scanner fingerprints, CVE patterns, and protocol abuse that managed rulesets don't address).
Comparison
Standard is production-ready — the 75 custom WAF rules provide equivalent coverage to the managed rulesets. Premium is worth it when you need Private Link for compliance requirements (e.g. zero public surface) or prefer Microsoft-maintained WAF rules over custom ones.
WAF rules can be customized via infrastructure.json — including custom match rules and rate limit rules using Azure's native match conditions. See Service Configuration — WAF Rules for details.
Compute: App Service + Container Apps
App Service (Kong + Next.js):
- Kong and Next.js run on App Service (not Container Apps) for:
- Front Door Access Restrictions with FDID header validation
- Always-available gateway (
always_on: true)
- Default SKU: B1 (
$13/month per plan). S1 ($69/month) for auto-scaling - VNet integrated for outbound traffic to Container Apps
Container Apps (NestJS backends):
- Consumption plan with ILB (Internal Load Balancer) — no public IP
- KEDA HTTP scaling enables scale-from-zero with automatic wake-up (2-5s cold start)
- Services are VNet-accessible only via ILB static IP + private DNS zone
Data: PostgreSQL + Managed Redis
PostgreSQL Flexible Server:
- VNet-integrated (postgres subnet, no public access)
- Databases created directly by Terraform (no separate init task, unlike AWS)
- Default:
B_Standard_B1ms(~$14/month, burstable) - Migrations run via Container Apps Jobs (in VNet, can reach PostgreSQL)
Azure Managed Redis:
Balanced_B0(~$13/month) withEnterpriseClusterpolicy- Private endpoint only (no public access)
- TLS required, dynamic port (from Terraform output)
BullMQ compatibility: Azure Managed Redis uses EnterpriseCluster clustering policy. BullMQ requires a {bull} prefix to force all keys to the same hash slot, avoiding CROSSSLOT errors. This is Azure-specific — GCP and AWS don't use clustering at the basic tier.
Storage: Azure Blob Storage
When storage buckets are configured in config.json, Terraform creates a shared storage account with blob containers:
- One storage account per project-env:
{project}{env}storage(alphanumeric only, max 24 chars) - One blob container per logical bucket name
- Soft delete enabled (7-day retention)
- CORS set to
*(presigned URLs are the security boundary)
IAM: The Container Apps managed identity gets the Storage Blob Data Contributor role on the storage account.
Special: AZURE_STORAGE_ACCOUNT_NAME is injected as an environment variable on Container Apps (not a secret — it's a Terraform output). The Azure Blob adapter uses this alongside managed identity for authentication.
No client secrets in containers — Container Apps use managed identity automatically.
For setup and usage, see Object Storage.
Edge: Front Door
Azure Front Door replaces three AWS services (CloudFront + ALB + ACM) with one unified service.
Features:
- CDN with global edge caching
- WAF (custom rules or managed rulesets depending on tier)
- Managed SSL certificates (auto-provisioned)
- Load balancing across origin groups
Standard tier WAF (~75 custom rules):
Premium tier: Bands 500-899 are replaced by Microsoft's managed rulesets (DRS 2.1 + Bot Manager), with ~31 custom rules covering rate limiting, restricted paths, scanner fingerprints, CVE patterns, and protocol abuse.
Access Logging:
- Diagnostic settings on Front Door profile capture three log categories:
FrontDoorAccessLog— all incoming requestsFrontDoorHealthProbeLog— health probe trafficFrontDoorWebApplicationFirewallLog— WAF allow/block decisions
- Logs are sent to a Log Analytics workspace
Networking
Kong (App Service) resolves Container App FQDNs via a private DNS zone with a wildcard A record pointing to the CAE internal static IP.
Secrets: Key Vault
RBAC mode (not legacy Access Policies). Two principals with different roles:
Zero-credential runtime: Container Apps need SECRETS_PROVIDER=azure, AZURE_CLIENT_ID (set to the managed identity's client ID), and AZURE_KEYVAULT_NAME as env vars. No service principal credentials are needed — the user-assigned managed identity handles both ACR image pulls and Key Vault access.
Secret naming auto-transforms underscores to hyphens: DATABASE_URL > DATABASE-URL.
Scale-to-Zero
Container Apps use KEDA HTTP scaling — services scale to zero when idle and wake automatically on the next request (2-5s cold start). No wake-up mechanisms needed.
Kong runs on App Service with always_on: true — always available with no cold start.
Security
- Standard: Front Door validates requests via Access Restrictions with FDID header matching
- Premium: Front Door connects via Private Link (zero public surface on App Service origins)
- Backend services are in ILB Container Apps Environment (no public IP)
- NSG rules: Allow LoadBalancer + VNet traffic, deny all others
- Managed Identity for zero-credential runtime (no secrets in containers)
Cost Estimation
See Azure Cost Estimation for a detailed breakdown across development (scale-to-zero), production (always-on), and scaled scenarios, including Standard vs Premium tier comparisons and links to official Azure pricing pages.
Async Messaging
Async messaging uses Redis Streams on the same Azure Cache for Redis instance used for caching and BullMQ. No additional Azure resources are created — messaging is a framework-level feature that runs on existing infrastructure. See Async Messaging for details.
Terraform Resources
Azure deployments create approximately 25-30 Terraform resources — the fewest of all three providers. This includes VNet, subnets, Container Apps Environment, App Service plans, Front Door profile with WAF policy, PostgreSQL Flexible Server, Managed Redis, Key Vault, ACR, DNS zones, and Managed Identity role assignments.