From cbedf66d1979cf5b1e2c5616790a3024c5054756 Mon Sep 17 00:00:00 2001 From: Ralf Haferkamp Date: Mon, 30 Jun 2025 16:51:32 +0200 Subject: [PATCH] adr(multi-tenancy): Add more details to the Problem Statement Also collect Pros/Cons of the different options --- ...nancy-using-a-single-opencloud-instance.md | 133 ++++++++++++++---- 1 file changed, 107 insertions(+), 26 deletions(-) diff --git a/docs/adr/0001-simple-multi-tenancy-using-a-single-opencloud-instance.md b/docs/adr/0001-simple-multi-tenancy-using-a-single-opencloud-instance.md index 8269a9e71..0211fccbd 100644 --- a/docs/adr/0001-simple-multi-tenancy-using-a-single-opencloud-instance.md +++ b/docs/adr/0001-simple-multi-tenancy-using-a-single-opencloud-instance.md @@ -14,41 +14,123 @@ To reduce resource usage and cost service providers want a single OpenCloud instance to host multiple tenants. Members of the same tenant should be able to only see each other when trying to share resources. A user can only be a member of a single tenant. Moving a user from one tenant to another is not supported. -For the scope of this ADR we assume the tenants are overall rather small -(sometimes just a single user, often less than 10). There is just a single IDP -with a single "realm". Also there is no need to support per tenant groups of -users for now. + +OpenCloud does currently not have any concept of multi-tenancy. All users able to +login to an OpenCloud instance are able to see each other and share resources with +everybody. This ADR is supposed to layout a concept for a minimal multi-tenancy +solution that implements the characteristics mentioned above. + +To further limit the scope there are a couple of constraints: + +- Tenants are rather small (sometimes just a single user, often less than 10) +- There is just a single IDP with a single "realm". +- The user-management is external to OpenCloud. There is no tenant-specific adminstrator + that can add/delete users. +- The membership of a user to a tenant is represented by a tenant id + that is provided via a claim in the users' Access Token/UserInfo or by a per User + Attribute in the LDAP directory. +- There is no need to support per tenant groups +- There is no need to isolate the storage of the tenants from each other ## Decision Drivers -* Low Resource Overhead: The solution should not require a lot of additional - resources (CPU, Memory, Storage) on the OpenCloud instance. +* Low Resource Overhead: The solution should not require much additional + resources (CPU, Memory, Storage) per tenant on the OpenCloud instance. * Implementation effort: The solution should be easy to implement and maintain. * Security: The solution should prevent users from seeing or accessing anything from other tenants. + ## Considered Options -The user <-> tenant id relation in maintained by the OIDC IDP and the tenant id -will be available as a claim in the OIDC tokens. A tenant id is assigned to -every user. +### Option 1: Tenant ID as a new property of the CS3 UserId -* Option 1: Users are autoprovisioned on the 1st login. The value of the tenant id - will be persisted as a new part of the CS3 UserId. Everywhere the UserID is used - the tenant id is also available. This allows to implement more sophisticated checks e.g. - on permission grants and to a certain extend during share creation. -* Option 2: Users are autoprovisioned on the 1st login. The value of the tenant id - will be persisted as a new property of the CS3 User Object. (Just a minor difference to Option 1, - to avoid overloading the UserId with yet another property.) -* Option 3: Users are autoprovisioned on the 1st login. The value of the tenant id - will be persisted in the user backend (usually LDAP in our case). There will not be any a new properties - on CS3 UserID or User Object. Whenever a user lookup is done the tentant id of the - requesting user (taken from the reva token) is used to construct the appropriate backend query - (LDAP filter or subtree or ...) to only return users of the same tenant. -* Option 4: All of the above would also work without the autoprovisioning step. - In that case an external LDAP server would need to be available that - maintains the users' tenant assignments either via an explicit attribute on - the users or by using a per-tenant subtrees. +The CS3 UserId (https://buf.build/cs3org-buf/cs3apis/docs/main:cs3.identity.user.v1beta1#cs3.identity.user.v1beta1.UserId) +is extended by a new property "tenantId". + +#### Pros: + +* Everywhere the UserID is used the tenant id is also available. + * This might allow implementing more sophisticated checks e.g. on permission + grants and to a certain extend during share creation. + * the tenant id is immediately available e.g. in Events/Auditlog without an addtional + user lookup + +#### Cons: + +* Requires changes to the CS3 API +* Adds even more semantics to the UserId. Ideally the UserID would just be an + opaque identifier without carrying and specific semantics other than being + globally unique. +* on the GraphAPI the ID of a User is just a opaque string without any additional + meaning. (Currently it is just using the `OpqueId` property of the CS3 UserId, + without considering the `idp` property.) + +### Option 2: Tenant ID is stored as the `idp` value of the CS3 UserId + +Instead of introducing a new property the on the CS3 UserId we'll just override +the `idp` value with the tenant id. + +#### Pros + +* No changes to the CS3 API required +* The pros of Option 1 apply here as well + +#### Cons: + +* It's a crutch, we're already "abusing" the `idp` property of the CS3 UserId + to have a different meaning in the context of federated sharing. Adding an + additiona meaning could make the code even more complicated. +* Apart from the API change the Cons of Option 1 apply here as well. + +### Option 3: Tenant ID is a property of the CS3 User Object + +A new (optional) property "tenantId" is added to the CS3 User Object. + +#### Pros: + +* Avoid overloading CS3 UserId with additional semantics. +* The tenant id is available everywhere the User Object is used. + +#### Cons: + +* Requires changes to the CS3 API +* Might require more user lookups in places where we need to find out the + tenant id of a specific user + +### Option 4: Tenant ID is invisible to the CS3 API + +Reva Tokens would get a new property `tenantId`. To have the tenant id available +of the signed in user available with every request. +While not being part of the CS3 API objects the `users` service will be made "tenant aware" +so that is only returns users of the same tenant as the requesting user e.g. by using +proper LDAP filters or subtree searches. + +#### Pros: + +* No changes to the CS3 API required +* Code changes could be limited to the `users` and`share-provider` services and the reva token manager +* The tenant id of the current user is available everywhere the reva token is used. + +#### Cons: + +* Can this work with the App Token feature if the Tenant Id is not part of the User Object in + any way, how can the the token manager know with Id to add to the token? +* What about places where the system user is doing stuff on behalf of a user + +### Option 5: Tenant membership via LDAP group membership + +All members of a tenant are assigned to the same group. The `users` service gets a config +switch to only allow users to search for users that are part of the same group. + +#### Pros: + +* ? + +#### Cons: + +* The group needs to be hidden somehow from the `groups` service as this is not supposed to be a + "sharing group". ## Decision Outcome @@ -78,6 +160,5 @@ and all sharees are part of the same tenant. ### Negative consequences: -* requires changes to the CS3 API * no clear data separation