mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-29 00:11:21 -05:00
152 lines
5.9 KiB
Markdown
152 lines
5.9 KiB
Markdown
---
|
|
title: "1. Simple Multi-Tenancy using a single OpenCloud Instance"
|
|
---
|
|
|
|
* Status: proposed
|
|
* Deciders: [@micbar @butonic @dragotin @rhafer]
|
|
* Date: 2025-05-20
|
|
|
|
Technical Story: https://github.com/opencloud-eu/opencloud/issues/877
|
|
|
|
## Context and Problem Statement
|
|
|
|
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.
|
|
|
|
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
|
|
- 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
|
|
- Role Assignment happens at first login via OIDC claims
|
|
|
|
## Decision Drivers
|
|
|
|
* 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
|
|
|
|
### Option 1: Tenant ID as a new property of the CS3 UserId
|
|
|
|
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 additional
|
|
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 `OpaqueId` 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
|
|
|
|
### Chosen option: Option 1 - Tenant ID as a new property of the CS3 UserId
|
|
|
|
As part of the OIDC Connect Authentication OpenCloud will receive a tenant id via the
|
|
Access Token or Userinfo endpoint. For the initial implementation it is assume that OpenCloud
|
|
has read access to a shared LDAP server, that contains all users of all tenants. Users in
|
|
LDAP will have a the tenant id as an dedicated attribute.
|
|
|
|
### Implementation Steps
|
|
|
|
* Extend the CS3 UserId with a new property "tenantId"
|
|
* Adapt the `users` service` to only return users that are part of the same tenant
|
|
* To cleanup technical debt and reduce code duplication the `cs3` users backend in the
|
|
graph service is being improved so that is can fully replace the `LDAP` users backend for
|
|
read operations.
|
|
* The reva `share-provider` service only allow shares between users of the same tenant
|
|
|