AWS Partner Network (APN) Blog
Simple and Flexible SaaS Entitlement Management with LaunchDarkly
By Brian Rinaldi, Developer Experience Engineer – LaunchDarkly
By Bill Tarr, Sr. Partner Solutions Architect – AWS SaaS Factory
LaunchDarkly |
Being able to support varying tenant configurations is a common requirement for software-as-a-service (SaaS) providers. This could include enabling or disabling specific features or enforcing usage limits for tenants.
Feature sets are often grouped together under a subscription tier of the SaaS offering. Each tenant in a given tier receives the same set of features and functionality. These configurable features that are made available to some tenants but not others are called entitlements.
If you are maintaining different versions of your SaaS solution for your customers, or handling customer requests for customizations, you may already be struggling with the loss of agility your team is experiencing.
Consider as you read this post how configuration shifts you back to a single version of your solution, and shift your teams focus back to delivering innovation and away from the pain of supporting one-off customizations are customer-specific versions.
One of the design principles of the SaaS Lens for the AWS Well-Architected Framework is to “support one-off requirements through global customization.” This means we should maintain a single environment that operates all of our customers, and avoid customizing that environment for specific tenant experiences.
Rather, we implement all features as part of our core code base, then adjust those features through configuration, creating the desired combinations of tenant experiences.
LaunchDarkly is an AWS DevOps Competency Partner that provides tools for the management of feature flags that allow for the continuous delivery of features during deployments. In this post, we’ll show one way to use LaunchDarkly to manage entitlements with a combination of flags and advanced targeting capabilities.
Solution Overview
Our example SaaS solution offers multiple subscription tiers to represent the packaging of pricing and features that tenants can subscribe to. In our example, the tiers look like this:
- Free tier: Baseline functionality that any tenant can access once they onboard into our solution.
- Pro tier: Free tier functionality plus additional features or increased access to rate limited features.
- Business tier: Pro tier functionality plus additional features and higher rate limits.
We’ll examine the configuration in LaunchDarkly required to represent our tenants, tiers, and feature flags. Once we’ve set up our sample SaaS solution, we’ll explain how to model entitlements as feature flags, targeted to tiers, and we’ll discuss how we can also give tenants access to specific features, even if they don’t belong to a given tier.
Figure 1 – SaaS solution checking access to tenant features.
Above, Figure 1 demonstrates the following:
- A tenant logging into the system of record; an example in this case is Amazon Cognito.
- Provides the tenant identity and subscription tiers in a JSON Web Token (JWT) token.
- SaaS application calls LaunchDarkly with the context information provided from the JWT about the tenant and tier.
- LaunchDarkly evaluates and returns the feature flags targeted for the provided context.
- Returns the service should provide access to Feature 1, but deny access to Feature 2.
LaunchDarkly is not a tenant management solution, but rather accepts variables representing tenants passed in from your application, which in this example is Amazon Cognito. Tenant variables become the inputs into LaunchDarkly’s targeting rules to determine the entitlements for that tenant.
Figure 2 – Logical model of feature flags in LaunchDarkly.
Figure 2 shows the building blocks and LaunchDarkly terminology we’ll use to enable feature flag entitlement. You can see the logical model for how Tier (Segment), Tenant (Context), and feature flag are related (Targeting Rules), with the LaunchDarkly terminology provided in parentheses.
Now, let’s dive into those building blocks.
Applications are Called Projects
It’s useful for feature management solutions to support multiple applications. For LaunchDarkly, these are called projects and they can contain multiple environments, like “Test” and “Production.” For this post, assume the remaining building blocks are part of a single project and environment.
Feature Flags
Feature flags are called exactly that in LaunchDarkly. For now, we’ll just call out a few aspects that will be important later. Each flag has a unique “key” which allows us to reference it programmatically. Feature flags must be marked as “permanent” since entitlements are long-lived, unlike release flags for example.
Figure 3 – Creating a toggled feature flag.
There are two types of feature flags we can utilize:
- Toggled feature: Boolean flag that indicates whether the feature is on or off for a given tier or tenant. For example: “API Access” or “single sign on.”
- Multivariate feature: This could be a string, number, or JSON value. These would often rate-limit a feature that varies per tier. For example, “concurrent meetings” might have a low limit for the basic tier but increase with each successive tier.
Here’s an example of feature flags for our tiers:
Figure 4 – Example of subscription tiers and features.
We also need to make sure targeting is turned on for our features. Having targeting turned on will allow us to create these relationships between our tiers and tenants.
Passing Contexts for Tenants
We can use what are called contexts to represent the tenants in our example. LaunchDarkly recently introduced contexts, which provide flexibility in targeting different kinds of entities—users, servers, devices, or tenants.
Contexts have a type of categorization called “context kinds,” and we’ll use one named “tenant” as shown in Figure 4. For simplicity, we will be using “tenant context” as the term for contexts that have a “context kind” of tenant in this blog.
Figure 5 – Creating a context kind for tenant.
In Figure 5, we are defining a “kind,” which is essentially a set of parameters that represent a tenant. We can pass in additional attributes like tier and these can be used as inputs into the targeting rules. Remember that LaunchDarkly is not a tenant management solution, and tenant contexts are passed in at runtime.
Figure 6 – Tenant content passed to LaunchDarkly for basic-tier tenant.
In Figure 6, you can see the Context kind is “tenant,” while the tenant’s name is “basic-tenant-1” and the tier is “basic-tier.” We’ll use these attributes for mapping later.
Before we start sending tenant contexts into LaunchDarkly, we need to create segments for our tiers and the rules that will group our tenants to the appropriate tier.
Segments for Representing Tiers
We can use segments in LaunchDarkly to represent SaaS tiers, and we’ll call those “tier segments.” We’ll map our tenants to their tier segments by targeting the “tier” attribute of their tenant context.
Figure 7 – Mapping tenants to the basic tier segment.
We can create rules to assign our tenant contexts to each segment. The rule in Figure 6 will allow us to map our tenants that have a tier attribute “basic-tier” to the Basic Tier segment.
Flag Targeting
Once our tenant contexts and tier segments are set up, we can target our flags to our tier segments. As mentioned, when we set up our flags we enabled targeting, but we still need a rule that maps our tier segment to this flag.
You can see in Figure 8 a mapping of the Basic Tier segment to Basic Feature. This will provide all tenants in the basic tier access to this feature.
Figure 8 – Targeting a feature for basic tier tenants.
Handling Exceptional Use Cases for Entitlements
When managing entitlements, there will likely be use cases for providing access to entitlements that are outliers our team needs to handle, but are not part of our regular pricing model. Thankfully, LaunchDarkly targeting rules allow us just that kind of flexibility.
Such use cases could include:
- Customer success teams providing a tenant temporary increases in their limits to a feature to build customer loyalty, manually adding an additional rule targeting their tenant context in the user interface (UI).
- Sales teams granting the CMO of a particular tenant access to a specific feature to encourage them to try a different pricing tier by targeting that feature to the individual’s user key.
The key thing to understand here is the tenant targeting we’ve set up establishes a baseline level of entitlements for a user, but these can be overridden however you require to meet the needs of your system.
Using Flags in Server-Side Code
At this point, we’ve covered all the building blocks. We’ve created:
- Tenant contexts that will contain a tier attribute which can be used to map the tenant to a tier segment.
- Tier segments with rules that create those mappings of tenant contexts to their tier segments.
- Feature flags with rules to ensure tenants will find a feature enabled/disabled based upon their tier segment.
- Multivariate flags with the values representing the rate limit for each entitlement tier segment.
All that’s left now is to use the flags in our code to manage our entitlements. As discussed earlier, a major benefit of this approach is the same flags work across any part of our application, whether frontend or backend, using LaunchDarkly’s SDKs.
The following example is a server-side demonstration of a Node.js application; for instance in an AWS Lambda. First, we need to install the Node SDK:
npm install launchdarkly-node-server-sdk
Then we need to initialize the SDK client:
1 2 |
const ld = require("launchdarkly-node-server-sdk"); const client = ld.init("sdk-my-sdk-key"); |
Before we can get values from LaunchDarkly, we need to create the tenant context. Note that in this case we are only sending a single context, but LaunchDarkly allows you to send multiple contexts which we can use to override some of the entitlement access.
The required attributes for our use case are the key, which is a critical identifier most likely representing an account number or tenant ID within your system, the kind, which aligns with the context kind that this object is associated with (such as tenant), and the tier, which our current targeting examples require to determine the proper segment to place the tenant in. Any other attributes are optional and we can add as many as we need to.
1 2 3 4 5 6 |
context = { kind: "tenant", key: "umbrella-corporation-hbwihisef8kfxhgf7exne", name: "Umbrella Corporation", tier: "Business tier", }; |
Once we have created the context object, we can pass the flag key, context object and a default value (should the call fail for some reason) to the variation() call to get the correct entitlement value for this tier. There is also an allFlags() to retrieve all values for a context.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
let test; // Business clients get 3 concurrent meetings test = await client.variation("concurrent-meetings", context, 0); console.log(test); // 3 // this should be true because Business gets pro features test = await client.variation("speech-to-text", context, false); console.log(test); // true // this should be true because Business gets business feature test = await client.variation("sync-files", context, false); console.log(test); // true // this should be true because it's an Business feature test = await client.variation("live-captioning", context, false); console.log(test); // true |
Obviously, the goal isn’t to console.log() the values but instead to wrap feature specific code to modify or prevent the specific tenant’s access.
For more details on how to use LaunchDarkly’s SDKs in AWS serverless environments, refer to this blog post.
Security
As a final item, let’s touch briefly on how this system is secure. You may be concerned that a user could just intercept and modify the data being sent to LaunchDarkly and suddenly have access to Business tier features that they never paid for.
Thankfully, there are multiple layers that can prevent vulnerabilities of this type:
- Flags are available to all the different layers of your application. This means the same flag that prevents a feature from displaying on the frontend will also prevent the feature from running on your backend or API. Therefore, even if a value were to change, the user might see the UI for a feature but still be unable to use it.
- LaunchDarkly also provides a secure mode that can be used when a client-side SDK communicates with LaunchDarkly. This hash is generated on the server and is passed when initializing the SDK client. Secure mode prevents a user from doing an evaluation for a context or user key that hasn’t been signed on the backend.
Conclusion
In this post, we demonstrated how to use LaunchDarkly to create varied tenant experiences with entitlement flags. Keep in mind, LaunchDarkly is flexible and you can use different combinations of contexts, segments (or even big segments) and targeting rules to fit almost any entitlement structure.
In addition to feature entitlements, you can use LaunchDarkly feature flagging for your deployments/releases, doing progressive rollouts, or running experimentation—all important release practices for SaaS providers.
Sign up for a free trial to try out LaunchDarkly today or subscribe in AWS Marketplace.
.
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.
.
LaunchDarkly – AWS Partner Spotlight
LaunchDarkly is an AWS Partner that powers modern DevOps through feature management, helping development teams innovate faster by transforming how they deliver software. With the ability to progressively release new features to any segment of users on any platform, organizations can scale safer releases, accelerate their cloud journey, and foster better collaboration between development and business teams.