AWS Business Intelligence Blog

Support multi-tenant applications for SaaS environments using Amazon QuickSight

Applications and services that use visualizations and reporting drive customer adoption, increase revenue, and provide a competitive advantage. Without integrated analytics and reporting, a software as a service (SaaS) solution will experience reduced competitiveness in the market. However, in-house and commercial business intelligence (BI) solutions are expensive to build and maintain. Amazon QuickSight, AWS’s serverless BI service, is used by thousands of customers in embedded applications to cost-effectively integrate visualizations and analytical experiences seamlessly into their srvice offering. This post focuses on multi-tenancy in QuickSight; for more details on patterns beyond multi-tenancy, refer to Build embedded analytics architectures using Amazon QuickSight.

Although many organizations can take advantage of multi-tenancy, the most common users of multi-tenancy are SaaS solutions that allow you to consume the software without any operational overhead or expense. One challenge SaaS solutions have is providing a high-quality BI solution at a low cost and high scale. QuickSight can provide the capability cost-effectively while reducing operational overhead of self-managed solutions. Additionally, multi-tenancy in QuickSight is useful for consulting firms providing dashboards and reporting solutions for their customers.

This post provides guidance on deploying QuickSight in a multi-tenant environment, and the considerations around data isolation and deploying resources to tenants in a QuickSight application. Multi-tenancy within applications provides a mechanism to segment groups of users from one another. These groups could be users from different companies, different geographic regions, or different lines of business within an enterprise. Users within different tenants can’t see other users, data, and assets, while reducing the complexity of having a different infrastructure for each set of users.

This post covers the following topics:

  • Selecting the ideal QuickSight data isolation method for your use case
  • Choosing the best way to deploy and grant access to objects within QuickSight
  • Provisioning tenant users
  • Development and deployment methodologies to allow asset deployment to all tenants

Groups vs. namespaces

Amazon QuickSight offers two ways to achieve multi-tenancy by isolating resources: using groups or using namespaces. Both ways offer isolation of resources (data sources, datasets, analyses, dashboards), but they have one fundamental difference. If end-users require the ability to interact with QuickSight to build, deploy, or share their own dashboards, then you must use namespaces.

Namespaces are necessary when end-users need to build reports and they need an Author license. Group membership does not restrict authors with an Author license from sharing newly created resources outside the group. This increases the risk of unintentional data breaches.

From an observability perspective, namespaces simplify monitoring of QuickSight usage at the tenant level, making it easier for organizations to track and charge back their customers.

Before you decide on either groups or namespaces, review the documentation on the limitations of each approach.

Datasets and data sources per tenant vs. a single dataset with row-level security

With multi-tenant architectures with QuickSight, you must make a decision regarding your datasets. In this section, we explore two options. Which one works best depends on your organization’s risk tolerance and industry-specific compliance requirements.

Datasets and data sources per tenant

In this scenario, you have a dataset per tenant. Each dataset is configured to bring back data for that tenant specifically, either in the form of a data filter or a custom query with a parameter.

A data source per tenant is not mandatory. For example, if you use Amazon Athena to query data from Amazon Simple Storage Service (Amazon S3), you can have a data source with shared connection details across all tenants. Each tenant’s dataset can push a query down to Athena with a different tenant ID.

If multi-tenancy at the database level includes separated hardware or schemas, such as a database schema or cluster per tenant, then you also need one data source per tenant.

You can use an AWS Lambda function to deploy the assets per tenant in an automated fashion. The process creates new assets and applies the necessary permissions so those assets are only visible by the groups or users in a specific namespace (tenant). You can also use Lambda to clean up a tenant and delete users and assets if deemed necessary.

The following diagram illustrates this architecture.

Solution with one namespace per tenant

Single dataset with row-level security

In this scenario, you have one dataset holding the raw data for all tenants, which has row-level security (RLS) enabled. A single dashboard points to the dataset, which can be shared across all tenants.

RLS requires a separate dataset to be created that holds information on what data is accessible by each tenant. For more information, see Using row-level security (RLS) in Amazon QuickSight.

The following diagram illustrates this architecture.

Solution with common assets across tenants and RLS

Comparing options

The following table summarizes the pros and cons of each option.

Option Pros Cons
Unique assets (data source, dataset, dashboard) per tenant Comply with industry-specific requirements that require isolation of data Need for automation to manage assets; greater development overhead
Straightforward to track per-tenant costs for SPICE
Shared assets with RLS across tenants Straightforward implementation with lower development overhead Unable to track per tenant costs for SPICE
RLS rules dataset becomes the linchpin for security
Higher chance of reaching SPICE limits for data stored

Provisioning, authentication, and authorization

For the purpose of this post, we provision tenants (namespaces), groups, and users. In other implementations, groups can be managed externally to QuickSight using identity federation.

Embedding the dashboard in an application eliminates user management in QuickSight and delivers a seamless user experience. The embedding application calls the QuickSight API on behalf of the user to generate a single-use URL that can be used in an iFrame presenting the dashboard to the user. Signing in to QuickSight is not required because the user context is passed when the embedding URL is created. For more information, refer to the Embedding Workflow workshop.

For security best practices specific to QuickSight, refer to Best practices for security in Amazon QuickSight.

In the following sections, you create the resources needed to support a multi-tenant environment in QuickSight using AWS Identity and Access Management (IAM) users, groups, namespaces, and assets. We use examples using the AWS Command Line Interface (AWS CLI) for simplicity. You can use other SDKs such as the AWS SDK for Python (Boto3) instead of the AWS CLI.

Tenants (namespaces)

In this section, you create the first tenant in the form of a custom namespace, then you create a group. Groups within namespaces are useful for applying permissions across many users.

Enter the following command (provide your AWS account ID and a name for your namespace):

aws quicksight create-namespace --aws-account-id YOUR_AWS_ACCOUNT_ID --name YOUR_NAMESPACE --identity-store QUICKSIGHT

This process is asynchronous. To check whether the namespace is created, enter the following command:

aws quicksight describe-namespace --aws-account-id YOUR_AWS_ACCOUNT_ID --namespace YOUR_NAMESPACE

Users

In this section, you create an IAM user and register the user in QuickSight under a namespace.

First, you have to create an IAM user with appropriate privileges. For more information, refer to Creating an IAM user in your AWS account.

Enter the following command to register the user you created as an QuickSight Author under the namespace:

aws quicksight register-user --identity-type IAM --email YOUR_USER_EMAIL --user-role AUTHOR --iam-arn YOUR_IAM_USER_ARN --aws-account-id YOUR_AWS_ACCOUNT_ID --namespace YOUR_NAMESPACE

Deploy assets across tenants

In this section, we review the process of deploying datasets across the tenants. You export a dataset in JSON using the AWS CLI and create a template so it can be deployed to different tenants.

You can use AWS CLI commands or the SDK for Python in conjunction with Lambda to create an export and deployment pipeline, and automate these pipelines for production workloads.

In QuickSight, there are two ways to export assets as code:

  • Using the standard APIs (for example, describe-dashboard)
  • Using the bundle APIs

Using the bundle APIs simplifies the export process by bundling all dependencies in a single export file.

When developing assets in a multi-tenant environment, assign a namespace for development use. That can be the default namespace, or a customer’s namespace.

The following diagram illustrates the export, templating, and import process of assets across namespaces.

Export, templating, and deployment across tenants

Complete the following steps to deploy assets as a bundle export:

  1. To get the ARN for the dashboard you want to export, enter the following command:
aws quicksight list-dashboards --aws-account-id YOUR_AWS_ACCOUNT_ID
  1. Start the export job using the resource ARN you retrieved. In the AWS CLI, make sure to include dependencies because that will export the datasets and data sources the dashboard is using. For this post, use JSON as the export format, but AWS CloudFormation is also supported. See the following code:
aws quicksight start-asset-bundle-export-job --aws-account-id YOUR_AWS_ACCOUNT_ID --asset-bundle-export-job-id YOUR_EXPORT_JOB_ID --resource-arns YOUR_RESOURCE_ARN --include-all-dependencies --export-format QUICKSIGHT_JSON

The value for –asset-bundle-export-job-id must be unique for the duration of the export job. QuickSight supports up to five concurrent runs of the asset bundle export job. The export job generates a .zip file with .qs as the file extension, containing the dashboard, dataset, and data source JSON output (or CloudFormation format). The .zip file is stored in Amazon S3.

When the export job is complete, an S3 presigned URL is generated, showing the location of the .qs file. The URL is active for 5 minutes. If it expires, run the describe-asset-bundle-export-job call to re-enable it.

  1. Because the API is asynchronous, enter the following command to check the bundle export progress:
aws quicksight describe-asset-bundle-export-job --aws-account-id YOUR_AWS_ACCOUNT_ID --asset-bundle-export-job-id YOUR_EXPORT_JOB_ID

The following code shows what your output should look like:

{ "Status": 200, "JobStatus": "SUCCESSFUL", "DownloadUrl": "https://QuickSight-asset-bundle-export-job-us-east-1.s3.amazonaws.com/YOUR_AWS_ACCOUNT_ID/YOUR_EXPORT_JOB_ID/.../asset-bundle.qs?X-Amz-Security-Token=...", "Arn": "arn:aws:QuickSight:us-east-1:AWS_ACCOUNT_ID:asset-bundle-export-job/job-1", "CreatedTime": "2023-12-19T04:06:37+00:00", "AssetBundleExportJobId": "job-1", "AwsAccountId": "AWS_ACCOUNT_ID", "ResourceArns": [ "arn:aws:QuickSight:us-east-1:AWS_ACCOUNT_ID:dashboard/4c9f55d7-9fdb-41ca-be97-a2d2f0c38c29" ], "IncludeAllDependencies": true, "ExportFormat": "QuickSight_JSON", "RequestId": "8491111e-9cba-4f23-a63d-5b1572540419" }
  1. Copy the value from DownloadUrl and download the file from Amazon S3 using curl. Make sure to use double quotes around the DownloadURL value:
curl "DownloadUrl" --output asset_bundle.qs
  1. Unzip the contents using the following command:
unzip asset_bundle.qs

The following screenshot shows what the folder structure should look like.

Folder structure

QuickSight offers a few options out of the box when it comes to overriding parameters such as hostname, password, or the name of a data source during import. To do so, use the AssetBundleImportJobOverrideParameters APIs.

If the attributes you are trying to parameterize are not supported by the API, you have to add those parameters in the template manually. You can use a script to find and replace the parameter with the needed value. This post does not address the find and replace process.

Looking at the exported files in the bundle, each JSON file has an id (datasourceId, dataSetId, or dashboardId) and a name key you have to update, as shown in the following screenshot.

Making the dashboardId, datasetId, and name unique per tenant is mandatory.

In the following example, there is a dataset filter for country, which should be set to a different value for each tenant. Your dashboard may not have the same fields or filters. Pick the column or filter you can see and prefer to set.

The following screenshot shows the original filter.

Quicksight filter

The following screenshot shows the filter with the new parameter.

Quicksight filter with parameter

At this point, you can automate the process and have your script replace {{COUNTRY_PARAMETER}} with the relevant value.

  1. For this post, manually set {{COUNTRY_PARAMETER}} to a value and save the file.
  2. Go into the same directory level as the dashboard, dataset, and datasource folders and create a new .zip file:
zip -r new_bundle.qs dashboard dataset datasource
  1. Upload the new bundle file to Amazon S3:
aws s3 cp new_bundle.qs s3://YOUR_S3_BUCKET/new_bundle.qs
  1. Start the import job using the following AWS CLI command:
aws quicksight start-asset-bundle-import-job --aws-account-id YOUR_AWS_ACCOUNT_ID --asset-bundle-import-job-id YOUR_IMPORT_JOB_ID --region us-east-1 --asset-bundle-import-source "{\"S3Uri\": \"s3://YOUR_S3_BUCKET/new_bundle.qs\"}"
  1. To check the progress, enter the following command:
aws quicksight describe-asset-bundle-import-job --aws-account-id YOUR_AWS_ACCOUNT_ID --asset-bundle-import-job-id YOUR_IMPORT_JOB_ID

After the bundle is imported, the assets created are not visible or accessible by anyone. That’s because permissions are not included in the bundle by design.

  1. To add permissions to the new dashboard so that the group associated with the relevant tenant can view it, enter the following command (the value of YOUR_PRINCIPAL_ARN can be the IAM user you created):
aws quicksight update-dashboard-permissions --aws-account-id YOUR_AWS_ACCOUNT_ID --dashboard-id YOUR_DASHBOARD_ID --grant-permissions Principal=YOUR_PRINCIPAL_ARN,Actions=QuickSight:DescribeDashboard,QuickSight:QueryDashboard,QuickSight:ListDashboardVersions

After you update the dashboard permissions for the tenant group, the job is complete and users can now access it. If users need to access the dataset, you need to update permissions for that asset.

  1. Enter the following command to update permissions:
aws quicksight update-data-set-permissions --aws-account-id YOUR_AWS_ACCOUNT_ID --data-set-id YOUR_DATASET_ID --grant-permissions Principal=YOUR_QUICKSIGHT_ARN,Actions=QuickSight:DescribeDataSet,QuickSight:DescribeDataSetPermissions,QuickSight:PassDataSet,QuickSight:DescribeIngestion,QuickSight:ListIngestions

Deploy assets to another namespace

To deploy assets to another namespace, repeat the previous steps, starting with adding your attribute parameters to your template.

Conclusion

This post covered the design considerations when deploying QuickSight reports in a multi-tenant SaaS environment. The first design decision is to isolate the permissions across tenants. If tenants can create or edit resources, then namespaces are the best fit. The next design decision is whether to have row-level security or a single dataset per tenant. Having isolation between SPICE datasets requires a dataset per tenant. The last sections of the post provided guidance on how to deploy asset bundles across tenants.

For more information about embedded analytics and multi-tenancy with QuickSight, refer to Build embedded analytics architectures using Amazon QuickSight and Embed multi-tenant analytics in applications with Amazon QuickSight.


About the Authors

Evangelos Pertsinis is a Solutions Architect at Amazon Web Services. He helps customers leverage AWS technologies efficiently. With a background in designing and building end-to-end data solutions, Evangelos is passionate about working with customers to unlock the value of their data. In his free time, Evangelos enjoys playing soccer, hiking, and fishing.

Mike Gillespie is a Principal Solutions Architect at Amazon Web Services. He works with the software companies who run their solutions on AWS and helps them improve their products by using AWS. Mike is a builder who likes getting hands-on technology, building solutions in a variety of domains including machine learning, analytics, serverless, and security. Outside of work, Mike enjoys being outdoors running and paddling, walking his dog while listening to podcasts, and photography.

Ramon Lopez is a Principal Solutions Architect for Amazon QuickSight. With many years of experience building BI solutions and a background in accounting, he loves working with customers, creating solutions and making world class services. When not working he prefers to be outdoors in the ocean or up on a mountain.