[Feature] CosmosClient multi-tenant enablement
See original GitHub issueContext
One of popular multi-tenant pattern, is to partition data per application tenant. Partitioning can be by Container OR container/PK (later is very prominent). Scale of multi-tenants might be very high.
Least privilege access principle demands application to use very constrained access credentials. Azure Cosmos DB has ResourceTokens which enables fine grained access credentials.
Challenges/Gaps
Client instances ~ #tokens
Tokens are created on-demand (when new tenant created etc…), and new CosmosClient instances needs to be created to access data. Resulting in #clients approx. #tokens.
- Anti-pattern: Cosmos recommends Singleton pattern
- Non-optimal (result of multiple instances) and might result in throttling
Maintaining a valid token
Each token generated has a temporal validity after which are invalid. Application needs to keep re-generate new replacement tokens for the ones which are expiring.
- Re-generation demands CosmosClient re-creation
- Re-generation demands service interaction NW call
- Maintain map of token -> validity
This issue is trying to address the CosmosClient gaps only. Hence token generation gaps are out-of-scope.
Possibilities
Authorization provider API
Abstract authorization into a plug-in MasterKey plug-in will be out-of-box, enable customization for ResourceToken based implementation. Draft below
- Fully extensible: Can be even leveraged for credential swap/rotation
- Advanced usage: Depth of knowledge to map cosmos addressing -> tenant. Get-started sample might help, still user need to maintain it.
- Overloaded with non-user concerns: ex: Background calls, new resource addresses
abstract class ICosmosAuthorizationProvider
{
string GetAuthorization(OperationContext context);
}
class MasterKeyAuthorizationProvider : ICosmosAuthorizationProvider
{
public MasterKeyAuthorizationProvider(string masterKey)
{
...
}
public override string GetAuthorization(OperationContext context)
{
return AuthorizationHelper.Generate..(context);
}
}
class TokenAuthorizationProvider : ICosmosAuthorizationProvider
{
private Dictionay<string, string> tenantToTokens;
public MasterKeyAuthorizationProvider(string masterKey)
{
...
}
public override string GetAuthorization(OperationContext context)
{
string tenant = GetTenant(context);
return tenantToTokens[tenant];
}
}
Request level credential
Application has full context of tenant and easier/intutive to pass required context into the API call. One possibility is to have it as ReqeustOption, draft below.
What about non-user invoke API concerns like background calls etc… few possibilities are
- Use master key & assert its non-use through custom handler
- Enable client-option to start with no-key & lazy bound initialization to API invocation
class RequestOptions
{
...
public string Authorization { get; set; }
}
Recommendation
ReqeustOptions is simple and very intutive. And get started with “MasterKey” based constructor. Its a kind of override mechanism. Assertion of always override can be asserted through CustomHandler.
References:
https://docs.microsoft.com/en-us/azure/cosmos-db/secure-access-to-data#resource-tokens #622 ResourceTokens support
Issue Analytics
- State:
- Created 4 years ago
- Reactions:7
- Comments:11 (1 by maintainers)
Top GitHub Comments
@kirankumarkolli bumping this as well. We’re in need of this functionality and opening and closing a
CosmosClient
is causing major connection issues in our application at scale.If I am not mistaken, the situation with multiple
CosmosClient
instances is exacerbated by the fact that the client owns an instance of theDocumentClient
class which in turn owns anHttpClient
. The http client is disposed with theDocumentClient
when theCosmosClient
is disposed. And we all know what this can lead to…