elsa-core
elsa-core copied to clipboard
Multitenancy
An area of functionality which has been requested a few times across various mediums (issues, discussion, chat) is support for multi-tenancy.
This is a quite wide subject with numerous potential interpretations. Before it can be conclusively implemented we should answer such questions as:
- What does multi-tenancy mean to Elsa?
- What model(s) of multi-tenancy should Elsa support?
- What should be left to the consuming application?
- What will Elsa explicitly not-support?
Once we have a better understanding of the requirements, we can formulate a strategy for support and schedule appropriate enhancements.
Roundup of related issues
The following are issues which relate to requests for multi-tenancy. It should be added-to as further issues are raised/found.
- [ ] #762 - variable workflow definitions/logic per-tenant
- #140 - discussion/request for support
- [ ] #242 - another issue/story for multi-tenancy
- [ ] #221 - touches on multi-tenancy
First thing about multi-tenancy that comes into my mind is user authorization (for dashboard and designer). How else do you know which workflow belongs to which tenant?
That's an interesting point.
Elsa & authorization
I don't personally think that Elsa should get too deeply involved in auth. The main reason for that is that we can't predict every app's authentication/authorization model. I think that at absolute most what we should do is provide an extension point/hook which is something like:
public interface IGetsPermissionToEditWorkflow
{
bool CanEditWorkflow(string workflowCorrelationId);
}
Our default impl of that class would be to hard-code a true
result every time. But then a consumer of Elsa may supply their own impl via DI and add whatever logic in there that they want.
One multi-tenancy example
As it happens, "my day job customer" is using Elsa in an app which is already multi-tenant. We achieve this by:
- Using Single Sign On (happens to be Identity Server) which knows about all of the tenants
- When a user logs into the app, they may choose between the available tenants
- We have some tricks in play which means some URLs cause the tenant to be pre-selected and hidden from the UI
- Different "identity" users have mappings to different levels of permission in different tenants
- So [email protected] might be an Admin on Tenant A, might be a regular user on Tenant B and might not be allowed to access Tenant C at all
- Once login is complete, the "current tenant" for that login session is held as one of the claims within the authentication token
- Each tenant's data is stored within a different instance of the application database (literally a different connection string).
- We use a combination of that "current tenant ID" claim and an app/tenants configuration to generate a connection string
- DI makes sure that when we get a DB connection anywhere in the app, it came from the correct tenant-specific DB
- The connection itself is scoped per HTTP request, so everything in a single request uses one connection
Now, we've already got this implemented just fine, actually using Elsa 1.4 (we'll upgrade probably once 2.0 is ready for stable release). Elsa itself knows nothing about our users, or our multi-tenancy setup. All we needed to do (in our closed source app) was to extend the registration mechanisms for Elsa. That was partly replayed back into Elsa as open source contribs in #748 (actually some of we had done had already been done as part of Elsa 2.0!).
We are kind of lucky though in that we don't use the dashboard or designer UIs yet. The user-specific configuration/customisation of our workflow(s) is already built into the app (we used to use a different workflow product) and so we already have our own UI for doing all of that, and it already respects our own auth rules.
Thanks for the explanation of your use case. I agree Elsa should have an interface for multi-tenancy/authorization and implement true by default. But would definitely like to see this interface include "all" aspects of multi-tenancy in elsa (for example connection string fetching through that interface). Or at least ones that you described and know of (since you already did it) combined with dashboard and designer.
Exactly, I think that's a good starting point for the discussion which needs to happen. Indeed, one possible strategy to supporting multi-tenancy might just be to support all of the right extension points to do all of this stuff (part of the work we'd need to do is to identify what those are).
There's lots of possibilities available and at some point I think we're all going to have to get together and make our minds up. Right now priority no. 1 is getting Elsa 2.0 out of the door, and so we're not focussing too much on multi-tenancy. That doesn't mean we're not accepting ideas and talking points though.
So would it be possible to make a place/hook in Elsa 2.0 dashboard/designer to include custom JS code which could be fired and executed in cases where API calls fail due to the fact that they weren't authorized? And of course ability to add custom headers and or cookies to the API calls (namely authorization header one I guess).
We can definitely add that, it makes sense.
Elsa is good enough workflow engine, multi tenant should be something handled outside wrapped to Elsa and set the required DB connection to it
instead of making Elsa jack of all its better Elsa becomes just master of workflow
That depends on the how you define multi-tenancy @khan-mail-com Your approach assumes (or at least that is how I read your comment, sorry if I'm mistaken) that each tenant has its own database (so all you need to do is point Elsa to different db). However what about when you want multiple tenants inside each database?
Moreover even if they were inside same database, when (and how) would you point Elsa to different database? At each inbound HTTP request? Yes this is possible probably. But since workflow can continue on timers/schedules without inbound requests that leaves two places where it should be possible, and probably many more....
I agreee that some stuff should be left outside of Elsa (like user auth, etc....). But elsa definitely needs to be "internally" multi-tenant and have hooks for all the cases where you want to somehow "tell" it which tenant to use (either by completely switching database or by changing some internal id of a tenant when multiple tenants are inside same db).
Yes, multi-tenancy for separate DB, all you need to do is point to separate DB but i think HangFire services may require to configured to point each of DB to run schedules
for same DB, we need to apply the context filter with the tenant ID, which is again a top layer thing
On Tue, Nov 23, 2021 at 5:08 PM tomy2105 @.***> wrote:
That depends on the how you define multi-tenancy @khan-mail-com https://github.com/khan-mail-com Your approach assumes (or at least that is how I read your comment, sorry if I'm mistaken) that each tenant has its own database (so all you need to do is point Elsa to different db). However what about when you want multiple tenants inside each database?
Moreover even if they were inside same database, when (and how) would you point Elsa to different database? At each inbound HTTP request? Yes this is possible probably. But since workflow can continue on timers/schedules without inbound requests that leaves two places where it should be possible, and probably many more....
I agreee that some stuff should be left outside of Elsa (like user auth, etc....). But elsa definitely needs to be "internally" multi-tenant and have hooks for all the cases where you want to somehow "tell" it which tenant to use (either by completely switching database or by changing some internal id of a tenant when multiple tenants are inside same db).
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/elsa-workflows/elsa-core/issues/764#issuecomment-976588105, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKECRB7DBK43UJIMY5RV5CTUNON7PANCNFSM4ZHLREBA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
I have to support both multi-tencancy modes. This would be super usefull.
Well being able to have multi-tenancy by using a separate database for each tenant is gread. We use abp however, which also allows to keep tenants in a single database. In that case, we have a "int TenantId" property on every entity which denotes the tenant. The EF DbContext then automatically applies the filter to get only the current tenant data.
I read that for ELsa 3 the storage api is revised to make it easier for devs to create their own storage provider. Does this then also allow us to add such a "tenant filtering" mechanism?
I see in the code that there is a reference to TenantId, so it looks like it has been implemented in Elsa to a certain extent for single database approaches.
It might be interesting to look at a library like FinBuckle and the patterns it uses to introduce multitenancy into .NET projects. That could provide an essential guide for opening Elsa up to multitenancy through other frameworks. Aspects of better access to DBContext in Elsa and implementation of options builders.
@jspitman I had not heard of FinBuckle before, will look into it. Thanks for pointing it out!
I’m not a 100% sure but I think it had some issues with Blazor. Maybe I’m wrong. Anyway we’re doing multitenancy in our new Blazor app without it and it works just fine, it’s simpler. Maybe it’s not needed. Just saying.
Re: MultiTenancy,
Am investigating different workflow automation tools for work. Elsa looks pretty good but part of my evaluation is looking at aspects like multitenancy and project separation, which is an area Elsa performs poorly in.
Another product I'm comparing it to is Dolphin Scheduler, which allows for both multitenancy and project separation. It is however, excessively complex and unintuitive for our intended audience (operators/tier 2), which is something that Elsa does really, REALLY, well.
Ultimately, cause elsa is .net, we can probably roll our own nodes to ensure that data for one organisation never hits an endpoint or accesses data outside of what it is allowed, and edit the dashboard to allow us to filter on orgs, but ya know, that is a pain. Or we would need to spin up multiple elsa instances (like logic apps), and put some sort of proxy service in front of it, which is still, a pain.
Definitely something I think elsa should support, but I'm biased because it would make my life easier haha.
Hi @Gryhyphen,
Thank you for your detailed feedback on Elsa's multi-tenancy capabilities compared to other tools like Dolphin Scheduler.
I completely understand where you're coming from. Multi-tenancy is indeed an essential feature, and we are committed to improving Elsa in this aspect. While Elsa 3 offers features like Events and the Webhooks module, and also ensures extensibility for cross-app communication via service bus messaging, I acknowledge that there might be areas where it falls short in terms of project separation and multi-tenancy.
Could you perhaps provide specific instances or features you found lacking or any suggestions for improvement? This would greatly help us refine and potentially update our roadmap to better cater to your scenarios.
Our 2024 focus is on enhancing the maturity of the Elsa engine for scalable production use, which encompasses multi-tenancy and security.
Again, I appreciate your insights and look forward to hearing more from you!