From 9c2369a992eaae562bbb7c0ac2bc283804b783bd Mon Sep 17 00:00:00 2001 From: shaoting-huang Date: Tue, 24 Dec 2024 12:10:23 +0800 Subject: [PATCH] fix privilege group list and list collections Signed-off-by: shaoting-huang --- client/milvusclient/rbac_test.go | 16 +- configs/milvus.yaml | 2 +- internal/proxy/privilege_interceptor_test.go | 6 +- internal/rootcoord/root_coord.go | 59 +----- internal/rootcoord/root_coord_test.go | 23 --- internal/rootcoord/show_collection_task.go | 7 +- .../rootcoord/show_collection_task_test.go | 51 ++++++ pkg/util/constant.go | 95 ---------- pkg/util/paramtable/rbac_config_test.go | 41 +++-- pkg/util/paramtable/rbac_param.go | 171 +++++++++++++++++- .../integration/rbac/privilege_group_test.go | 6 +- 11 files changed, 265 insertions(+), 212 deletions(-) diff --git a/client/milvusclient/rbac_test.go b/client/milvusclient/rbac_test.go index f5d0429b6595e..76717ca615180 100644 --- a/client/milvusclient/rbac_test.go +++ b/client/milvusclient/rbac_test.go @@ -399,11 +399,11 @@ func TestRoleRBAC(t *testing.T) { suite.Run(t, new(RoleSuite)) } -type PrivilgeGroupSuite struct { +type PrivilegeGroupSuite struct { MockSuiteBase } -func (s *PrivilgeGroupSuite) TestGrantV2() { +func (s *PrivilegeGroupSuite) TestGrantV2() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -433,7 +433,7 @@ func (s *PrivilgeGroupSuite) TestGrantV2() { }) } -func (s *PrivilgeGroupSuite) TestRevokeV2() { +func (s *PrivilegeGroupSuite) TestRevokeV2() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -463,7 +463,7 @@ func (s *PrivilgeGroupSuite) TestRevokeV2() { }) } -func (s *PrivilgeGroupSuite) TestCreatePrivilegeGroup() { +func (s *PrivilegeGroupSuite) TestCreatePrivilegeGroup() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -487,7 +487,7 @@ func (s *PrivilgeGroupSuite) TestCreatePrivilegeGroup() { }) } -func (s *PrivilgeGroupSuite) TestDropPrivilegeGroup() { +func (s *PrivilegeGroupSuite) TestDropPrivilegeGroup() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -511,7 +511,7 @@ func (s *PrivilgeGroupSuite) TestDropPrivilegeGroup() { }) } -func (s *PrivilgeGroupSuite) TestListPrivilegeGroups() { +func (s *PrivilegeGroupSuite) TestListPrivilegeGroups() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -548,7 +548,7 @@ func (s *PrivilgeGroupSuite) TestListPrivilegeGroups() { }) } -func (s *PrivilgeGroupSuite) TestOperatePrivilegeGroup() { +func (s *PrivilegeGroupSuite) TestOperatePrivilegeGroup() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -575,5 +575,5 @@ func (s *PrivilgeGroupSuite) TestOperatePrivilegeGroup() { } func TestPrivilegeGroup(t *testing.T) { - suite.Run(t, new(PrivilgeGroupSuite)) + suite.Run(t, new(PrivilegeGroupSuite)) } diff --git a/configs/milvus.yaml b/configs/milvus.yaml index e508238fbeb2d..67221cf5fe8b1 100644 --- a/configs/milvus.yaml +++ b/configs/milvus.yaml @@ -827,7 +827,7 @@ common: superUsers: defaultRootPassword: "Milvus" # default password for root user. The maximum length is 72 characters, and double quotes are required. rbac: - overrideBuiltInPrivilgeGroups: + overrideBuiltInPrivilegeGroups: enabled: false # Whether to override build-in privilege groups cluster: readonly: diff --git a/internal/proxy/privilege_interceptor_test.go b/internal/proxy/privilege_interceptor_test.go index e8093e0985d7b..fd1aef75da32a 100644 --- a/internal/proxy/privilege_interceptor_test.go +++ b/internal/proxy/privilege_interceptor_test.go @@ -576,9 +576,9 @@ func TestBuiltinPrivilegeGroup(t *testing.T) { mgr := newShardClientMgr() policies := []string{} - for _, priv := range util.BuiltinPrivilegeGroups["ClusterReadOnly"] { - objectType := util.GetObjectType(priv) - policies = append(policies, funcutil.PolicyForPrivilege("role1", objectType, "*", util.PrivilegeNameForMetastore(priv), "default")) + for _, priv := range Params.RbacConfig.GetDefaultPrivilegeGroup("ClusterReadOnly").Privileges { + objectType := util.GetObjectType(priv.Name) + policies = append(policies, funcutil.PolicyForPrivilege("role1", objectType, "*", util.PrivilegeNameForMetastore(priv.Name), "default")) } client.listPolicy = func(ctx context.Context, in *internalpb.ListPolicyRequest) (*internalpb.ListPolicyResponse, error) { return &internalpb.ListPolicyResponse{ diff --git a/internal/rootcoord/root_coord.go b/internal/rootcoord/root_coord.go index 914b0cee142e8..c36a046dd8e48 100644 --- a/internal/rootcoord/root_coord.go +++ b/internal/rootcoord/root_coord.go @@ -638,50 +638,6 @@ func (c *Core) initPublicRolePrivilege() error { return nil } -func (c *Core) initBuiltinPrivilegeGroups() []*milvuspb.PrivilegeGroupInfo { - // init built in privilege groups, override by config if rbac config enabled - builtinGroups := make([]*milvuspb.PrivilegeGroupInfo, 0) - for groupName, privileges := range util.BuiltinPrivilegeGroups { - if Params.RbacConfig.Enabled.GetAsBool() { - var confPrivs []string - switch groupName { - case "ClusterReadOnly": - confPrivs = Params.RbacConfig.ClusterReadOnlyPrivileges.GetAsStrings() - case "ClusterReadWrite": - confPrivs = Params.RbacConfig.ClusterReadWritePrivileges.GetAsStrings() - case "ClusterAdmin": - confPrivs = Params.RbacConfig.ClusterAdminPrivileges.GetAsStrings() - case "DatabaseReadOnly": - confPrivs = Params.RbacConfig.DBReadOnlyPrivileges.GetAsStrings() - case "DatabaseReadWrite": - confPrivs = Params.RbacConfig.DBReadWritePrivileges.GetAsStrings() - case "DatabaseAdmin": - confPrivs = Params.RbacConfig.DBAdminPrivileges.GetAsStrings() - case "CollectionReadOnly": - confPrivs = Params.RbacConfig.CollectionReadOnlyPrivileges.GetAsStrings() - case "CollectionReadWrite": - confPrivs = Params.RbacConfig.CollectionReadWritePrivileges.GetAsStrings() - case "CollectionAdmin": - confPrivs = Params.RbacConfig.CollectionAdminPrivileges.GetAsStrings() - default: - return nil - } - if len(confPrivs) > 0 { - privileges = confPrivs - } - } - - privs := lo.Map(privileges, func(name string, _ int) *milvuspb.PrivilegeEntity { - return &milvuspb.PrivilegeEntity{Name: name} - }) - builtinGroups = append(builtinGroups, &milvuspb.PrivilegeGroupInfo{ - GroupName: groupName, - Privileges: privs, - }) - } - return builtinGroups -} - func (c *Core) initBuiltinRoles() error { log := log.Ctx(c.ctx) rolePrivilegesMap := Params.RoleCfg.Roles.GetAsRoleDetails() @@ -2648,7 +2604,7 @@ func (c *Core) isValidPrivilege(ctx context.Context, privilegeName string, objec if customPrivGroup { return fmt.Errorf("can not operate the custom privilege group [%s]", privilegeName) } - if lo.Contains(lo.Keys(util.BuiltinPrivilegeGroups), privilegeName) { + if lo.Contains(Params.RbacConfig.GetDefaultPrivilegeGroupNames(), privilegeName) { return fmt.Errorf("can not operate the built-in privilege group [%s]", privilegeName) } // check object privileges for built-in privileges @@ -2757,7 +2713,7 @@ func (c *Core) OperatePrivilege(ctx context.Context, in *milvuspb.OperatePrivile grants := []*milvuspb.GrantEntity{in.Entity} allGroups, err := c.meta.ListPrivilegeGroups(ctx) - allGroups = append(allGroups, c.initBuiltinPrivilegeGroups()...) + allGroups = append(allGroups, Params.RbacConfig.GetDefaultPrivilegeGroups()...) if err != nil { return nil, err } @@ -3243,16 +3199,7 @@ func (c *Core) ListPrivilegeGroups(ctx context.Context, in *milvuspb.ListPrivile metrics.RootCoordDDLReqLatency.WithLabelValues(method).Observe(float64(tr.ElapseSpan().Milliseconds())) // append built in privilege groups - for groupName, privileges := range util.BuiltinPrivilegeGroups { - privGroups = append(privGroups, &milvuspb.PrivilegeGroupInfo{ - GroupName: groupName, - Privileges: lo.Map(privileges, func(p string, _ int) *milvuspb.PrivilegeEntity { - return &milvuspb.PrivilegeEntity{ - Name: p, - } - }), - }) - } + privGroups = append(privGroups, Params.RbacConfig.GetDefaultPrivilegeGroups()...) return &milvuspb.ListPrivilegeGroupsResponse{ Status: merr.Success(), PrivilegeGroups: privGroups, diff --git a/internal/rootcoord/root_coord_test.go b/internal/rootcoord/root_coord_test.go index e6b8c380f4e9b..bf92be38d7102 100644 --- a/internal/rootcoord/root_coord_test.go +++ b/internal/rootcoord/root_coord_test.go @@ -2037,29 +2037,6 @@ func TestCore_InitRBAC(t *testing.T) { err := c.initRbac() assert.NoError(t, err) }) - - t.Run("init default privilege groups", func(t *testing.T) { - clusterReadWrite := `SelectOwnership,SelectUser,DescribeResourceGroup` - meta := mockrootcoord.NewIMetaTable(t) - c := newTestCore(withHealthyCode(), withMeta(meta)) - - Params.Save(Params.RbacConfig.Enabled.Key, "true") - Params.Save(Params.RbacConfig.ClusterReadWritePrivileges.Key, clusterReadWrite) - - defer func() { - Params.Reset(Params.RbacConfig.Enabled.Key) - Params.Reset(Params.RbacConfig.ClusterReadWritePrivileges.Key) - }() - - builtinGroups := c.initBuiltinPrivilegeGroups() - fmt.Println(builtinGroups) - assert.Equal(t, len(util.BuiltinPrivilegeGroups), len(builtinGroups)) - for _, group := range builtinGroups { - if group.GroupName == "ClusterReadWrite" { - assert.Equal(t, len(group.Privileges), 3) - } - } - }) } func TestCore_BackupRBAC(t *testing.T) { diff --git a/internal/rootcoord/show_collection_task.go b/internal/rootcoord/show_collection_task.go index b0f40be928d61..31c268abde57b 100644 --- a/internal/rootcoord/show_collection_task.go +++ b/internal/rootcoord/show_collection_task.go @@ -88,12 +88,15 @@ func (t *showCollectionTask) Execute(ctx context.Context) error { } for _, entity := range entities { objectType := entity.GetObject().GetName() + priv := entity.GetGrantor().GetPrivilege().GetName() if objectType == commonpb.ObjectType_Global.String() && - entity.GetGrantor().GetPrivilege().GetName() == util.PrivilegeNameForAPI(commonpb.ObjectPrivilege_PrivilegeAll.String()) { + priv == util.PrivilegeNameForAPI(commonpb.ObjectPrivilege_PrivilegeAll.String()) { privilegeColls.Insert(util.AnyWord) return privilegeColls, nil } - if objectType != commonpb.ObjectType_Collection.String() { + // should list collection level built-in privilege group objects + if objectType != commonpb.ObjectType_Collection.String() && + !Params.RbacConfig.IsCollectionPrivilegeGroup(priv) { continue } collectionName := entity.GetObjectName() diff --git a/internal/rootcoord/show_collection_task_test.go b/internal/rootcoord/show_collection_task_test.go index 4b8a552de9c2a..ccc7d6bfebe48 100644 --- a/internal/rootcoord/show_collection_task_test.go +++ b/internal/rootcoord/show_collection_task_test.go @@ -325,6 +325,57 @@ func TestShowCollectionsAuth(t *testing.T) { assert.Equal(t, "foo", task.Rsp.GetCollectionNames()[0]) }) + t.Run("collection level privilege group", func(t *testing.T) { + Params.Save(Params.CommonCfg.AuthorizationEnabled.Key, "true") + defer Params.Reset(Params.CommonCfg.AuthorizationEnabled.Key) + meta := mockrootcoord.NewIMetaTable(t) + core := newTestCore(withMeta(meta)) + + meta.EXPECT().SelectUser(mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return([]*milvuspb.UserResult{ + { + User: &milvuspb.UserEntity{ + Name: "foo", + }, + Roles: []*milvuspb.RoleEntity{ + { + Name: "hoooo", + }, + }, + }, + }, nil).Once() + meta.EXPECT().SelectGrant(mock.Anything, mock.Anything, mock.Anything).Return([]*milvuspb.GrantEntity{ + { + Object: &milvuspb.ObjectEntity{Name: commonpb.ObjectType_Global.String()}, + Grantor: &milvuspb.GrantorEntity{ + Privilege: &milvuspb.PrivilegeEntity{ + Name: util.PrivilegeNameForAPI(commonpb.ObjectPrivilege_PrivilegeGroupCollectionReadOnly.String()), + }, + }, + ObjectName: util.AnyWord, + }, + }, nil).Once() + meta.EXPECT().ListCollections(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]*model.Collection{ + { + DBID: 1, + CollectionID: 100, + Name: "foo", + CreateTime: tsoutil.GetCurrentTime(), + }, + }, nil).Once() + + task := &showCollectionTask{ + baseTask: newBaseTask(context.Background(), core), + Req: &milvuspb.ShowCollectionsRequest{DbName: "default"}, + Rsp: &milvuspb.ShowCollectionsResponse{}, + } + ctx := GetContext(context.Background(), "foo:root") + err := task.Execute(ctx) + assert.NoError(t, err) + assert.Equal(t, 1, len(task.Rsp.GetCollectionNames())) + assert.Equal(t, "foo", task.Rsp.GetCollectionNames()[0]) + }) + t.Run("all collection", func(t *testing.T) { Params.Save(Params.CommonCfg.AuthorizationEnabled.Key, "true") defer Params.Reset(Params.CommonCfg.AuthorizationEnabled.Key) diff --git a/pkg/util/constant.go b/pkg/util/constant.go index bef093cf3fef1..d1ca65d396a43 100644 --- a/pkg/util/constant.go +++ b/pkg/util/constant.go @@ -290,101 +290,6 @@ var ( commonpb.ObjectPrivilege_PrivilegeAlterDatabase.String(), commonpb.ObjectPrivilege_PrivilegeFlush.String(), } - - BuiltinPrivilegeGroups = map[string][]string{ - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupCollectionReadOnly.String()): CollectionReadOnlyPrivilegeGroup, - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupCollectionReadWrite.String()): CollectionReadWritePrivilegeGroup, - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupCollectionAdmin.String()): CollectionAdminPrivilegeGroup, - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupDatabaseReadOnly.String()): DatabaseReadOnlyPrivilegeGroup, - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupDatabaseReadWrite.String()): DatabaseReadWritePrivilegeGroup, - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupDatabaseAdmin.String()): DatabaseAdminPrivilegeGroup, - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupClusterReadOnly.String()): ClusterReadOnlyPrivilegeGroup, - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupClusterReadWrite.String()): ClusterReadWritePrivilegeGroup, - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupClusterAdmin.String()): ClusterAdminPrivilegeGroup, - } - - CollectionReadOnlyPrivilegeGroup = []string{ - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeQuery.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeSearch.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeIndexDetail.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGetFlushState.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGetLoadState.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGetLoadingProgress.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeHasPartition.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeShowPartitions.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDescribeCollection.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDescribeAlias.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGetStatistics.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeListAliases.String()), - } - - CollectionReadWritePrivilegeGroup = append(CollectionReadOnlyPrivilegeGroup, - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeLoad.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeRelease.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeInsert.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDelete.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeUpsert.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeImport.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeFlush.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCompaction.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeLoadBalance.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreateIndex.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropIndex.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreatePartition.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropPartition.String()), - ) - - CollectionAdminPrivilegeGroup = append(CollectionReadWritePrivilegeGroup, - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreateAlias.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropAlias.String()), - ) - - DatabaseReadOnlyPrivilegeGroup = []string{ - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeShowCollections.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDescribeDatabase.String()), - } - - DatabaseReadWritePrivilegeGroup = append(DatabaseReadOnlyPrivilegeGroup, - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeAlterDatabase.String()), - ) - - DatabaseAdminPrivilegeGroup = append(DatabaseReadWritePrivilegeGroup, - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreateCollection.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropCollection.String()), - ) - - ClusterReadOnlyPrivilegeGroup = []string{ - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeListDatabases.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeSelectOwnership.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeSelectUser.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDescribeResourceGroup.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeListResourceGroups.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeListPrivilegeGroups.String()), - } - - ClusterReadWritePrivilegeGroup = append(ClusterReadOnlyPrivilegeGroup, - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeFlushAll.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeTransferNode.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeTransferReplica.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeUpdateResourceGroups.String()), - ) - - ClusterAdminPrivilegeGroup = append(ClusterReadWritePrivilegeGroup, - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeBackupRBAC.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeRestoreRBAC.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreateDatabase.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropDatabase.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreateOwnership.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropOwnership.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeManageOwnership.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreateResourceGroup.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropResourceGroup.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeUpdateUser.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeRenameCollection.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreatePrivilegeGroup.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropPrivilegeGroup.String()), - MetaStore2API(commonpb.ObjectPrivilege_PrivilegeOperatePrivilegeGroup.String()), - ) ) // StringSet convert array to map for conveniently check if the array contains an element diff --git a/pkg/util/paramtable/rbac_config_test.go b/pkg/util/paramtable/rbac_config_test.go index 803fceabe2896..9a780bcea435b 100644 --- a/pkg/util/paramtable/rbac_config_test.go +++ b/pkg/util/paramtable/rbac_config_test.go @@ -20,22 +20,41 @@ import ( "testing" "github.com/stretchr/testify/assert" - - "github.com/milvus-io/milvus/pkg/util" ) func TestRbacConfig_Init(t *testing.T) { params := ComponentParam{} params.Init(NewBaseTable(SkipRemote(true))) cfg := ¶ms.RbacConfig + assert.Equal(t, len(cfg.GetDefaultPrivilegeGroupNames()), 9) + assert.True(t, cfg.IsCollectionPrivilegeGroup("CollectionReadOnly")) + assert.False(t, cfg.IsCollectionPrivilegeGroup("DatabaseReadOnly")) assert.Equal(t, cfg.Enabled.GetAsBool(), false) - assert.Equal(t, cfg.ClusterReadOnlyPrivileges.GetAsStrings(), util.BuiltinPrivilegeGroups["ClusterReadOnly"]) - assert.Equal(t, cfg.ClusterReadWritePrivileges.GetAsStrings(), util.BuiltinPrivilegeGroups["ClusterReadWrite"]) - assert.Equal(t, cfg.ClusterAdminPrivileges.GetAsStrings(), util.BuiltinPrivilegeGroups["ClusterAdmin"]) - assert.Equal(t, cfg.DBReadOnlyPrivileges.GetAsStrings(), util.BuiltinPrivilegeGroups["DatabaseReadOnly"]) - assert.Equal(t, cfg.DBReadWritePrivileges.GetAsStrings(), util.BuiltinPrivilegeGroups["DatabaseReadWrite"]) - assert.Equal(t, cfg.DBAdminPrivileges.GetAsStrings(), util.BuiltinPrivilegeGroups["DatabaseAdmin"]) - assert.Equal(t, cfg.CollectionReadOnlyPrivileges.GetAsStrings(), util.BuiltinPrivilegeGroups["CollectionReadOnly"]) - assert.Equal(t, cfg.CollectionReadWritePrivileges.GetAsStrings(), util.BuiltinPrivilegeGroups["CollectionReadWrite"]) - assert.Equal(t, cfg.CollectionAdminPrivileges.GetAsStrings(), util.BuiltinPrivilegeGroups["CollectionAdmin"]) + assert.Equal(t, cfg.ClusterReadOnlyPrivileges.GetAsStrings(), builtinPrivilegeGroups["ClusterReadOnly"]) + assert.Equal(t, cfg.ClusterReadWritePrivileges.GetAsStrings(), builtinPrivilegeGroups["ClusterReadWrite"]) + assert.Equal(t, cfg.ClusterAdminPrivileges.GetAsStrings(), builtinPrivilegeGroups["ClusterAdmin"]) + assert.Equal(t, cfg.DBReadOnlyPrivileges.GetAsStrings(), builtinPrivilegeGroups["DatabaseReadOnly"]) + assert.Equal(t, cfg.DBReadWritePrivileges.GetAsStrings(), builtinPrivilegeGroups["DatabaseReadWrite"]) + assert.Equal(t, cfg.DBAdminPrivileges.GetAsStrings(), builtinPrivilegeGroups["DatabaseAdmin"]) + assert.Equal(t, cfg.CollectionReadOnlyPrivileges.GetAsStrings(), builtinPrivilegeGroups["CollectionReadOnly"]) + assert.Equal(t, cfg.CollectionReadWritePrivileges.GetAsStrings(), builtinPrivilegeGroups["CollectionReadWrite"]) + assert.Equal(t, cfg.CollectionAdminPrivileges.GetAsStrings(), builtinPrivilegeGroups["CollectionAdmin"]) +} + +func TestRbacConfig_Override(t *testing.T) { + params := ComponentParam{} + params.Init(NewBaseTable(SkipRemote(true))) + + clusterReadWrite := `SelectOwnership,SelectUser,DescribeResourceGroup` + + params.Save(params.RbacConfig.Enabled.Key, "true") + params.Save(params.RbacConfig.ClusterReadWritePrivileges.Key, clusterReadWrite) + + defer func() { + params.Reset(params.RbacConfig.Enabled.Key) + params.Reset(params.RbacConfig.ClusterReadWritePrivileges.Key) + }() + + group := params.RbacConfig.GetDefaultPrivilegeGroup("ClusterReadWrite") + assert.Equal(t, len(group.Privileges), 3) } diff --git a/pkg/util/paramtable/rbac_param.go b/pkg/util/paramtable/rbac_param.go index 34e0bfb7dbc29..d793a4d93b26d 100644 --- a/pkg/util/paramtable/rbac_param.go +++ b/pkg/util/paramtable/rbac_param.go @@ -3,9 +3,110 @@ package paramtable import ( "strings" + "github.com/samber/lo" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb" "github.com/milvus-io/milvus/pkg/util" ) +var ( + builtinPrivilegeGroups = map[string][]string{ + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupCollectionReadOnly.String()): collectionReadOnlyPrivilegeGroup, + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupCollectionReadWrite.String()): collectionReadWritePrivilegeGroup, + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupCollectionAdmin.String()): collectionAdminPrivilegeGroup, + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupDatabaseReadOnly.String()): databaseReadOnlyPrivilegeGroup, + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupDatabaseReadWrite.String()): databaseReadWritePrivilegeGroup, + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupDatabaseAdmin.String()): databaseAdminPrivilegeGroup, + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupClusterReadOnly.String()): clusterReadOnlyPrivilegeGroup, + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupClusterReadWrite.String()): clusterReadWritePrivilegeGroup, + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupClusterAdmin.String()): clusterAdminPrivilegeGroup, + } + + collectionReadOnlyPrivilegeGroup = []string{ + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeQuery.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeSearch.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeIndexDetail.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGetFlushState.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGetLoadState.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGetLoadingProgress.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeHasPartition.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeShowPartitions.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDescribeCollection.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDescribeAlias.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGetStatistics.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeListAliases.String()), + } + + collectionReadWritePrivilegeGroup = append(collectionReadOnlyPrivilegeGroup, + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeLoad.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeRelease.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeInsert.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDelete.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeUpsert.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeImport.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeFlush.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCompaction.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeLoadBalance.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreateIndex.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropIndex.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreatePartition.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropPartition.String()), + ) + + collectionAdminPrivilegeGroup = append(collectionReadWritePrivilegeGroup, + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreateAlias.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropAlias.String()), + ) + + databaseReadOnlyPrivilegeGroup = []string{ + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeShowCollections.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDescribeDatabase.String()), + } + + databaseReadWritePrivilegeGroup = append(databaseReadOnlyPrivilegeGroup, + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeAlterDatabase.String()), + ) + + databaseAdminPrivilegeGroup = append(databaseReadWritePrivilegeGroup, + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreateCollection.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropCollection.String()), + ) + + clusterReadOnlyPrivilegeGroup = []string{ + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeListDatabases.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeSelectOwnership.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeSelectUser.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDescribeResourceGroup.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeListResourceGroups.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeListPrivilegeGroups.String()), + } + + clusterReadWritePrivilegeGroup = append(clusterReadOnlyPrivilegeGroup, + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeFlushAll.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeTransferNode.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeTransferReplica.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeUpdateResourceGroups.String()), + ) + + clusterAdminPrivilegeGroup = append(clusterReadWritePrivilegeGroup, + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeBackupRBAC.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeRestoreRBAC.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreateDatabase.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropDatabase.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreateOwnership.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropOwnership.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeManageOwnership.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreateResourceGroup.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropResourceGroup.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeUpdateUser.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeRenameCollection.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreatePrivilegeGroup.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropPrivilegeGroup.String()), + util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeOperatePrivilegeGroup.String()), + ) +) + type rbacConfig struct { Enabled ParamItem `refreshable:"false"` ClusterReadOnlyPrivileges ParamItem `refreshable:"false"` @@ -23,7 +124,7 @@ type rbacConfig struct { func (p *rbacConfig) init(base *BaseTable) { p.Enabled = ParamItem{ - Key: "common.security.rbac.overrideBuiltInPrivilgeGroups.enabled", + Key: "common.security.rbac.overrideBuiltInPrivilegeGroups.enabled", DefaultValue: "false", Version: "2.4.16", Doc: "Whether to override build-in privilege groups", @@ -33,7 +134,7 @@ func (p *rbacConfig) init(base *BaseTable) { p.ClusterReadOnlyPrivileges = ParamItem{ Key: "common.security.rbac.cluster.readonly.privileges", - DefaultValue: strings.Join(util.ClusterReadOnlyPrivilegeGroup, ","), + DefaultValue: strings.Join(clusterReadOnlyPrivilegeGroup, ","), Version: "2.4.16", Doc: "Cluster level readonly privileges", Export: true, @@ -42,7 +143,7 @@ func (p *rbacConfig) init(base *BaseTable) { p.ClusterReadWritePrivileges = ParamItem{ Key: "common.security.rbac.cluster.readwrite.privileges", - DefaultValue: strings.Join(util.ClusterReadWritePrivilegeGroup, ","), + DefaultValue: strings.Join(clusterReadWritePrivilegeGroup, ","), Version: "2.4.16", Doc: "Cluster level readwrite privileges", Export: true, @@ -51,7 +152,7 @@ func (p *rbacConfig) init(base *BaseTable) { p.ClusterAdminPrivileges = ParamItem{ Key: "common.security.rbac.cluster.admin.privileges", - DefaultValue: strings.Join(util.ClusterAdminPrivilegeGroup, ","), + DefaultValue: strings.Join(clusterAdminPrivilegeGroup, ","), Version: "2.4.16", Doc: "Cluster level admin privileges", Export: true, @@ -60,7 +161,7 @@ func (p *rbacConfig) init(base *BaseTable) { p.DBReadOnlyPrivileges = ParamItem{ Key: "common.security.rbac.database.readonly.privileges", - DefaultValue: strings.Join(util.DatabaseReadOnlyPrivilegeGroup, ","), + DefaultValue: strings.Join(databaseReadOnlyPrivilegeGroup, ","), Version: "2.4.16", Doc: "Database level readonly privileges", Export: true, @@ -69,7 +170,7 @@ func (p *rbacConfig) init(base *BaseTable) { p.DBReadWritePrivileges = ParamItem{ Key: "common.security.rbac.database.readwrite.privileges", - DefaultValue: strings.Join(util.DatabaseReadWritePrivilegeGroup, ","), + DefaultValue: strings.Join(databaseReadWritePrivilegeGroup, ","), Version: "2.4.16", Doc: "Database level readwrite privileges", Export: true, @@ -78,7 +179,7 @@ func (p *rbacConfig) init(base *BaseTable) { p.DBAdminPrivileges = ParamItem{ Key: "common.security.rbac.database.admin.privileges", - DefaultValue: strings.Join(util.DatabaseAdminPrivilegeGroup, ","), + DefaultValue: strings.Join(databaseAdminPrivilegeGroup, ","), Version: "2.4.16", Doc: "Database level admin privileges", Export: true, @@ -87,7 +188,7 @@ func (p *rbacConfig) init(base *BaseTable) { p.CollectionReadOnlyPrivileges = ParamItem{ Key: "common.security.rbac.collection.readonly.privileges", - DefaultValue: strings.Join(util.CollectionReadOnlyPrivilegeGroup, ","), + DefaultValue: strings.Join(collectionReadOnlyPrivilegeGroup, ","), Version: "2.4.16", Doc: "Collection level readonly privileges", Export: true, @@ -96,7 +197,7 @@ func (p *rbacConfig) init(base *BaseTable) { p.CollectionReadWritePrivileges = ParamItem{ Key: "common.security.rbac.collection.readwrite.privileges", - DefaultValue: strings.Join(util.CollectionReadWritePrivilegeGroup, ","), + DefaultValue: strings.Join(collectionReadWritePrivilegeGroup, ","), Version: "2.4.16", Doc: "Collection level readwrite privileges", Export: true, @@ -105,10 +206,60 @@ func (p *rbacConfig) init(base *BaseTable) { p.CollectionAdminPrivileges = ParamItem{ Key: "common.security.rbac.collection.admin.privileges", - DefaultValue: strings.Join(util.CollectionAdminPrivilegeGroup, ","), + DefaultValue: strings.Join(collectionAdminPrivilegeGroup, ","), Version: "2.4.16", Doc: "Collection level admin privileges", Export: true, } p.CollectionAdminPrivileges.Init(base.mgr) } + +func (p *rbacConfig) GetDefaultPrivilegeGroups() []*milvuspb.PrivilegeGroupInfo { + privilegeGroupConfigs := []struct { + GroupName string + Privileges func() []string + }{ + {"ClusterReadOnly", p.ClusterReadOnlyPrivileges.GetAsStrings}, + {"ClusterReadWrite", p.ClusterReadWritePrivileges.GetAsStrings}, + {"ClusterAdmin", p.ClusterAdminPrivileges.GetAsStrings}, + {"DatabaseReadOnly", p.DBReadOnlyPrivileges.GetAsStrings}, + {"DatabaseReadWrite", p.DBReadWritePrivileges.GetAsStrings}, + {"DatabaseAdmin", p.DBAdminPrivileges.GetAsStrings}, + {"CollectionReadOnly", p.CollectionReadOnlyPrivileges.GetAsStrings}, + {"CollectionReadWrite", p.CollectionReadWritePrivileges.GetAsStrings}, + {"CollectionAdmin", p.CollectionAdminPrivileges.GetAsStrings}, + } + + builtinGroups := make([]*milvuspb.PrivilegeGroupInfo, 0, len(privilegeGroupConfigs)) + for _, config := range privilegeGroupConfigs { + privileges := lo.Map(config.Privileges(), func(name string, _ int) *milvuspb.PrivilegeEntity { + return &milvuspb.PrivilegeEntity{Name: name} + }) + builtinGroups = append(builtinGroups, &milvuspb.PrivilegeGroupInfo{ + GroupName: config.GroupName, + Privileges: privileges, + }) + } + return builtinGroups +} + +func (p *rbacConfig) GetDefaultPrivilegeGroup(privName string) *milvuspb.PrivilegeGroupInfo { + for _, group := range p.GetDefaultPrivilegeGroups() { + if group.GroupName == privName { + return group + } + } + return nil +} + +func (p *rbacConfig) GetDefaultPrivilegeGroupNames() []string { + return lo.Keys(builtinPrivilegeGroups) +} + +func (p *rbacConfig) IsCollectionPrivilegeGroup(privName string) bool { + collectionPrivilegeGroups := lo.PickBy(builtinPrivilegeGroups, func(groupName string, _ []string) bool { + return strings.Contains(groupName, "Collection") + }) + _, exists := collectionPrivilegeGroups[privName] + return exists +} diff --git a/tests/integration/rbac/privilege_group_test.go b/tests/integration/rbac/privilege_group_test.go index 7e44c5301e119..966eb6b55b9c5 100644 --- a/tests/integration/rbac/privilege_group_test.go +++ b/tests/integration/rbac/privilege_group_test.go @@ -68,7 +68,7 @@ func (s *PrivilegeGroupTestSuite) TestBuiltinPrivilegeGroup() { resp, _ = s.operatePrivilege(ctx, roleName, "Admin", commonpb.ObjectType_Global.String(), milvuspb.OperatePrivilegeType_Grant) s.True(merr.Ok(resp)) - for _, builtinGroup := range lo.Keys(util.BuiltinPrivilegeGroups) { + for _, builtinGroup := range paramtable.Get().RbacConfig.GetDefaultPrivilegeGroupNames() { resp, _ = s.operatePrivilege(ctx, roleName, builtinGroup, commonpb.ObjectType_Global.String(), milvuspb.OperatePrivilegeType_Grant) s.False(merr.Ok(resp)) } @@ -157,7 +157,7 @@ func (s *PrivilegeGroupTestSuite) TestGrantV2BuiltinPrivilegeGroup() { s.NoError(err) s.True(merr.Ok(createRoleResp)) - for _, builtinGroup := range lo.Keys(util.BuiltinPrivilegeGroups) { + for _, builtinGroup := range paramtable.Get().RbacConfig.GetDefaultPrivilegeGroupNames() { resp, _ := s.operatePrivilegeV2(ctx, roleName, builtinGroup, util.AnyWord, util.AnyWord, milvuspb.OperatePrivilegeType_Grant) s.True(merr.Ok(resp)) } @@ -314,7 +314,7 @@ func (s *PrivilegeGroupTestSuite) TestGrantV2CustomPrivilegeGroup() { // Validate the group was dropped listResp, err := s.Cluster.Proxy.ListPrivilegeGroups(ctx, &milvuspb.ListPrivilegeGroupsRequest{}) s.NoError(err) - s.Equal(len(util.BuiltinPrivilegeGroups), len(listResp.PrivilegeGroups)) + s.Equal(len(paramtable.Get().RbacConfig.GetDefaultPrivilegeGroupNames()), len(listResp.PrivilegeGroups)) // validate edge cases resp, _ = s.operatePrivilegeV2(ctx, role, util.AnyWord, util.AnyWord, util.AnyWord, milvuspb.OperatePrivilegeType_Grant)