diff --git a/_includes/code/python/howto.configure.rbac.permissions.py b/_includes/code/python/howto.configure.rbac.permissions.py index baeab65d3..383cf4101 100644 --- a/_includes/code/python/howto.configure.rbac.permissions.py +++ b/_includes/code/python/howto.configure.rbac.permissions.py @@ -11,7 +11,7 @@ # Use custom port defined in tests/docker-compose-rbac.yml (without showing the user) port=8580, grpc_port=50551, - auth_credentials=Auth.api_key("admin-key") + auth_credentials=Auth.api_key("user-a-key") ) def reset_user(user: str, client: WeaviateClient): @@ -25,7 +25,7 @@ def reset_user(user: str, client: WeaviateClient): # ================================================================= # Clean slate -reset_user("other-user", client=admin_client) +reset_user("user-c", client=admin_client) admin_client.roles.delete("rw_role_target_collections") # delete if exists # START ReadWritePermissionDefinition @@ -52,11 +52,11 @@ def reset_user(user: str, client: WeaviateClient): # Create a new role and assign it to a user admin_client.roles.create(role_name="rw_role_target_collections", permissions=admin_permissions) -admin_client.roles.assign_to_user(role_names="rw_role_target_collections", user="other-user") +admin_client.roles.assign_to_user(role_names="rw_role_target_collections", user="user-c") # END ReadWritePermissionDefinition # ===== TEST ===== basic checks to see if the role was created -user_permissions = admin_client.roles.by_user("other-user") +user_permissions = admin_client.roles.by_user("user-c") assert "rw_role_target_collections" in user_permissions.keys() assert user_permissions["rw_role_target_collections"].collections_permissions[0].collection == "TargetCollection_*" @@ -67,7 +67,7 @@ def reset_user(user: str, client: WeaviateClient): # ================================================================= # Clean slate -reset_user("other-user", client=admin_client) +reset_user("user-c", client=admin_client) admin_client.roles.delete("viewer_role_target_collections") # delete if exists # START ViewerPermissionDefinition @@ -82,11 +82,41 @@ def reset_user(user: str, client: WeaviateClient): # Create a new role and assign it to a user admin_client.roles.create(role_name="viewer_role_target_collections", permissions=viewer_permissions) -admin_client.roles.assign_to_user(role_names="viewer_role_target_collections", user="other-user") +admin_client.roles.assign_to_user(role_names="viewer_role_target_collections", user="user-c") # END ViewerPermissionDefinition +# Clean slate - delete `tenant_manager` role if exists +admin_client.roles.delete("tenant_manager") + +# START MTPermissionsExample +permissions = [ + Permissions.collections( + collection="TargetCollection_*", + create_collection=True, + read_config=True, + update_config=True, + delete_collection=True + ), + # Without the below permission, the user would not + # be able to create tenants in collections starting with "TargetCollection_" + Permissions.tenants( + collection="TargetCollection_*", + create=True, + read=True, + update=True, + delete=False + ) +] + +admin_client.roles.create( + role_name="tenant_manager", permissions=permissions +) + +admin_client.roles.assign_to_user(role_names="tenant_manager", user="user-c") +# END MTPermissionsExample + # ===== TEST ===== basic checks to see if the role was created -user_permissions = admin_client.roles.by_user("other-user") +user_permissions = admin_client.roles.by_user("user-c") assert "viewer_role_target_collections" in user_permissions.keys() assert user_permissions["viewer_role_target_collections"].collections_permissions[0].collection == "TargetCollection_*" diff --git a/_includes/code/python/howto.configure.rbac.roles.py b/_includes/code/python/howto.configure.rbac.roles.py index fc2df06eb..d092aa5f4 100644 --- a/_includes/code/python/howto.configure.rbac.roles.py +++ b/_includes/code/python/howto.configure.rbac.roles.py @@ -11,14 +11,17 @@ port=8580, grpc_port=50551, # START AdminClient - auth_credentials=Auth.api_key("admin-key") + auth_credentials=Auth.api_key("user-a-key") ) # END AdminClient -jane_client = weaviate.connect_to_local( - port=8580, grpc_port=50551, auth_credentials=Auth.api_key("jane-key") +custom_user_client = weaviate.connect_to_local( + port=8580, grpc_port=50551, auth_credentials=Auth.api_key("user-c-key") ) +admin_client.roles.delete("devrel") +admin_client.roles.delete("devrel-admin") + # # START CreateRole # admin_client.roles.create(role_name="devrel") # # END CreateRole @@ -82,16 +85,16 @@ # START AssignRole -admin_client.roles.assign_to_user(role_names="devrel", user="jane-doe") +admin_client.roles.assign_to_user(role_names="devrel", user="user-c") # END AssignRole -assert "devrel" in admin_client.roles.by_user(user="jane-doe") +assert "devrel" in admin_client.roles.by_user(user="user-c") # START ListCurrentUserRoles print(admin_client.roles.of_current_user()) # END ListCurrentUserRoles # START ListUserRoles -user_roles = admin_client.roles.by_user(user="jane-doe") +user_roles = admin_client.roles.by_user(user="user-c") for role in user_roles: print(role) @@ -112,7 +115,7 @@ for user in assigned_users: print(user) # END AssignedUsers -assert "jane-doe" in assigned_users +assert "user-c" in assigned_users # START ListAllRoles all_roles = admin_client.roles.list_all() @@ -140,13 +143,13 @@ # END RemovePermissions # START RevokeRoles -admin_client.roles.revoke_from_user(role_names=["devrel"], user="jane-doe") +admin_client.roles.revoke_from_user(role_names=["devrel"], user="user-c") # END RevokeRoles -assert "devrel" not in admin_client.roles.by_user(user="jane-doe") +assert "devrel" not in admin_client.roles.by_user(user="user-c") # START DeleteRole admin_client.roles.delete(role_name="devrel") # END DeleteRole admin_client.close() -jane_client.close() +custom_user_client.close() diff --git a/developers/weaviate/configuration/authentication.md b/developers/weaviate/configuration/authentication.md index f123ab435..6a6788650 100644 --- a/developers/weaviate/configuration/authentication.md +++ b/developers/weaviate/configuration/authentication.md @@ -97,10 +97,10 @@ services: AUTHENTICATION_APIKEY_ENABLED: 'true' # List one or more keys in plaintext separated by commas. Each key corresponds to a specific user identity below. - AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'viewer-key,admin-key' + AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'user-a-key,user-b-key' # List one or more user identities, separated by commas. Each identity corresponds to a specific key above. - AUTHENTICATION_APIKEY_USERS: 'viewer-user,admin-user' + AUTHENTICATION_APIKEY_USERS: 'user-a,user-b' ``` This configuration: @@ -127,13 +127,13 @@ authentication: # List one or more keys in plaintext separated by commas. Each key corresponds to a specific user identity below. allowed_keys: - - admin-key - - viewer-key + - user-a-key + - user-b-key # List one or more user identities, separated by commas. Each identity corresponds to a specific key above. users: - - admin-user - - viewer-user + - user-a + - user-b ``` This configuration: diff --git a/developers/weaviate/configuration/authorization.md b/developers/weaviate/configuration/authorization.md index 962eaa661..7366f8856 100644 --- a/developers/weaviate/configuration/authorization.md +++ b/developers/weaviate/configuration/authorization.md @@ -135,8 +135,8 @@ services: # OIDC access can also be used with RBAC AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'false' AUTHENTICATION_APIKEY_ENABLED: 'true' - AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'viewer-key,admin-key,other-key' - AUTHENTICATION_APIKEY_USERS: 'viewer-user,admin-user,other-user' + AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'user-a-key,user-b-key,user-c-key' + AUTHENTICATION_APIKEY_USERS: 'user-a,user-b,user-c' # Authorization configuration # Enable RBAC @@ -146,17 +146,17 @@ services: # This assumes that the relevant user has been authenticated and identified # # You MUST define at least one admin user - AUTHORIZATION_ADMIN_USERS: 'admin-user' - AUTHORIZATION_VIEWER_USERS: 'viewer-user' + AUTHORIZATION_ADMIN_USERS: 'user-a' + AUTHORIZATION_VIEWER_USERS: 'user-b' ``` This configuration: - Enables RBAC -- Configures `admin-user` as a user with built-in admin permissions -- Configures `viewer-user` as a user with built-in viewer permissions -- Configures `other-user` as a user with no built-in permissions +- Configures `user-a` as a user with built-in admin permissions +- Configures `user-b` as a user with built-in viewer permissions +- Configures `user-c` as a user with no built-in permissions -The `other-user` can now be assigned custom roles and permissions using the [RBAC Roles API](./roles.md). +The `user-c` can now be assigned custom roles and permissions using the [RBAC Roles API](./roles.md). ### RBAC: Kubernetes @@ -170,13 +170,13 @@ authentication: apikey: enabled: true allowed_keys: - - admin-key - - viewer-key - - other-key + - user-a-key + - user-b-key + - user-c-key users: - - admin-user - - viewer-user - - other-user + - user-a + - user-b + - user-c # Authorization configuration authorization: @@ -188,18 +188,18 @@ authorization: # # You MUST define at least one admin user admins: - - admin-user + - user-a viewers: - - viewer-user + - user-b ``` This configuration: - Enables RBAC -- Configures `admin-user` as a user with built-in admin permissions -- Configures `viewer-user` as a user with built-in viewer permissions -- Configures `other-user` as a user with no built-in permissions +- Configures `user-a` as a user with built-in admin permissions +- Configures `user-b` as a user with built-in viewer permissions +- Configures `user-c` as a user with no built-in permissions -The `other-user` can now be assigned custom roles and permissions using the [RBAC Roles API](./roles.md). +The `user-c` can now be assigned custom roles and permissions using the [RBAC Roles API](./roles.md). ## Admin list @@ -223,8 +223,8 @@ services: # OIDC access can also be used with RBAC AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'false' AUTHENTICATION_APIKEY_ENABLED: 'true' - AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'viewer-key,admin-key,other-key' - AUTHENTICATION_APIKEY_USERS: 'viewer-user,admin-user,other-user' + AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'user-a-key,user-b-key,user-c-key' + AUTHENTICATION_APIKEY_USERS: 'user-a,user-b,user-c' # Authorization configuration # Enable admin list @@ -234,16 +234,16 @@ services: # This assumes that the relevant user has been authenticated and identified # # You MUST define at least one admin user - AUTHORIZATION_ADMINLIST_USERS: 'admin-user' - AUTHORIZATION_ADMINLIST_READONLY_USERS: 'viewer-user' + AUTHORIZATION_ADMINLIST_USERS: 'user-a' + AUTHORIZATION_ADMINLIST_READONLY_USERS: 'user-b' ``` This configuration: - Enables Admin list authorization -- Configures `admin-user` as a user with built-in admin permissions -- Configures `viewer-user` as a user with built-in viewer permissions +- Configures `user-a` as a user with built-in admin permissions +- Configures `user-b` as a user with built-in viewer permissions -Note that in this configuration, `other-user` has no permissions. +Note that in this configuration, `user-c` has no permissions. ### Admin list: Kubernetes @@ -257,13 +257,13 @@ authentication: apikey: enabled: true allowed_keys: - - admin-key - - viewer-key - - other-key + - user-a-key + - user-b-key + - user-c-key users: - - admin-user - - viewer-user - - other-user + - user-a + - user-b + - user-c # Authorization configuration authorization: @@ -276,9 +276,9 @@ authorization: # # You MUST define at least one admin user users: - - admin-user + - user-a read_only_users: - - viewer-user + - user-b ``` ### Anonymous users @@ -305,11 +305,11 @@ services: # Configure admin user API key AUTHORIZATION_ADMINLIST_ENABLED: 'true' - AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'admin-key' - AUTHENTICATION_APIKEY_USERS: 'admin-user' + AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'user-a-key' + AUTHENTICATION_APIKEY_USERS: 'user-a' - # Enable admin list and provide admin access to "admin-user" only - AUTHORIZATION_ADMINLIST_USERS: 'admin-user' + # Enable admin list and provide admin access to "user-a" only + AUTHORIZATION_ADMINLIST_USERS: 'user-a' # Provide read-only access to anonymous users AUTHORIZATION_ADMINLIST_READONLY_USERS: 'anonymous' ``` @@ -329,17 +329,17 @@ authentication: apikey: enabled: true allowed_keys: - - admin-key + - user-a-key users: - - admin-user + - user-a authorization: - # Enable admin list and provide admin access to "admin-user" only + # Enable admin list and provide admin access to "user-a" only admin_list: # Enable admin list enabled: true users: - - admin-user + - user-a # Provide read-only access to anonymous users read_only_users: - anonymous diff --git a/developers/weaviate/configuration/roles.md b/developers/weaviate/configuration/roles.md index 57ec52e8b..af6b88006 100644 --- a/developers/weaviate/configuration/roles.md +++ b/developers/weaviate/configuration/roles.md @@ -69,6 +69,9 @@ Permissions can be defined for the following resources: 1. **Collections** (collection definitions only, data object permissions are separate) - Create, read, update, and delete collection definitions +1. **Tenants** ([available from `v1.28.3`](#collection-and-tenant-permissions)) + - Create, read, update, and delete tenants + 1. **Data Objects** - Read, write, update, and delete objects @@ -109,6 +112,18 @@ Many permissions require a collection name filter, to specify which collections In thi case, `"*"` acts as a multi-character wildcard. As an example, setting a permission with `"Test_*"` as the collection filter would apply that permission to all collections that start with `Test_`. Or, setting a permission with `"*"` as the collection filter would apply that permission to all available collections. +### Collection and tenant permissions + +:::caution Breaking change introduced in `v1.28.3` +This change was introduced in `v1.28.3` during the technical preview phase. In `v1.28.0` - `v1.28.2`, a collection level permission would cascade to confer permissions the equivalent tenant-level operations. This behavior was changed in `v1.28.3` to require explicit tenant-level permissions for tenant operations, for operations such as creating a tenant, updating tenant status, and so on. +::: + +A collection permission is independent of tenant permissions. + +To have permissions to operate on a tenant that belongs to a collection, the user must have the appropriate tenant-level permissions for that collection. Collection-level permissions, such as that to create collections, do not confer the equivalent tenant-level permissions, such as that to create tenants for that collection. + +For example, to create a tenant in a collection called "Test_Collection", the user must have permission to "create" tenants in that collection. This is separate from the permission to create a collection called "Test_Collection". + ## Example permission sets ### Read and write permissions @@ -193,6 +208,47 @@ This confers viewer permissions for collections starting with `TargetCollection_ +### Example tenant permissions + +This confers permissions to manage collections starting with `TargetCollection_`, and to create, read, and update tenants in the same collection. + + + + + + + + + +```ts +// TS support coming soon +``` + + + + + +```go +// Go support coming soon +``` + + + + + +```java +// Java support coming soon +``` + + + + + import RolePyCode from '!!raw-loader!/_includes/code/python/howto.configure.rbac.roles.py'; ## Role management @@ -419,7 +475,7 @@ This example removes from the "devrel" role permissions to: A custom user can have any number of roles assigned to them (including none). The role can be a predefined role (e.g. `viewer`) or a custom role. -This example assigns the custom "devrel" role to "jane-doe". +This example assigns the custom "devrel" role to "user-c". @@ -745,7 +801,7 @@ Deleting a role will remove it from the system, and revoke the associated permis You can revoke one or more roles from a specific user. -This examples revokes "role-1" and "role-2" from the user "jane-doe". +This examples revokes "role-1" and "role-2" from the user "user-c". diff --git a/tests/docker-compose-anon-2.yml b/tests/docker-compose-anon-2.yml index 1a078ed14..880af62e7 100644 --- a/tests/docker-compose-anon-2.yml +++ b/tests/docker-compose-anon-2.yml @@ -8,7 +8,7 @@ services: - '8080' - --scheme - http - image: cr.weaviate.io/semitechnologies/weaviate:1.28.2 + image: cr.weaviate.io/semitechnologies/weaviate:1.28.3 ports: - 8090:8080 - 50061:50051 diff --git a/tests/docker-compose-anon-bind.yml b/tests/docker-compose-anon-bind.yml index 318a51f27..a9f8e3eea 100644 --- a/tests/docker-compose-anon-bind.yml +++ b/tests/docker-compose-anon-bind.yml @@ -8,7 +8,7 @@ services: - '8080' - --scheme - http - image: cr.weaviate.io/semitechnologies/weaviate:1.28.2 + image: cr.weaviate.io/semitechnologies/weaviate:1.28.3 ports: - 8380:8080 - 50351:50051 diff --git a/tests/docker-compose-anon-clip.yml b/tests/docker-compose-anon-clip.yml index bac2cfe8d..fb0224132 100644 --- a/tests/docker-compose-anon-clip.yml +++ b/tests/docker-compose-anon-clip.yml @@ -8,7 +8,7 @@ services: - '8080' - --scheme - http - image: cr.weaviate.io/semitechnologies/weaviate:1.28.2 + image: cr.weaviate.io/semitechnologies/weaviate:1.28.3 ports: - 8280:8080 - 50251:50051 diff --git a/tests/docker-compose-anon-offload.yml b/tests/docker-compose-anon-offload.yml index aee4d7bd7..f4d07b370 100644 --- a/tests/docker-compose-anon-offload.yml +++ b/tests/docker-compose-anon-offload.yml @@ -8,7 +8,7 @@ services: - '8080' - --scheme - http - image: cr.weaviate.io/semitechnologies/weaviate:1.28.2 + image: cr.weaviate.io/semitechnologies/weaviate:1.28.3 ports: - 8080:8080 - 50051:50051 diff --git a/tests/docker-compose-anon.yml b/tests/docker-compose-anon.yml index 70ca842eb..ac907a49b 100644 --- a/tests/docker-compose-anon.yml +++ b/tests/docker-compose-anon.yml @@ -8,7 +8,7 @@ services: - '8080' - --scheme - http - image: cr.weaviate.io/semitechnologies/weaviate:1.28.2 + image: cr.weaviate.io/semitechnologies/weaviate:1.28.3 ports: - 8080:8080 - 50051:50051 diff --git a/tests/docker-compose-rbac.yml b/tests/docker-compose-rbac.yml index 48f5966b1..26b523e23 100644 --- a/tests/docker-compose-rbac.yml +++ b/tests/docker-compose-rbac.yml @@ -8,7 +8,7 @@ services: - '8080' - --scheme - http - image: cr.weaviate.io/semitechnologies/weaviate:1.28.2 + image: cr.weaviate.io/semitechnologies/weaviate:1.28.3 ports: - 8580:8080 - 50551:50051 @@ -24,9 +24,9 @@ services: # AuthN and AuthZ settings AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'false' AUTHENTICATION_APIKEY_ENABLED: 'true' - AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'viewer-key,admin-key,other-user,jane-key' - AUTHENTICATION_APIKEY_USERS: 'viewer-user,admin-user,other-user,jane-doe' + AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'user-a-key,user-b-key,user-c-key' + AUTHENTICATION_APIKEY_USERS: 'user-a,user-b,user-c' AUTHORIZATION_ENABLE_RBAC: 'true' - AUTHORIZATION_ADMIN_USERS: 'admin-user' - AUTHORIZATION_VIEWER_USERS: 'viewer-user' + AUTHORIZATION_ADMIN_USERS: 'user-a' + AUTHORIZATION_VIEWER_USERS: 'user-b' ... diff --git a/tests/docker-compose-three-nodes.yml b/tests/docker-compose-three-nodes.yml index c6f775aa5..3e1742c00 100644 --- a/tests/docker-compose-three-nodes.yml +++ b/tests/docker-compose-three-nodes.yml @@ -8,7 +8,7 @@ services: - '8080' - --scheme - http - image: cr.weaviate.io/semitechnologies/weaviate:1.28.2 + image: cr.weaviate.io/semitechnologies/weaviate:1.28.3 restart: on-failure:0 ports: - "8180:8080" @@ -36,7 +36,7 @@ services: - '8080' - --scheme - http - image: cr.weaviate.io/semitechnologies/weaviate:1.28.2 + image: cr.weaviate.io/semitechnologies/weaviate:1.28.3 restart: on-failure:0 ports: - "8181:8080" @@ -65,7 +65,7 @@ services: - '8080' - --scheme - http - image: cr.weaviate.io/semitechnologies/weaviate:1.28.2 + image: cr.weaviate.io/semitechnologies/weaviate:1.28.3 restart: on-failure:0 ports: - "8182:8080" diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index 6c33db38c..532961cbf 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -8,7 +8,7 @@ services: - '8080' - --scheme - http - image: cr.weaviate.io/semitechnologies/weaviate:1.28.2 + image: cr.weaviate.io/semitechnologies/weaviate:1.28.3 ports: - 8099:8080 - 50052:50051