AWS Logo
Menu
Streamline Your SaaS Tenant Routing at the Edge with Amazon CloudFront Functions and KeyValueStore

Streamline Your SaaS Tenant Routing at the Edge with Amazon CloudFront Functions and KeyValueStore

In today's SaaS landscape, efficiently routing tenant traffic is critical for maintaining performance, scalability, and isolation. Amazon CloudFront Functions now offers a powerful, cost-effective solution for dynamic tenant routing that outperforms traditional approaches.

Daniel Wirjo
Amazon Employee
Published Apr 6, 2025
Last Modified Apr 7, 2025
This post is co-written with Anthony Kawamoto, Senior Solutions Architect.

Introduction

When designing multi-tenant SaaS applications, efficiently routing tenant traffic is critical for maintaining performance, scalability, and isolation. In a previous post on Tenant routing strategies for SaaS applications on AWS, we explored two strategies: domain-driven and data-driven routing.
This post dives deeper into data-driven routing, covering the role of edge functions, particularly Amazon CloudFront Functions, and comparing them to Lambda@Edge. Edge functions excel when you need dynamic request routing based on request attributes (headers, cookies, or JWT tokens) with minimal latency. They perform best in advanced scenarios requiring real-time decisions, personalization, or when tenant information doesn't appear in the domain.
Note: If you have simpler tenant routing requirements, consider the alternative domain-driven routing approach, which assigns unique hostnames to tenants (like tenant1.example.com). This approach leverages DNS infrastructure to obtain tenant context directly from the hostname.

CloudFront Functions vs. Lambda@Edge for Tenant Routing

CloudFront Functions represents a significant advancement over Lambda@Edge for tenant routing scenarios, offering several key advantages:
  • Faster performance and lower latency: CloudFront Functions execute in 225+ Edge Locations closer to end users (compared to Lambda@Edge's 13 Regional Edge Caches), resulting in sub-millisecond execution times (compared to Lambda@Edge's 5-30 seconds). This proximity to users makes CloudFront Functions ideal for high-performance tenant routing where milliseconds matter.
  • Scalability: CloudFront Functions can handle 10,000,000+ requests per second, while Lambda@Edge is limited to approximately 10,000 requests per second per Region.
  • Cost-effective: CloudFront Functions offer a free tier and are charged only per request, whereas Lambda@Edge has no free tier and charges for both requests and function duration.
The scale difference is particularly important for multi-tenant applications: CloudFront Functions can handle millions of requests per second, making it suitable for even the largest SaaS platforms.

Dynamic Origin Selection with CloudFront Functions

A key capability of CloudFront Functions is dynamic origin selection, which allows you to route requests to different origins based on request attributes. This is particularly valuable for multi-tenant architectures where each tenant might need to be routed to a specific backend. With the November 2024 update, CloudFront Functions can now modify origins directly, enabling you to:
  1. Route requests to different origins based on subdomain or path patterns
  2. Implement geographic routing to the closest AWS Region
  3. Direct traffic based on tenant identifiers in the request path
  4. Support cell-based architectures with tenant isolation
CloudFront Functions can also route to various origin types, demonstrating its versatility:
  • Amazon S3 buckets
  • API Gateway endpoints
  • Application Load Balancers
  • Amazon EC2 instances
  • Custom HTTP endpoints
  • Origin groups for failover scenarios
To learn more about CloudFront Functions, see examples.

Leveraging CloudFront KeyValueStore for Tenant Management

CloudFront KeyValueStore provides a high-performance, globally distributed data store that pairs perfectly with CloudFront Functions for tenant routing. This combination allows you to:
  1. Store tenant-to-origin mappings in KeyValueStore
  2. Access these mappings with minimal latency from CloudFront Functions
  3. Update routing rules without modifying function code
  4. Scale to thousands of tenants without performance degradation

Implementing Tenant Routing with CloudFront Functions

Here's an example of how a lightweight JavaScript CloudFront Function can dynamically route tenant requests using KeyValueStore:
This function extracts the tenant ID from the request URI, looks up the appropriate backend domain in KeyValueStore, and dynamically updates the origin using cf.updateRequestOrigin().

Adding Tenant-to-Origin Mappings to the KeyValue Store upon Tenant Onboarding

A robust tenant onboarding process is essential to your SaaS architecture, enabling frictionless customer onboarding, operational efficiency, and scalable growth. When you provision new tenants, remember to update your KeyValueStore with new mappings.
To illustrate, see example _provision_tenant_onboarding in AWS Cloud Development Kit (CDK) in Python:
  • Creates an Amazon Simple Queue Service (SQS) queue that serves as the entry point for tenant onboarding requests
  • Provisions an AWS Lambda function that processes messages from this queue to update tenant-to-origin mappings in KeyValueStore
  • Configures necessary IAM permissions for the Lambda function to interact with KeyValueStore (specifically the PutKey and DescribeKeyValueStore actions)
  • Exports the SQS queue URL as a CloudFormation output, making it accessible to other systems that need to send tenant onboarding requests
  • Passes cluster mapping information to the Lambda function as environment variables, allowing it to determine which cluster a tenant should be assigned to
The tenant onboarding process is completed by a Lambda function that processes messages from an SQS queue and updates the CloudFront KeyValueStore with tenant-to-cluster mappings. Let's examine the Lambda handler that powers this functionality:
This Lambda function performs several key operations:
  1. It retrieves the tenant ID and target cluster from the SQS queue message body
  2. It maps the origin (cluster ID) to the actual domain name using environment variables
  3. It fetches the current ETag of the KeyValueStore to ensure atomic updates
  4. It updates the KeyValueStore with the tenant-to-origin mapping
To onboard a new tenant, you simply send a message to the SQS queue with the tenant ID and target origin. The Lambda function processes this message and updates the KeyValueStore, making the tenant immediately available for routing through CloudFront Functions.

Conclusion

CloudFront Functions offers a powerful solution for dynamic tenant routing, providing a cost-effective and scalable alternative to traditional methods like Lambda@Edge. By leveraging CloudFront Functions and KeyValueStore, you can efficiently manage multi-tenant architectures with minimal latency and high performance. This approach allows for seamless integration with various origin types, making it versatile for different backend configurations.
By adopting CloudFront Functions for tenant routing, you can improve the scalability and efficiency of your SaaS applications, ensuring a better experience for your users.

Resources

Any opinions in this post are those of the individual author and may not reflect the opinions of AWS.

Comments