Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi-tenant MongoDB + mongo-native driver + connection pooling

We are trying to implement the strategy outlined in the following presentation (slides 13-18) using nodejs/mongo-native driver.

https://www.slideshare.net/mongodb/securing-mongodb-to-serve-an-awsbased-multitenant-securityfanatic-saas-application

In summary:

  • Create a connection pool to mongodb from node.js.
  • For every request for a tenant, get a conenction from the pool and "authenticate" it. Use the authenticated conenection to serve the request. After response, return the connection to the pool.

Im able to create a connection pool to mongodb without specifying any database using the mongo-native driver like so:

const client = new MongoClient('mongodb://localhost:27017', { useNewUrlParser: true, poolSize: 10 });

However, in order to get a db object, I need to do the following:

const db = client.db(dbName);

This is where I would like to authenticate the connection, and it AFAICS, this functionality has been deprecated/removed from the more recent mongo drivers, node.js and java.

Going by the presentation, looks like this was possible to do with older versions of the Java driver.

Is it even possible for me to use a single connection pool and authenticate tenants to individual databases using the same connections ?

The alternative we have is to have a connection pool per tenant, which is not attractive to us at this time.

Any help will be appreciated, including reasons why this feature was deprecated/removed.

like image 882
Anand Hariharan Avatar asked Aug 04 '19 08:08

Anand Hariharan


Video Answer


1 Answers

it's me from the slides!! :) I remember that session, it was fun.

Yeah that doesn't work any more, they killed this magnificent feature like 6 months after we implemented it and we were out with it in Beta at the time. We had to change the way we work..

It's a shame since till this day, in Mongo, "connection" (network stuff, SSL, cluster identification) and authentication are 2 separate actions. Think about when you run mongo shell, you provide the host, port, replica set if any, and your in, connected! But not authenticated. You can then authenticate to user1, do stuff, and then authenticate to user2 and do stuff only user2 can do. And this is done on the same connection! without going thru the overhead creating the channel again, SSL handshake and so on...

Back then, the driver let us have a connection pool of "blank" connections that we could authenticate at will to the current tenant in context of that current execution thread.

Then they deprecated this capability, I think it was with Mongo 2.4. Now they only supported connections that are authenticated at creation. We asked enterprise support, they didn't say why, but to me it looked like they found this way is not secured, "old" authentication may leak, linger on that "not so blank" reusable connection.

We made a change in our multi-tenancy infra implementation, from a large pool of blank connections to many (small) pools of authenticated connections, a pool per tenant. These pools per tenant can be extremely small, like 3 or 5 connections. This solution scaled nicely to several hundreds of tenants, but to meet thousands of tenants we had to make all kinds of optimizations to create pools as needed, close them after idle time, lazy creation for non-active or dormant tenants, etc. This allowed us to scale even more... We're still looking into solutions and optimizations.

You could always go back to a global pool of authenticated connections to a Mongo user that have access to multiple databases. Yes, you can switch database on that same authenticated connection. You just can't switch authentication.. This is an example of pure Mongo Java driver, we used Spring which provide similar functionality:

MongoClient mongoClient = new MongoClient();
DB cust1db = mongoClient.getDB("cust1");
cust1db.get...
DB cust2db = mongoClient.getDB("cust2");
cust2db.get...

Somewhat related, I would recommend looking at MongoDB encryption at rest, it's an enterprise feature. The only way to encrypt each database (each customer) according to a different key.

like image 107
Doron Levari Avatar answered Nov 20 '22 16:11

Doron Levari