AWS Cloud Operations & Migrations Blog

Using AWS AppConfig to Manage Multi-Tenant SaaS Configurations

As a Software as a Service (SaaS) provider, you can benefit from a SaaS operating model in a number of ways. One of the most impactful benefits you can realize is improvements to your operational efficiency, and one of the fundamental techniques you can leverage is to maintain a single software version for all your tenants with dynamic configuration. Rather than supporting various product versions and customization requests, a single version allows your team to focus on adding value to your product, enabling the growth that is the true promise of SaaS.

That said, if you are operating a SaaS solution today, you may already be experiencing challenges achieving your target operational efficiency. You may be handling customer requests for one-off customizations to your solution. The added complexity of customer specific code and pipelines to support varied customer experiences may be slowly eroding your team’s agility, and ability to focus on delivering innovation and iterating and improving your SaaS product. You need tools and strategies that can reduce complexity.

One strategy you can leverage to improve operational efficiency is to implement SaaS pricing tiers. Grouping configurations into pricing tiers allows you to maintain a single software version, creating a set of well-curated, but varied tenant experiences. That said, implementing these experiences based on pricing tiers requires a tool that allows you to group features of the application, toggle features on and off, or set limits on features, independent of your application code.

In this blog, you’ll see examples of using AWS Systems Manager AppConfig (AppConfig) as a tool to enable managing pricing tiers in a SaaS solution. We’ll examine leveraging AppConfig for managing pricing tier configuration, including integrations with other AWS services. We’ll dig into AppConfigs’ ability to unblock your development team’s ability to iterate and change pricing tier features by changing configurations, even without code releases of your SaaS solution.

Multi-Tenant SaaS Pricing Tiers

Pricing tiers are different subscription options or plans you can offer to the prospective customers of your SaaS solution. The motivation for offering different pricing tiers can vary, including inducing customers to try a solution for free or at a lower initial cost, attracting different customers by industry and size, or simply packaging the product that appeals to different customer profiles.

From an implementation perspective, you can consider a pricing tier as a group of features and limitations on usage. In most SaaS solutions each tier has different features, or even just different limits on how much we allocate of a tenant-specific feature. However, those feature groupings and limits are not static. As new features continue to be added, we must continually revisit our pricing tiers packaging to ensure growth and success, especially as we continue adjusting to changing market and economic conditions.

Given the advantages of pricing tiers, let’s examine how we can implement them with dynamic configuration in AppConfig.

Introducing AppConfig

AppConfig allows you to manage, store, and deploy application configurations. These configurations can be consumed by multiple clients within your SaaS application. You can use it to manage dynamic configuration, such as pricing tiers, and store a single JSON file that contains dynamic configuration, including feature flags.

AppConfig is certainly not the only AWS service capable of configuration management. Other services like Amazon DynamoDB (DynamoDB) and AWS Systems Manager Parameter Store can manage configurations, but AppConfig has many advantages you can leverage, such as:

Solution Overview

In the sections that follow, you’ll set up AppConfig, as shown in Figure 1, to manage one feature that will only be enabled for your premium pricing tier. We’ll show how to retrieve and evaluate feature flags in an AWS Lambda (Lambda), and leverage the retrieved value in your code.


Figure 1 – Lambda evaluating configuration for a premium tier tenant

The flow shows:

  1. A request from a premium tier customer reaches the Lambda function
  2. Lambda function fetches AppConfig JSON configuration.
  3. Feature Flags utility evaluates the “premium” feature flag with a “premium tier customer” context and returns the value “true.”
  4. Lambda function uses the “true” value in code

Let’s get into how you can set this up.

AppConfig Configuration Setup

AppConfig consists of configuration hierarchies. First, you’ll need an application. Here, we define the ‘product-catalog’ application.


Figure 2 – Applications map to service names

Your application will have a list of environments (‘dev,’ ‘stage,’ ‘production,’ etc.).


Figure 3 – Application ‘product-catalog’ with a ‘dev’ environment

Each environment contains the current configuration deployments, their status and details.

Your environment can have one or more configuration profiles.


Figure 4 – Freeform JSON configuration

Each configuration profile details the deployed JSON contents and its current version. We will explore the contents of this JSON configuration in the section below.

Implementing AppConfig Feature Flags in Code

Now that you’ve stored a configuration in AppConfig, you’ll need to fetch the dynamic configuration in your code containing the feature flags that make up your pricing tiers.

Let’s examine how to use the configuration above in a Lambda function to enable a feature for your premium tier tenant and disable it for your standard tier tenants. The Lambda function will need to adjust its behavior at runtime, adjusting to the input event and tenant tier it contains on each invocation, in this case, a premium tier tenant.


Figure 5 – Lambda input event

Since we are using AppConfig Freeform configurations, we can use a JSON document to define the rules we want to apply for our feature flags. While you can implement this logic however you prefer, we’ll be using Powertools for AWS Lambda (Powertools), an open-source collection of serverless utilities, and the feature flags utility to fetch the JSON configurations from AppConfig and evaluate our feature flag.


Figure 6 – Configuration for a feature flag enabled for premium tier tenants

Let’s review the JSON structure in Figure 6 we will use. Remember the convention matches the Powertools feature flag library. The structure can have any valid JSON value (boolean, int, etc.)

  • Each feature has a default value under the default key (line 3)
  • A feature can have optional rules determining the evaluated value (Line 4)
  • Rules consist of a default value to return (in case of a match — when_match) and a list of conditions. (Line 6-7)
  • Only one rule can match
  • Each condition consists of an action name (operator) and a key-value pair (Line 9-11)

So, in this configuration, the ‘premium_features’ feature flag is turned off by default, and enabled if our inputs match a rule. The rule is matched when the context passed in has a key ‘tier’ with a value of ‘premium.’

Read more about the rules, conditions, logic, and supported actions in the official documentation.


Figure 7 – Lambda code implementing your feature flag

  • In lines 3-6, you initialize the AppConfigStore class to fetch configuration from AppConfig, provide it with the application, environments, and configuration names.
  • In line 9, you initialize the Powertools feature flags utility.
  • In line 13, you prepare the context for the feature flags utility, set the key “tier” with the current user’s tier from the input event. This value correlates to the rule definition defined above.
  • In line 17, you fetch the feature flag ‘premium_features’ and provide the context and a default value of disabled. The default value serves as a fallback in case of an error or if we accidentally remove the feature flag from the configuration. The fallback value enables the service to continue functioning correctly.
  • Line 19 is the naive implementation of feature flags. If the feature is enabled, the service will run the premium feature code, i.e., if the user’s tier is premium; otherwise, the default service behavior is run.

For a deep dive and more examples, see AWS Lambda Cookbook  - Part 6 - Configuration & Feature Flags Best Practices where AWS Serverless Hero Ran Isenberg describes logging, observability, input validation, AWS CDK integration, and more.

Feature Flags Introduce Complexity

As seen in this post, you’ve seen feature flags provide capabilities at the cost of additional resources to maintain an additional business domain code. However, the complexity does not end there. You manage your feature flags across the service CI/CD pipeline, from the development stages to testing, rollout, monitoring, and even retiring and removing stable feature flags.

To learn more about managing feature flags, check out Manage Your AWS Lambda Feature Flags Like a Boss by Ran Isenberg.

AppConfig Configuration Options

SaaS solutions usually consist of multiple planes, including a control plane, where the core services that orchestrate your SaaS reside, and application plane, where we’ve deployed the application used by your tenants. With AppConfig, you have options to deploy your configurations either to each of your application planes, or as a single configuration in your control plane, or to each of your application planes.

In the distributed approach, each instance of your application plane has its own AppConfig configuration resources in the same account as your code. If you are leveraging an account-per-tenant model for your application plane, each account would have an AppConfig instance. One benefit of this approach is that we can roll configuration changes out to tenants incrementally. However, this approach increases the resources you manage and deploy.


Figure 8 – AppConfig distributed to each application plane

The shared configuration model approach deploys only one central AppConfig configuration. It can be deployed in a separate account, like your control plane account.


Figure 9 – Shared configuration in the SaaS Control Plane

This approach allows changes to proliferate across multiple services with one feature flag, even if the services are different compute types like Lambda functions and Amazon EC2, as shown in Figure 9.

In some cases, different teams maintain and deploy services to different AWS accounts, and managing a centralized AppConfig may be complicated. Accessing your resources in other accounts requires Cross-account resources access with AWS Identity and Access Management (IAM) roles, complicating the deployment and adding runtime latency when assuming the role.

The choice is yours to decide what configuration model suits your SaaS solution. However, the distributed approach may be simpler for getting started.

Multi Regional Service Considerations

Dynamic Configuration is a critical part of your SaaS solution, however, outages or momentarily failures can and will occur. If you deploy your SaaS solution across multiple AWS Regions, you might be tempted to put your AppConfig configurations in a single central Region to simplify deployment. This, however, can make that central region a single point of failure for all your regional deployments. Consider deploying your configurations to each Region instead. This will improve reliability and resilience of your solution, though it increases complexity.

Other Architectures

We’ve focused on using AppConfig with Lambda functions in this post. You can also use the AppConfig Agent for Amazon EC2, Amazon ECS, Amazon EKS, Lambda Extension, or call the service directly.

Conclusion

In this blog, you’ve learned about why configuration management is important to SaaS providers’ operational efficiency. You now have an improved understanding of pricing tiers as one strategy you can use to maintain operational efficiency in your SaaS solution.

You now have some familiarity with AppConfig, and how you can use it and Powertools feature flag utility to implement dynamic configuration. AppConfig also enables various packaging configurations in a SaaS solution, including pricing tiers, allowing you to maintain agility while providing tenants flexibility by keeping a single version of your software.

Key resources to get started:

About AWS SaaS Factory

AWS SaaS Factory helps organizations at any stage of the SaaS journey. Whether looking to build new products, migrate existing applications, or optimize SaaS solutions on AWS, we can help. Visit the AWS SaaS Factory Insights Hub to discover more technical and business content and best practices.

SaaS builders are encouraged to reach out to their account representative to inquire about engagement models and to work with the AWS SaaS Factory team.

Sign up to stay informed about the latest SaaS on AWS news, resources, and events.

About the authors:

Ran Isenberg

Ran Isenberg is an AWS Serverless Hero, a Principal Software Architect at CyberArk, a blogger, and a public speaker. He maintains a blog (RanTheBuilder.cloud) where he shares knowledge and experience in the Serverless world.

Alex Pulver

Alex Pulver is a Principal Solutions Architect at AWS SaaS Factory team. He works with AWS Partners at any stage of their software-as-a-service (SaaS) journey to help build new products, migrate existing applications, or optimize SaaS solutions on AWS. His areas of interest include builder experience (e.g., developer tools, DevOps culture, CI/CD), containers, security, IoT, and AWS multi-account strategy.

Bill Tarr

Bill Tarr is a Senior Solutions Architect at the AWS SaaS Factory, enabling SaaS Builders on their software-as-a-service (SaaS) journey. Bill evangelizes the best practices for designing, building, and operating SaaS solution through direct engagement, speaking at events, and live streamed shows like Building SaaS on AWS on Twitch.