aws-amplify / amplify-cli

The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development.
Apache License 2.0
2.81k stars 821 forks source link

Support better multi-tenancy with @tenant transformer #3654

Closed mdegrees closed 4 years ago

mdegrees commented 4 years ago

Is your feature request related to a problem? Please describe. Multi-tenancy (MT) implementation support using Amplify is very limited. The only MT strategy that is possible is to have a tenantId column in tables. With 100+ tenants, table sizes might explode. Making lookups slow and deleting a tenant data complicated.

A better alternative is to have tenant specific tables using prefixing: tenantid1_posts, tenantid_2_posts ... . This can possibly be achieved with a @tenant transformer with something like:

type Blog @model {
  id: ID!
  name: String!
  posts: [Post] @connection(name: "BlogPosts")
}
type Post @model @tenant {
  id: ID!
  title: String!
  blog: Blog @connection(name: "BlogPosts")
  tenantid: String
}

such as when a tenantid is provided, the entry will be created in a separate tenantid prefixed table/collection.

About MT strategies https://d0.awsstatic.com/whitepapers/Multi_Tenant_SaaS_Storage_Strategies.pdf

undefobj commented 4 years ago

@mdegrees We are looking at more multi-tenancy support this year, however rather than look at a specific implementation could you uplevel a bit and go into detail around your use cases and scenarios? This would allow us to look at if there is a point feature causing problems here or a larger design that is cross cutting categories which needs implementation. Thanks.

benmj commented 4 years ago

@mdegrees We are looking at more multi-tenancy support this year, however rather than look at a specific implementation could you uplevel a bit and go into detail around your use cases and scenarios? This would allow us to look at if there is a point feature causing problems here or a larger design that is cross cutting categories which needs implementation. Thanks.

Great to know this is on your radar, @undefobj . Do you have a sense of when this may be tackled by the team, or suggestions for strategies related to multi-tenancy in the meantime?

mdegrees commented 4 years ago

@undefobj my use case is largely similar to Slack. Users create spaces. Some spaces are private some are public. In each space, users belong to privilege groups: admins, moderators, regular users. Admins get to decide what's authorized and what's not on their space. For e.g they can enable/disable moderators to delete posts.

The first wall I hit was: configurable auth. Amplify allows you to statically define the rules, but what if auth is configurable at the user level.

The second wall I hit was isolating data. In an sql database I would create a database per space. For security reasons but also for ease of manipulation. Deleting a tenant for e.g is as simple as deleting a database. An acceptable compromise is isolation at the table level: adding a prefix to tenant tables (the proposal).

In a perfect world where amplify has an API and deployment of a new amplify instance takes less than 5 seconds, this problem would've not existed. I would just interact with the amplify API , create or update a whole amplify instance upon user actions (on behalf of users).

Right now I had no choice but ejecting @modal and @auth scaffoldings and go manual with @function Lamda resolvers. I kept researching and trying for weeks but reached a deadlock.

Thank you

undefobj commented 4 years ago

@undefobj my use case is largely similar to Slack. Users create spaces. Some spaces are private some are public. In each space, users belong to privilege groups: admins, moderators, regular users. Admins get to decide what's authorized and what's not on their space. For e.g they can enable/disable moderators to delete posts.

The first wall I hit was: configurable auth. Amplify allows you to statically define the rules, but what if auth is configurable at the user level.

What does this mean specifically? You want to define an owner on a database record? Amplify supports this. I'm not really following what "configurable at the user level" means.

The second wall I hit was isolating data. In an sql database I would create a database per space. For security reasons but also for ease of manipulation. Deleting a tenant for e.g is as simple as deleting a database. An acceptable compromise is isolation at the table level: adding a prefix to tenant tables (the proposal).

In a perfect world where amplify has an API and deployment of a new amplify instance takes less than 5 seconds, this problem would've not existed. I would just interact with the amplify API , create or update a whole amplify instance upon user actions (on behalf of users).

If you're going to separate each tenant by database, then why not just duplicate Amplify projects? Separate databases is a way to go but I think this is opposite from what many people define multi tenancy to be. Usually it's shared resources be that User Directories, Databases, or even Compute instances (the lowest level). Separate databases will have more operational overhead and ultimately costs which is why shared tenancy gives you business advantages.

I don't think a specific directive solves these problems. Perhaps this article talking about different techniques might help you here: https://medium.com/@dantasfiles/multi-tenant-aws-amplify-cc3252c4def4 Note that the OR rules for @auth are on our roadmap and that might be a way to help your design further.

RossWilliams commented 4 years ago

@undefobj Do you have anything to share about the design of your AND rule implementation? Are there any plans to develop it in the open? AND rules were critical for me to create a multi-tenant system.

undefobj commented 4 years ago

@undefobj Do you have anything to share about the design of your AND rule implementation? Are there any plans to develop it in the open? AND rules were critical for me to create a multi-tenant system.

Right now just matching proposal 5 is planned: https://github.com/aws-amplify/amplify-cli/issues/1043 If there's more feedback needed it will be public.

mdegrees commented 4 years ago

What does this mean specifically? You want to define an owner on a database record? Amplify supports this. I'm not really following what "configurable at the user level" means.

Imagine we're creating AMAs as a service. It's a service where customers create dedicated ask me anything pages. AMAs can be private or public. It's the customer who decides. (1) There is a switch in the admin panel to go private or public. (2) There is also a setting option that enables or disables moderators to edit the incoming questions.

In this case auth rules are dynamic and managed at the user level. I can default the schema to some auth rules. But the tenant can go and update them. I've learned about dynamic group access in the docs. If I've well understood to address feature number 2 for e.g, you would go with something like

type Question @model
  @auth(rules: [
    { allow: groups, groupsField: "groupsCanUpdate", operations: [update] }
  ]) {
  id: ID!
  title: String!
  content: String
  owner: String
  editors: [String]!
  groupsCanUpdate: [String]!
}

Then get groupsCanUpdate array from a settings table?

Also if auth is defined per record. Does it mean if groupsCanAccess is set to ['admin', 'moderators'] then the tenant decides to change this value, I have to update all the previous records with the new [string] value? What if there was thousands of them?

undefobj commented 4 years ago

Yes if you're setting group ACLs on an individual record, then you need to go back and update the records if information changes. This is why ideally you would separate groups by tenant and then update the groups rather than the records. So it's really up to you on what type of control and partitioning you'd like to give but the controls are in the system.

mdegrees commented 4 years ago

@undefobj is there any example i can look at? What would it look like for the above example? thank you

undefobj commented 4 years ago

No I don't have an example of updating records handy, but you should be able to do this using Lambda and the DynamoDB document client.

mdegrees commented 4 years ago

@undefobj ok, thank you! This reddit discussion revolves around the same pain points. Referencing it here for further readers and contributors. https://www.reddit.com/r/aws/comments/fccx6k/multitenant_app_using_aws_amplify/

github-actions[bot] commented 3 years ago

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels for those types of questions.