milvus-io / milvus

A cloud-native vector database, storage for next generation AI applications
https://milvus.io
Apache License 2.0
31.05k stars 2.95k forks source link

[Bug]: Grant load privilege to a role does not take effect #27775

Closed StormstoutY closed 1 year ago

StormstoutY commented 1 year ago

Is there an existing issue for this?

Environment

- Milvus version: v2.3.1
- Deployment mode(standalone or cluster):
- MQ type(rocksmq, pulsar or kafka):    
- SDK version(e.g. pymilvus v2.0.0rc2):pymilvus v2.3.0
- OS(Ubuntu or CentOS): 
- CPU/Memory: 
- GPU: 
- Others:

Current Behavior

I created a role and granted a collection's Load, Insert, Query, and Search privileges. Insert, Query, and Search can take effect, but Load never takes effect.

Here is my code and result:

>>> connections.connect(db_name="default", host=HOST, port=PORT, user="root", password=pwd)

### create a new role
>>> role_name = "testRoleA"
>>> role = Role(role_name)
>>> role.create()

### ist all roles 
>>> print(utility.list_roles(True))
RoleInfo groups:
- RoleItem: <role_name:admin>, <users:()>
- RoleItem: <role_name:public>, <users:()>
- RoleItem: <role_name:testRoleA>, <users:()>

>>> role.grant("Collection", "test2", "Load")
>>> role.grant("Collection", "test2", "Insert")
>>> role.grant("Collection", "test2", "Search")
>>> role.grant("Collection", "test2", "Query")
>>> print(role.list_grants())
GrantInfo groups:
- GrantItem: <object:Collection>, <object_name:test2>, <db_name:default>, <role_name:testRoleA>, <grantor_name:root>, <privilege:Insert>
- GrantItem: <object:Collection>, <object_name:test2>, <db_name:default>, <role_name:testRoleA>, <grantor_name:root>, <privilege:Load>
- GrantItem: <object:Collection>, <object_name:test2>, <db_name:default>, <role_name:testRoleA>, <grantor_name:root>, <privilege:Query>
- GrantItem: <object:Collection>, <object_name:test2>, <db_name:default>, <role_name:testRoleA>, <grantor_name:root>, <privilege:Search>

### bind a role to a user
>>> role_name = "testRoleA"
>>> role = Role(role_name)
>>> role.add_user("test1")
>>> print(role.get_users())
('test1',)

### test RBAC
>>> connections.connect(alias="test1", host=HOST, port=PORT, user="test1", password="test123")
>>> test2 = Collection("test2", using="test1")
>>> test2.load()
...
grpc._channel._MultiThreadedRendezvous: <_MultiThreadedRendezvous of RPC that terminated with:
        status = StatusCode.PERMISSION_DENIED
        details = "PrivilegeGetLoadingProgress: permission deny"
        debug_error_string = "UNKNOWN:Error received from peer ipv4:10.137.40.140:27027 {created_time:"2023-10-18T20:09:28.523136332+08:00", grpc_status:7, grpc_message:"PrivilegeGetLoadingProgress: permission deny"}

When I use user test1 to perform insert, query, search, etc. operations on collection test2, it can be executed normally.

>>> res = test2.query(expr="pk > 0", limit=2, output_fields=["text"])
>>> print(res)
[{'text': 'the text is just for test: 83', 'pk': 445018386610533734}, {'text': 'the text is just for test: 80', 'pk': 445018386610533735}]

Expected Behavior

No response

Steps To Reproduce

No response

Milvus Log

No response

Anything else?

No response

yanliang567 commented 1 year ago

/assign @NicoYuan1986 can we reproduce it in house? /unassign

NicoYuan1986 commented 1 year ago

Reproduced in house. milvus: master-20231019-635efdf1 pymilvus: 2.3.1.post1.dev11

And it is strange that the collection can be queried without load.

from pymilvus import CollectionSchema, FieldSchema, Collection, connections, DataType, utility
from pymilvus.orm.role import Role

connections.connect(alias="default", host=HOST, port=PORT, user="root", password=pwd)

# create a new role
role_name = "testRoleA"
role = Role(role_name)
role.create()

# list all roles
print(utility.list_roles(True))

role.grant("Global", "test2", "CreateCollection")
role.grant("Collection", "test2", "CreateIndex")
role.grant("Collection", "test2", "Load")
role.grant("Collection", "test2", "Insert")
role.grant("Collection", "test2", "Search")
role.grant("Collection", "test2", "Query")
print(role.list_grants())

# bind a role to a user
role = Role(role_name)
utility.create_user("test1", "test123")
role.add_user("test1")
print(role.get_users())

# test RBAC
connections.connect(alias="test1", host=HOST, port=PORT, user="test1", password="test123")
fields = [FieldSchema(name="pk", dtype=DataType.INT64, is_primary=True),
          FieldSchema(name="float_vector", dtype=DataType.FLOAT_VECTOR, dim=8)]
schema = CollectionSchema(fields=fields)
test2 = Collection("test2", schema=schema, using="test1")
test2.create_index("float_vector")
test2.load()

test2.query("", limit=1)

error:

>>> test2.load()
grpc RpcError: [get_loading_progress], <_MultiThreadedRendezvous: StatusCode.PERMISSION_DENIED, PrivilegeGetLoadingProgress: permission deny>, <Time:{'RPC start': '2023-10-19 17:02:10.886439', 'gRPC error': '2023-10-19 17:02:10.903707'}>
grpc RpcError: [wait_for_loading_collection], <_MultiThreadedRendezvous: StatusCode.PERMISSION_DENIED, PrivilegeGetLoadingProgress: permission deny>, <Time:{'RPC start': '2023-10-19 17:02:10.886323', 'gRPC error': '2023-10-19 17:02:10.904280'}>
grpc RpcError: [load_collection], <_MultiThreadedRendezvous: StatusCode.PERMISSION_DENIED, PrivilegeGetLoadingProgress: permission deny>, <Time:{'RPC start': '2023-10-19 17:02:10.856848', 'gRPC error': '2023-10-19 17:02:10.904428'}>
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/orm/collection.py", line 420, in load
    conn.load_collection(
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 143, in handler
    raise e from e
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 125, in handler
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 164, in handler
    return func(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 79, in handler
    raise e from e
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 68, in handler
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/client/grpc_handler.py", line 1028, in load_collection
    self.wait_for_loading_collection(collection_name, timeout, is_refresh=_refresh)
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 143, in handler
    raise e from e
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 125, in handler
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 164, in handler
    return func(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 79, in handler
    raise e from e
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 68, in handler
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/client/grpc_handler.py", line 1048, in wait_for_loading_collection
    progress = self.get_loading_progress(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 143, in handler
    raise e from e
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 125, in handler
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 164, in handler
    return func(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 79, in handler
    raise e from e
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/decorators.py", line 68, in handler
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/pymilvus/client/grpc_handler.py", line 1147, in get_loading_progress
    response = self._stub.GetLoadingProgress.future(request, timeout=timeout).result()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/grpc/_channel.py", line 881, in result
    raise self
grpc._channel._MultiThreadedRendezvous: <_MultiThreadedRendezvous of RPC that terminated with:
    status = StatusCode.PERMISSION_DENIED
    details = "PrivilegeGetLoadingProgress: permission deny"
    debug_error_string = "UNKNOWN:Error received from peer  {created_time:"2023-10-19T17:02:10.902505+08:00", grpc_status:7, grpc_message:"PrivilegeGetLoadingProgress: permission deny"}"

>>> test2.query("", limit=1)
[]

/assign @SimFG Can you help look into this issue? /unassign

SimFG commented 1 year ago

@StormstoutY @NicoYuan1986 need grant the GetLoadingProgress privilege. Because load in python sdk is a synchronous operation by default, the GetLoadingProgress interface is used.

role.grant("Collection", "test2", "GetLoadingProgress")
NicoYuan1986 commented 1 year ago

@StormstoutY @NicoYuan1986 need grant the GetLoadingProgress privilege. Because load in python sdk is a synchronous operation by default, the GetLoadingProgress interface is used.

role.grant("Collection", "test2", "GetLoadingProgress")

But I can query on the unloaded collection, do you know the reason?

xiaofan-luan commented 1 year ago

@StormstoutY @NicoYuan1986 need grant the GetLoadingProgress privilege. Because load in python sdk is a synchronous operation by default, the GetLoadingProgress interface is used.

role.grant("Collection", "test2", "GetLoadingProgress")

maybe we should change GetLoadingProgress to load too?

@SimFG Doesn't make sense if one has load access but not GetLoadingProgress

xiaofan-luan commented 1 year ago

@StormstoutY @NicoYuan1986 need grant the GetLoadingProgress privilege. Because load in python sdk is a synchronous operation by default, the GetLoadingProgress interface is used.

role.grant("Collection", "test2", "GetLoadingProgress")

But I can query on the unloaded collection, do you know the reason?

This makes sense because load already succeed. SImply becasue get Load progress don't have access

SimFG commented 1 year ago

/close

sre-ci-robot commented 1 year ago

@SimFG: Closing this issue.

In response to [this](https://github.com/milvus-io/milvus/issues/27775#issuecomment-1803047236): >/close Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md). If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.