Skip to content

PATTERN Cited by 2 sources

ALB path routing per tenant

Pattern

Use one Application Load Balancer per infra group with per-tenant listener rules that inspect a tenant identifier in the request (path or HTTP header) and forward to the tenant's dedicated target group. Each target group points at the tenant's dedicated ECS cluster. No tenant's traffic ever lands on another tenant's target group.

Canonicalised on the wiki by the 2026-05-12 AWS Architecture Blog post (Source: sources/2026-05-12-aws-building-hybrid-multi-tenant-architecture-for-stateful-services). Verbatim:

"Each infra group contains one Application Load Balancer. The load balancer inspects incoming requests and forwards them to the correct tenant's ECS service based on a tenant identifier extracted from the request path or a custom HTTP header. ... ALB listener rules route traffic exclusively to the correct tenant's target group based on the tenant identifier."

How this differs from

patterns/shared-alb-path-based-multi-cluster-routing

The pattern structurally overlaps but has different tenant models:

Pattern Tenants Target Blast radius
ALB path routing per tenant (this) Production SaaS tenants (customers) Dedicated ECS cluster per tenant 1/N × tenant_count (per-ALB)
Shared ALB path-based multi-cluster routing (Deloitte vCluster) Test / pre-prod environments vCluster virtual K8s clusters All vclusters on the ALB

Both patterns use ALB path-based routing to aggregate many backends behind a single load balancer. This pattern canonicalises the production-SaaS-tenant variant; the vCluster variant canonicalises the test-environment variant. They share the ALB config mechanics but differ on SLA and blast-radius posture.

Shape

Listener rule per tenant

Each tenant gets a listener rule on the shared HTTPS listener:

  • Condition: path-pattern matches /tenant-a/* (or an HTTP header with tenant identifier).
  • Action: forward to the tenant's target group.
  • Priority: unique per tenant; ordering determines precedence if paths overlap.

Per the canonical source:

# Create a target group for the tenant
aws elbv2 create-target-group \
  --name tg-tenant-a \
  --protocol HTTP --port 8080 \
  --vpc-id YOUR_VPC_ID \
  --target-type ip

# Add a listener rule routing /tenant-a/* to the target group
aws elbv2 create-rule \
  --listener-arn YOUR_LISTENER_ARN \
  --conditions '[{"Field":"path-pattern","Values":["/tenant-a/*"]}]' \
  --actions '[{"Type":"forward","TargetGroupArn":"YOUR_TARGET_GROUP_ARN"}]' \
  --priority 10

Header-based variant

Alternatively, use a custom HTTP header (X-Tenant-ID: tenant-a) with http-header condition. Advantages:

  • Tenant identifier not visible in URL logs / analytics.
  • No URL-path rewriting required on the client.
  • Cleaner for machine-to-machine APIs.

Disadvantages:

  • Requires client cooperation to set the header.
  • Less debuggable from raw network captures.

Capacity math

AWS ALB quotas (from the canonical post):

Quota Value
Target groups per ALB 100
Target groups per listener rule 5
Listener rules per ALB (practical) ~20
Target-group capacity per ALB 20 × 5 = 100
Tenants per infra group (avg 2 TGs/tenant) ~50
Tenants per infra group (1 TG/tenant) up to 100

A single ALB supports up to ~50 tenants with typical stateful-service target-group topology. When the tier approaches this limit, add a new infra group (see patterns/tier-cell-infra-group-hierarchy).

Why this routing grain is load-bearing

  • No application-layer routing. The ALB's L7 inspection replaces application-side tenant-dispatch code. Each tenant's ECS cluster serves only its own tenant's traffic; no tenant identifier propagation needed at the application layer for routing purposes.
  • Per-tenant metrics fall out naturally. ALB target-group metrics (TargetResponseTime, HTTPCode_Target_5XX_Count, HealthyHostCount) are already dimensioned by target group, which is per-tenant. No application-layer tagging required.
  • Tenant onboarding = listener rule add + target group add + ECS cluster register. Three API calls; no code change.

Configuration-driven onboarding

Onboarding a new tenant is reduced to:

  1. Create target group (aws elbv2 create-target-group).
  2. Add listener rule (aws elbv2 create-rule).
  3. Register ECS service as target.

Steps 1 and 2 are idempotent configuration operations. No networking, IAM, or cross-account work. Step 3 is standard ECS service-level operation.

This is the configuration-driven part of patterns/configuration-driven-tenant-onboarding.

Observability

  • TargetResponseTime per target group = per-tenant latency (baseline 100–200 ms for stateful services; alert on 2× baseline for >5 min).
  • HTTPCode_Target_5XX_Count per target group = per-tenant error rate.
  • RequestCount per target group = per-tenant QPS.
  • HealthyHostCount per target group = per-tenant capacity health.

All dimensioned by target group name; target group names encode tenant identity by convention (tg-tenant-a).

When to use

  • Many small-to-medium tenants on shared infra. Canonical use case.
  • Tenants with identifiable request-path or header namespacing. Path /tenant-a/* or header X-Tenant-ID: tenant-a must be derivable from the request.
  • Per-tenant latency / error-rate SLAs. Target-group metrics give this for free.
  • Tenants with dedicated backend clusters (per patterns/dedicated-ecs-cluster-per-tenant).

When not to use

  • Tenants share a backend (e.g., shared ECS cluster with application-layer dispatch). A single target group per backend is simpler; the ALB can't add value.
  • Tenant identifier is embedded in request body, not path / header. ALB can't inspect bodies; needs an application-layer routing tier.
  • Very large tenant counts (>50 per ALB). Need multiple ALBs (multiple infra groups).
  • Per-tenant TLS certificates (mTLS with tenant-specific client cert validation). Single ALB uses one server cert.

Anti-patterns

  • One listener rule with multiple target groups and application-layer dispatch. Defeats the per-tenant observability property.
  • Path-rewriting at the ALB to strip tenant identifier before forwarding. Works, but the application loses the routing context; makes debugging harder.
  • Shared target group across tenants. Re-introduces noisy neighbor at the target-group-health-check level.
  • Per-tenant listener (vs per-tenant rule on a shared listener). Wastes listener allocation; ALB listener count has stricter quotas than rule count.
  • Priority collisions. Overlapping path patterns with identical priorities cause ALB misrouting; priority must be unique per rule.

Caveats

  • Path-based tenant identifiers leak tenant identity in URLs and logs. For audit or privacy purposes, consider header-based routing.
  • Tenant set is bounded by ALB quotas. At ~50 tenants per infra group, horizontal scale via patterns/tier-cell-infra-group-hierarchy is required.
  • Listener rules evaluate in priority order. Careful priority management is required for correct routing when path patterns overlap.
  • Per-rule target-group limit is 5. A tenant needing >5 backend services on one path requires additional listener rules or path refinement.
  • ALB path-based routing doesn't support complex routing logic (geo-based, A/B tests, canary). Those need application-layer or service-mesh routing.

Seen in

Last updated · 542 distilled / 1,571 read