A SaaS with one tenant per customer

TeselaDB

TeselaDB

TeselaDB team

30 minAdvanced

Put each customer in its own tenant of the same cluster, with its users and its databases, without any of them seeing the others.

A SaaS with many small customers does not need a cluster per customer, because in TeselaDB each customer can be a tenant of the same cluster. Each user belongs to one tenant. Authentication sets the tenant of the connection from its user and authorization keeps it out of another tenant's databases.

What you will build

Two tenants, acme and globex, each with a user for its application and its own shop database. Both use the same database name and each application only sees the databases of its tenant.

Requirements

  • A TeselaDB cluster with users and access to teseladb admin.
  • A tenant 0 user allowed to create users, such as root.

1. Create the tenants

Shell
teseladb admin --node node-01:27200 tenant create acme
teseladb admin --node node-01:27200 tenant create globex

2. Create a user in each tenant

From a tenant 0 connection, the $tenant argument makes the command work in another tenant. The user name is unique across the cluster, so each tenant has its own:

for (const tenant of ["acme", "globex"]) {
  db.getSiblingDB("admin").runCommand({
    createUser: `${tenant}-api`,
    pwd: passwordPrompt(),
    roles: [{ role: "readWrite", db: "shop" }],
    $tenant: tenant,
  });
}

3. Connect each application with its user

Each customer's application uses the string with its user. The tenant comes from authentication:

Shell
export TESELADB_URI="mongodb://acme-api:<password>@node-01:27017,node-02:27017/shop?tls=true&tlsCAFile=./ca.pem"

Try it

Connected as acme-api with the string of step 3, write an order in the orders collection of shop and then list the databases of the cluster to see which ones the application of acme can reach:

JavaScript
db.orders.insertOne({ customer: "Ana", total: 30 });
db.adminCommand({ listDatabases: 1, nameOnly: true });

listDatabases shows only shop, the one of acme. Connected as globex-api, the orders collection of its shop database is empty, and on the cluster it only has listDatabases, bypassDefaultMaxTimeMS and useUUID.

Clean up

Drop the databases and the users of each tenant from tenant 0 and then the tenants. tenant drop fails while the tenant still has databases or users:

Shell
teseladb admin --node node-01:27200 tenant drop acme
teseladb admin --node node-01:27200 tenant drop globex

Next steps