

# Tenant onboarding in SaaS architecture for the silo model using C\$1 and AWS CDK
<a name="tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk"></a>

*Tabby Ward, Susmitha Reddy Gankidi, and Vijai Anand Ramalingam, Amazon Web Services*

## Summary
<a name="tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk-summary"></a>

Software as a service (SaaS) applications can be built with a variety of different architectural models. The *silo model* refers to an architecture where tenants are provided dedicated resources.

SaaS applications rely on a frictionless model for introducing new tenants into their environment. This often requires the orchestration of a number of components to successfully provision and configure all the elements needed to create a new tenant. This process, in SaaS architecture, is referred to as tenant on-boarding. On-boarding should be fully automated for every SaaS environment by utilizing infrastructure as code in your on-boarding process.

This pattern guides you through an example of creating a tenant and provisioning a basic infrastructure for the tenant on Amazon Web Services (AWS). The pattern uses C\$1 and the AWS Cloud Development Kit (AWS CDK).

Because this pattern creates a billing alarm, we recommend deploying the stack in the US East (N. Virginia), or us-east-1, AWS Region. For more information, see the [AWS documentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/monitor_estimated_charges_with_cloudwatch.html).

## Prerequisites and limitations
<a name="tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk-prereqs"></a>

**Prerequisites**** **
+ An active [AWS account](https://aws.amazon.com/account/).
+ An AWS Identity and Access Management (IAM) principal with sufficient IAM access to create AWS resources for this pattern. For more information, see [IAM roles](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html).
+ [Install Amazon Command Line Interface (AWS CLI)](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) and [configure AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html) to perform AWS CDK deployment.
+ [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/) downloaded and installed or [Visual Studio Code](https://code.visualstudio.com/download) downloaded and installed.
+ [AWS Toolkit for Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/setup.html) set up.
+ [.NET Core 3.1 or later](https://dotnet.microsoft.com/download/dotnet-core/3.1) (required for C\$1 AWS CDK applications)
+ [Amazon.Lambda.Tools](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) installed.

**Limitations**** **
+ AWS CDK uses [AWS CloudFormation](https://aws.amazon.com/cloudformation/), so AWS CDK applications are subject to CloudFormation service quotas. For more information, see [AWS CloudFormation quotas](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html). 
+ The tenant CloudFormation stack is created with a CloudFormation service role `infra-cloudformation-role` with wildcard characters on actions (`sns`\$1 and `sqs*`) but with resources locked down to the `tenant-cluster` prefix. For a production use case, evaluate this setting and provide only required access to this service role. The `InfrastructureProvision` Lambda function also uses a wildcard character (`cloudformation*`) to provision the CloudFormation stack but with resources locked down to the `tenant-cluster` prefix.
+ This example code's docker build uses `--platform=linux/amd64` to force `linux/amd64` based images. This is to ensure that the final image artifacts will be suitable for Lambda, which by default uses x86-64 architecture. If you need to change the target Lambda architecture, be sure to change both the Dockerfiles and the AWS CDK codes. For more information, see the blog post [Migrating AWS Lambda functions to Arm-based AWS Graviton2 processors](https://aws.amazon.com/blogs/compute/migrating-aws-lambda-functions-to-arm-based-aws-graviton2-processors/).
+ The stack deletion process will not clean up CloudWatch Logs (log groups and logs) generated by the stack. You must manually clean up the logs through the AWS Management Console Amazon CloudWatch console or the through the API.

This pattern is set up as an example. For production use, evaluate the following setups and make changes based on your business requirements:
+ The [AWS Simple Storage Service (Amazon S3)](https://aws.amazon.com/s3/) bucket in this example does not have versioning enabled for simplicity. Evaluate and update the setup as needed.
+ This example sets up [Amazon API Gateway](https://aws.amazon.com/api-gateway/) REST API endpoints without authentication, authorization, or throttling for simplicity. For production use, we recommend integrating the system with the business security infrastructure. Evaluate this setting and add required security settings as needed.
+ For this tenant infrastructure example, [Amazon Simple Notification Service (Amazon SNS)](https://aws.amazon.com/sns/) and [Amazon Simple Queue Service (Amazon SQS)](https://aws.amazon.com/sqs/) have only minimum setups. The [AWS Key Management Service (AWS KMS)](https://aws.amazon.com/kms/) for each tenant opens to [Amazon CloudWatch](https://aws.amazon.com/cloudwatch/) and Amazon SNS services in the account to consume based on the [AWS KMS key policy](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-key-management.html#compatibility-with-aws-services). The setup is only an example placeholder. Adjust the setups as needed based on your business use case.
+ The entire setup, which includes but isn’t limited to API endpoints and backend tenant provisioning and deletion by using AWS CloudFormation, covers only the basic happy path case. Evaluate and update the setup with the necessary retry logic, additional error handling logic, and security logic based on your business needs.
+ The example code is tested with up-to-date [cdk-nag](https://github.com/cdklabs/cdk-nag) to check for policies at the time of this writing. New policies might be enforced in the future. These new policies might require you to manually modify the stack based on the recommendations before the stack can be deployed. Review the existing code to ensure that it aligns with your business requirements.
+ The code relies on the AWS CDK to generate a random suffix instead of relying on static assigned physical names for most created resources. This setup is to ensure that these resources are unique and do not conflict with other stacks. For more information, see the [AWS CDK documentation](https://docs.aws.amazon.com/cdk/v2/guide/resources.html#resources_physical_names). Adjust this based on your business requirements.
+ This example code packages .NET Lambda artifacts into Docker based images and runs with the Lambda provided [Container image runtime](https://docs.aws.amazon.com/lambda/latest/dg/csharp-image.html). The container image runtime has advantages for standard transfer and store mechanisms (container registries) and more accurate local test environments (through the container image). You can switch the project to use [Lambda provided .NET runtimes](https://docs.aws.amazon.com/lambda/latest/dg/lambda-csharp.html) to reduce the build time of the Docker images, but you will then need to set up transfer and store mechanisms and ensure that the local setup matches the Lambda setup. Adjust the code to align with users' business requirements.

**Product versions**
+ AWS CDK version 2.45.0 or later
+ Visual Studio 2022

## Architecture
<a name="tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk-architecture"></a>

**Technology stack**
+ Amazon API Gateway
+ AWS CloudFormation
+ Amazon CloudWatch
+ Amazon DynamoDB
+ AWS Identity and Access Management (IAM)
+ AWS KMS
+ AWS Lambda
+ Amazon S3
+ Amazon SNS
+ Amazon SQS

**Architecture**

The following diagram shows the tenant stack creation flow. For more information about the control-plane and tenant technology stacks, see the *Additional information* section.

![\[Workflow to create a tenant and provision a basic infrastructure for the tenant on AWS.\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/images/pattern-img/5baef800-fe39-4eb8-b11d-2c23eb3175fc/images/0b579484-b87c-4acb-8c60-8c33c18370e3.png)


**Tenant stack creation flow**

1. User sends a POST API request with new tenant payload (tenant name, tenant description) in JSON to a REST API hosted by Amazon API Gateway. The API Gateway processes the request and forwards it to the backend Lambda Tenant On-boarding function. In this example, there is no authorization or authentication. In a production setup, this API should be integrated with the SaaS infrastructure security system.

1. The Tenant On-boarding function verifies the request. Then it attempts to store the tenant record, which includes the tenant name, generated tenant universally unique identifier (UUID), and tenant description, into the Amazon DynamoDB Tenant On-boarding table. 

1. After DynamoDB stores the record, a DynamoDB stream initiates the downstream Lambda Tenant Infrastructure function.

1. The Tenant Infrastructure Lambda function acts based the on received DynamoDB stream. If the stream is for the INSERT event, the function uses the stream's NewImage section (latest update record, Tenant Name field) to invoke CloudFormation to create a new tenant infrastructure using the template that is stored in the S3 bucket. The CloudFormation template requires the Tenant Name parameter. 

1. AWS CloudFormation creates the tenant infrastructure based on the CloudFormation template and input parameters.

1. Each tenant infrastructure setup has a CloudWatch alarm, a billing alarm, and an alarm event.

1. The alarm event becomes a message to an SNS topic, which is encrypted by the tenant's AWS KMS key.

1. The SNS topic forwards the received alarm message to the SQS queue, which is encrypted by the tenant's AWS KMS for encryption key.

Other systems can be integrated with Amazon SQS to perform actions based on messages in queue. In this example, to keep the code generic, incoming messages remain in queue and require manual deletion.

**Tenant stack deletion flow**

1. User sends a DELETE API request with new tenant payload (tenant name, tenant description) in JSON to the REST API hosted by Amazon API Gateway, which will process the request and forward to Tenant On-boarding function. In this example, there is no authorization or authentication. In a production setup, this API will be integrated with the SaaS infrastructure security system.

1. The Tenant On-boarding function will verify the request and then attempt to delete the tenant record (tenant name) from the Tenant On-boarding table. 

1. After DynamoDB deletes the record successfully (the record exists in the table and is deleted), a DynamoDB stream initiates the downstream Lambda Tenant Infrastructure function.

1. The Tenant Infrastructure Lambda function acts based on the received DynamoDB stream record. If the stream is for the REMOVE event, the function uses the record's OldImage section (record information and Tenant Name field, before the latest change, which is delete) to initiate deletion of an existing stack based on that record information.

1. AWS CloudFormation deletes the target tenant stack according to the input.

## Tools
<a name="tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk-tools"></a>

**AWS services**
+ [Amazon API Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html) helps you create, publish, maintain, monitor, and secure REST, HTTP, and WebSocket APIs at any scale.
+ [AWS Cloud Development Kit (AWS CDK)](https://docs.aws.amazon.com/cdk/v2/guide/home.html) is a software development framework that helps you define and provision AWS Cloud infrastructure in code.
+ [AWS CDK Toolkit](https://docs.aws.amazon.com/cdk/v2/guide/cli.html) is a command line cloud development kit that helps you interact with your AWS Cloud Development Kit (AWS CDK) app.
+ [AWS Command Line Interface (AWS CLI)](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html) is an open-source tool that helps you interact with AWS services through commands in your command-line shell.
+ [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html) helps you set up AWS resources, provision them quickly and consistently, and manage them throughout their lifecycle across AWS accounts and Regions.
+ [Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) is a fully managed NoSQL database service that provides fast, predictable, and scalable performance.
+ [AWS Identity and Access Management (IAM)](https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html) helps you securely manage access to your AWS resources by controlling who is authenticated and authorized to use them.
+ [AWS Key Management Service (AWS KMS) ](https://docs.aws.amazon.com/kms/latest/developerguide/overview.html)helps you create and control cryptographic keys to help protect your data.
+ [AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html) is a compute service that helps you run code without needing to provision or manage servers. It runs your code only when needed and scales automatically, so you pay only for the compute time that you use.
+ [Amazon Simple Storage Service (Amazon S3)](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html) is a cloud-based object storage service that helps you store, protect, and retrieve any amount of data.
+ [Amazon Simple Notification Service (Amazon SNS)](https://docs.aws.amazon.com/sns/latest/dg/welcome.html) helps you coordinate and manage the exchange of messages between publishers and clients, including web servers and email addresses.
+ [Amazon Simple Queue Service (Amazon SQS)](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/welcome.html) provides a secure, durable, and available hosted queue that helps you integrate and decouple distributed software systems and components.
+ [AWS Toolkit for Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/welcome.html) is a plugin for the Visual Studio integrated development environment (IDE). The Toolkit for Visual Studio supports developing, debugging, and deploying .NET applications that use AWS services.

**Other tools**
+ [Visual Studio](https://docs.microsoft.com/en-us/visualstudio/ide/whats-new-visual-studio-2022?view=vs-2022) is an IDE that includes compilers, code completion tools, graphical designers, and other features that support software development.

**Code**

The code for this pattern is in the [Tenant onboarding in SaaS Architecture for Silo Model APG Example](https://github.com/aws-samples/tenant-onboarding-in-saas-architecture-for-silo-model-apg-example) repository.

## Epics
<a name="tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk-epics"></a>

### Set up AWS CDK
<a name="set-up-aws-cdk"></a>


| Task | Description | Skills required | 
| --- | --- | --- | 
| Verify Node.js installation. | To verify that Node.js is installed on your local machine, run the following command.<pre>node --version</pre> | AWS administrator, AWS DevOps | 
| Install AWS CDK Toolkit. | To install AWS CDK Toolkit on your local machine, run the following command.<pre>npm install -g aws-cdk</pre>If npm is not installed, you can install it from the [Node.js site](https://nodejs.org/en/download/package-manager/). | AWS administrator, AWS DevOps | 
| Verify the AWS CDK Toolkit version. | To verify that the AWS CDK Toolkit version is installed correctly on your machine, run the following command.  <pre>cdk --version</pre> | AWS administrator, AWS DevOps | 

### Review the code for the tenant onboarding control plane
<a name="review-the-code-for-the-tenant-onboarding-control-plane"></a>


| Task | Description | Skills required | 
| --- | --- | --- | 
| Clone the repository. | Clone the [repository](https://github.com/aws-samples/tenant-onboarding-in-saas-architecture-for-silo-model-apg-example), and navigate to the `\tenant-onboarding-in-saas-architecture-for-silo-model-apg-example` folder.In Visual Studio 2022, open the `\src\TenantOnboardingInfra.sln` solution. Open the `TenantOnboardingInfraStack.cs` file and review the code.The following resources are created as part of this stack:[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk.html) | AWS administrator, AWS DevOps | 
| Review the CloudFormation template. | In the `\tenant-onboarding-in-saas-architecture-for-silo-model-apg-example\template` folder, open `infra.yaml`, and review the CloudFormation template. This template will be hydrated with the tenant name retrieved from the tenant onboarding DynamoDB table.The template provisions the tenant-specific infrastructure. In this example, it provisions the AWS KMS key, Amazon SNS , Amazon SQS, and the CloudWatch alarm. | App developer, AWS DevOps | 
| Review the tenant onboarding function. | Open `Function.cs`, and review the code for the tenant onboarding function, which is created with the Visual Studio AWS Lambda Project (.NET Core- C\$1) template with the .NET 6 (Container Image) blueprint.Open the `Dockerfile`, and review the code. The `Dockerfile` is a text file that consists of instructions for building the Lambda container image.Note that the following NuGet packages are added as dependencies to the `TenantOnboardingFunction` project:[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk.html) | App developer, AWS DevOps | 
| Review the Tenant InfraProvisioning function. | Navigate to `\tenant-onboarding-in-saas-architecture-for-silo-model-apg-example\src\InfraProvisioningFunction`.Open `Function.cs`, and review the code for the tenant infrastructure provisioning function, which is created with the Visual Studio AWS Lambda Project (.NET Core- C\$1) template with the .NET 6 (Container Image) blueprint.Open the `Dockerfile`, and review the code. Note that the following NuGet packages are added as dependencies to the `InfraProvisioningFunction` project:[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk.html) | App developer, AWS DevOps | 

### Deploy the AWS resources
<a name="deploy-the-aws-resources"></a>


| Task | Description | Skills required | 
| --- | --- | --- | 
| Build the solution. | To build the solution, perform the following steps:[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk.html)Make sure that you update the `Amazon.CDK.Lib NuGet` package to the latest version in `\tenant-onboarding-in-saas-architecture-for-silo-model-apg-example\src\TenantOnboardingInfra` project before you build the solution. | App developer | 
| Bootstrap the AWS CDK environment. | Open the Windows command prompt and navigate to the AWS CDK app root folder where the `cdk.json` file is available (`\tenant-onboarding-in-saas-architecture-for-silo-model-apg-example`). Run the following command for bootstrapping.<pre>cdk bootstrap </pre>If you have created an AWS profile for the credentials, use the command with your profile.<pre>cdk bootstrap --profile <profile name><br />  </pre> | AWS administrator, AWS DevOps | 
| List the AWS CDK stacks. | To list all the stacks to be created as part of this project, run the following command.<pre>cdk ls<br />cdk ls --profile <profile name></pre>If you have created an AWS profile for the credentials, use the command with your profile.<pre>cdk ls --profile <profile name></pre> | AWS administrator, AWS DevOps | 
| Review which AWS resources will be created. | To review all the AWS resources that will be created as part of this project, run the following command.<pre>cdk diff</pre>If you have created an AWS profile for the credentials, use the command with your profile.<pre>cdk diff --profile <profile name></pre> | AWS administrator, AWS DevOps | 
| Deploy all the AWS resources by using AWS CDK. | To deploy all the AWS resources run the following command.<pre>cdk deploy --all --require-approval never</pre>If you have created an AWS profile for the credentials, use the command with your profile.<pre>cdk deploy --all --require-approval never --profile <profile name></pre>After the deployment is complete, copy the API URL from the outputs section in the command prompt, which is shown in the following example.<pre>Outputs:<br />TenantOnboardingInfraStack.TenantOnboardingAPIEndpoint42E526D7 = https://j2qmp8ds21i1i.execute-api.us-west-2.amazonaws.com/prod/</pre> | AWS administrator, AWS DevOps | 

### Verify the functionality
<a name="verify-the-functionality"></a>


| Task | Description | Skills required | 
| --- | --- | --- | 
| Create a new tenant. | To create the new tenant, send the following curl request.<pre>curl -X POST <TenantOnboardingAPIEndpoint* from CDK Output>tenant -d '{"Name":"Tenant123", "Description":"Stack for Tenant123"}'</pre>Change the place holder `<TenantOnboardingAPIEndpoint* from CDK Output>` to the actual value from AWS CDK, as shown in the following example.<pre>curl -X POST https://j2qmp8ds21i1i.execute-api.us-west-2.amazonaws.com/prod/tenant -d '{"Name":"Tenant123", "Description":"test12"}'</pre>The following example shows the output.<pre>{"message": "A new tenant added - 5/4/2022 7:11:30 AM"}</pre> | App developer, AWS administrator, AWS DevOps | 
| Verify the newly created tenant details in DynamoDB. | To verify the newly created tenant details in DynamoDB, perform the following steps.[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk.html) | App developer, AWS administrator, AWS DevOps | 
| Verify the stack creation for the new tenant. | Verify that the new stack was successfully created and provisioned with infrastructure for the newly created tenant according to the CloudFormation template.[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk.html) | App developer, AWS administrator, AWS DevOps | 
| Delete the tenant stack. | To delete the tenant stack, send the following curl request.<pre>curl -X DELETE <TenantOnboardingAPIEndpoint* from CDK Output>tenant/<Tenant Name from previous step></pre>Change the place holder `<TenantOnboardingAPIEndpoint* from CDK Output>` to the actual value from AWS CDK, and change `<Tenant Name from previous step>` to the actual value from the previous tenant creation step, as shown in the following example.<pre>curl -X DELETE https://j2qmp8ds21i1i.execute-api.us-west-2.amazonaws.com/prod/tenant/Tenant123</pre>The following example shows the output.<pre>{"message": "Tenant destroyed - 5/4/2022 7:14:48 AM"}</pre> | App developer, AWS DevOps, AWS administrator | 
| Verify the stack deletion for the existing tenant. | To verify that the existing tenant stack got deleted, perform the following steps:[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk.html) | App developer, AWS administrator, AWS DevOps | 

### Clean up
<a name="clean-up"></a>


| Task | Description | Skills required | 
| --- | --- | --- | 
| Destroy the environment. | Before the stack clean up, ensure the following:[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk.html)After testing is done, AWS CDK can be used to destroy all the stacks and related resources by running the following command.<pre>cdk destroy --all;</pre>If you created an AWS profile for the credentials, use the profile.Confirm the stack deletion prompt to delete the stack. | AWS administrator, AWS DevOps | 
| Clean up Amazon CloudWatch Logs. | The stack deletion process will not clean up CloudWatch Logs (log groups and logs) that were generated by the stack. Manually clean up the CloudWatch resources by using the CloudWatch console or the API. | App developer, AWS DevOps, AWS administrator | 

## Related resources
<a name="tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk-resources"></a>
+ [AWS CDK .NET Workshop](https://cdkworkshop.com/40-dotnet.html)
+ [Working with the AWS CDK in C\$1](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-csharp.html)
+ [CDK .NET Reference](https://docs.aws.amazon.com/cdk/api/v2/dotnet/api/index.html)

## Additional information
<a name="tenant-onboarding-in-saas-architecture-for-the-silo-model-using-c-and-aws-cdk-additional"></a>

**Control-plane technology stack**

The CDK code written in .NET is used to provision the control-plane infrastructure, which consists of the following resources:

1. **API Gateway**

   Serves as the REST API entry point for the control-plane stack.

1. **Tenant on-boarding Lambda function**

   This Lambda function is initiated by API Gateway using the m method.

   A POST method API request results in (`tenant name`, `tenant description`) being inserted into the DynamoDB `Tenant Onboarding` table.

   In this code example, the tenant name is also used as part of the tenant stack name and the names of resources within that stack. This is to make these resources easier to identify. This tenant name must be unique across the setup to avoid conflicts or errors. Detailed input validation setup is explained in the [IAM roles](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html) documentation and the *Limitations* section.

   The persistence process to the DynamoDB table will succeed only if the tenant name is not used in any other record in the table.

   The tenant name in this case is the partition key for this table, because only the partition key can be used as a `PutItem` condition expression.

   If the tenant name was never recorded before, the record will be saved into the table successfully.

   However, if the tenant name is already used by an existing record in the table, the operation will fail and initiate a DynamoDB `ConditionalCheckFailedException` exception. The exception will be used to return a failure message (`HTTP BadRequest`) indicating that the tenant name already exists.

   A `DELETE` method API request will remove the record for a specific tenant name from the `Tenant Onboardin`g table.

   The DynamoDB record deletion in this example will succeed even if the record does not exist.

   If the target record exists and is deleted, it will create a DynamoDB stream record. Otherwise, no downstream record will be created.

1. **Tenant on-boarding DynamoDB, with Amazon DynamoDB Streams enabled**

   This records the tenant metadata information, and any record save or deletion will send a stream downstream to the `Tenant Infrastructure` Lambda function. 

1. **Tenant infrastructure Lambda function**

   This Lambda function is initiated by the DynamoDB stream record from the previous step. If the record is for an `INSERT` event, it invokes AWS CloudFormation to create a new tenant infrastructure with the CloudFormation template that is stored in an S3 bucket. If the record is for `REMOVE`, it initiates deletion of an existing stack based on the stream record's `Tenant Name` field.

1. **S3 bucket**

   This is for storing the CloudFormation template.

1. **IAM roles for each Lambda function and a service role for CloudFormation**

   Each Lambda function has its unique IAM role with [least-privilege permissions](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) to achieve its task. For example, the `Tenant On-boarding` Lambda function has read/write access to DynamoDB, and the `Tenant Infrastructure` Lambda function can only read the DynamoDB stream.

   A custom CloudFormation service role is created for tenant stack provisioning. This service role contains additional permissions for CloudFormation stack provisioning (for example, the AWS KMS key). This divides roles between Lambda and CloudFormation to avoid all permissions on a single role (Infrastructure Lambda role).

   Permissions that allow powerful actions (such as creating and deleting CloudFormation stacks) are locked down and allowed only on resources that start with `tenantcluster-`. The exception is AWS KMS, because of its resource naming convention. The ingested tenant name from the API will be prepended with `tenantcluster-` along with other validation checks (alphanumeric with dash only, and limited to less than 30 characters to fit into most AWS resource naming). This ensures that the tenant name will not accidentally result in disruption of core infrastructure stacks or resources.

**Tenant technology stack**

A CloudFormation template is stored in the S3 bucket. The template provisions the tenant-specific AWS KMS key, a CloudWatch alarm, an SNS topic, an SQS queue, and an [SQS policy](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-using-identity-based-policies.html).

The AWS KMS key is used for data encryption by Amazon SNS and Amazon SQS for their messages. The security practices for [AwsSolutions-SNS2 and AwsSolutions-SQS2](https://github.com/cdklabs/cdk-nag/blob/main/RULES.md) recommend that you set up Amazon SNS and Amazon SQS with encryption. However, CloudWatch alarms don’t work with Amazon SNS when using an AWS managed key, so you must use a customer managed key in this case. For more information, see the [AWS Knowledge Center](https://aws.amazon.com/premiumsupport/knowledge-center/cloudwatch-receive-sns-for-alarm-trigger/).

The SQS policy is used on the Amazon SQS queue to allow the created SNS topic to deliver the message to the queue. Without the SQS policy, the access will be denied. For more information, see the [Amazon SNS documentation](https://docs.aws.amazon.com/sns/latest/dg/subscribe-sqs-queue-to-sns-topic.html#SendMessageToSQS.sqs.permissions).