Overview

SaaS companies operate solutions for a large number of tenants. Multi-tenant deployments of AWS Edge services (e.g. CloudFront, AWS WAF, etc...) require careful design decisions to meet business requirements such as flexibility, cost, scalability and operational overhead.

Architectural decisions

Consider the following architectural decisions when designing a multi-tenant solution using CloudFront:

  • Do you use the same host name for all tenants (e.g. saas.com/tenant1, saas.com/tenant2) or separate host names? If you are using the same host name, you have the option of deploying using a single CloudFront distribution.
  • If you are using separate host names, are you using the same domain name (e.g. tenant1.saas.com, tenant2.saas.com) or separate ones (e.g. tenant1.com, tenant2.com)? A CloudFront distribution can be associated with a single TLS certificate, which can host multiple host names (SAN certificates). When you use the same domain name, you have the choice of deploying a CloudFront distribution by tenant, or deploy a single distribution with wildcard CNAME and TLS certificate (*.saas.com) for all tenants. If the domains are different, you have the choice of deploying a CloudFront distribution by tenant, or deploy multiple distributions, each with s SAN certificate that can host up to 100 different domains. However, the more domains you attach to the same TLS certificate, the more friction you add to the process of TLS certificate issuance.
  • Who controls the domain name? If tenants control their domain, additional steps will be needed to add their hostname as a CNAME to a CloudFront distribution. For security reasons, CloudFront requires you to prove your ownership of the domain by attaching a valid TLS certificate that covers the hostname. Tenants either need to share their own TLS certificate, which you'd upload to ACM, or let you issue a TLS certificate on their behalf using ACM. With the second approach, ACM requires them to create a CNAME token in their DNS to prove their ownership of the domain.
  • Do tenants share the same content or different content? If they share common content, consider hosting the shared content on a single domain that can be used by different tenants. This results in better cache hit ratio for shared content.
  • If you are using a CloudFront distribution for multiple tenants, do you host tenants on the same origin or on different origins? If you are using the same origin (e.g. single S3 bucket or single ALB), you can differentiate tenants by URL path or by Host header. Add the Host header to the cache key if you choose this method of differentiating tenants. If you are using different origins (e.g. one S3 bucket per tenant, or sharding tenants on ALB clusters), you need a Lambda@Edge on origin request event to route traffic to the right origin. Note that if you are using path to differentiate tenants ((e.g. saas.com/tenant1, saas.com/tenant2), you can natively route different tenants to their origins using CloudFront cache behaviors, but you have quotas on the number of behaviors per CloudFront distribution.
  • Does your design respect the AWS quotas per AWS service and per AWS Account?

Consider the below trade-offs in your design. Note that you can implement differentiated tradeoffs for multi-tier offering. For example, in your basic tier where you control the domain name, all tenants share the same CloudFront distribution. Your premium tenants would have each a dedicated CloudFront distribution with a custom domain and security protections using AWS WAF.

  Each tenant is hosted on a dedicated CloudFront distribution Multiple tenants hosted on the same CloudFront distribution
Observability Natively available per tenant Available at the distribution level, extra effort is needed to extract metrics per tenant using logs
Blast Radius A change impacts only one tenant A single change impacts all tenants
Operational Overhead Requires automation at scale, with batched roll outs to avoid throttling at CloudFront API level Low
Customization Each tenant can have it's own different configuration Same config to all tenants. When you enable WAF, it's charged for all requests
Performance Each CloudFront distribution needs to be warmed by traffic separately (e.g. connections to origin) All tenants benefit from a warmed CloudFront distribution

A CloudFront distribution can be attached to a single AWS WAF WebACL. The same WebACL can be used across multiple CloudFront distributions. The previous mentioned tradeoffs also apply to WAF deployment, in addition to the following:

  Using the a WebACL per tenant Using the same WebACL for multiple tenants
Price WebACL/Rules cost scales linearly with tenant number WebACL/Rules cost is independent of tenant number
False positives A rule update might only cause false positives with a single tenant A rule update might cause false positives with many single tenants

Common use cases

Sub-domain per tenant

In this scenario, you create a subdomain (tenant1.saas.com) for every tenant. Route 53 is configured with wildcard Alias record (*.saas.com) to a CloudFront distribution, also configured with wildcard CNAME (*.saas.com), with Host header included in the cache key. An ALB origin serving dynamic requests natively distinguishes tenants using the Host header. Note that in this scenario, a single content invalidation will apply to all tenants, because CloudFront invalidations are agnostic to headers part of the cache key, such as the Host header. An S3 bucket serving static content would need a CloudFront Function configured on the viewer request event to read the Host header, and rewrite the URL to the tenant directory in S3 (e.g. tenant1.saas.com/index.html -> s3://bucket:arn/tenant1/index.html). If you are serving the same content to all tenants from S3, for example the same Single Page Application, but differentiating tenants with APIs, consider this simple solution.

If you are hosting tenants on different origins, then need a Lambda@Edge function configured on origin request event to route a tenant requests to the origin hosting the tenant. To learn more about this implementation, read the following case studies:

Tenants with own domains

In this scenario, dedicate a CloudFront distribution for each tenant, and automate the process (e.g. distribution creation and TLS certificate issuance using Amazon Certificate Manager). Make sure that you raise relevant quotas (e.g. number of distributions per account, number of TLS certificates) beforehand. In certain cases, you need to shard your CloudFront distributions across multiple AWS accounts.

Terminate TLS on your servers

If the scale of your requirements can not be satisfied by CloudFront, consider building a fleet of reverse proxy (e.g. based on NLB & EC2) to terminate TCP/TLS connections, and front by Global Accelerator for better security and performance. Note that in this scenario, you need to implement caching in your reverse proxy if needed.

Resources

Was this page helpful?