fix: [2.4] rbac custom group privilege level check (#39194)

cherry-pick from master: https://github.com/milvus-io/milvus/pull/39164
related: related: https://github.com/milvus-io/milvus/issues/39086

---------

Signed-off-by: shaoting-huang <shaoting.huang@zilliz.com>
pull/39209/head
sthuang 2025-01-13 13:58:58 +08:00 committed by GitHub
parent af2264446f
commit e56399720d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 233 additions and 183 deletions

View File

@ -5374,10 +5374,6 @@ func (node *Proxy) validateOperatePrivilegeV2Params(req *milvuspb.OperatePrivile
if err := ValidatePrivilege(req.Grantor.Privilege.Name); err != nil {
return err
}
// validate built-in privilege group params
if err := ValidateBuiltInPrivilegeGroup(req.Grantor.Privilege.Name, req.DbName, req.CollectionName); err != nil {
return err
}
if req.Type != milvuspb.OperatePrivilegeType_Grant && req.Type != milvuspb.OperatePrivilegeType_Revoke {
return merr.WrapErrParameterInvalidMsg("the type in the request not grant or revoke")
}

View File

@ -946,31 +946,6 @@ func ValidatePrivilege(entity string) error {
return validateName(entity, "Privilege")
}
func ValidateBuiltInPrivilegeGroup(entity string, dbName string, collectionName string) error {
if !util.IsBuiltinPrivilegeGroup(entity) {
return nil
}
switch {
case strings.HasPrefix(entity, milvuspb.PrivilegeLevel_Cluster.String()):
if !util.IsAnyWord(dbName) || !util.IsAnyWord(collectionName) {
return merr.WrapErrParameterInvalidMsg("dbName and collectionName should be * for the cluster level privilege: %s", entity)
}
return nil
case strings.HasPrefix(entity, milvuspb.PrivilegeLevel_Database.String()):
if collectionName != "" && collectionName != util.AnyWord {
return merr.WrapErrParameterInvalidMsg("collectionName should be * for the database level privilege: %s", entity)
}
return nil
case strings.HasPrefix(entity, milvuspb.PrivilegeLevel_Collection.String()):
if util.IsAnyWord(dbName) && !util.IsAnyWord(collectionName) && collectionName != "" {
return merr.WrapErrParameterInvalidMsg("please specify database name for the collection level privilege: %s", entity)
}
return nil
default:
return nil
}
}
func GetCurUserFromContext(ctx context.Context) (string, error) {
return contextutil.GetCurUserFromContext(ctx)
}

View File

@ -1458,7 +1458,7 @@ func (mt *MetaTable) RestoreRBAC(ctx context.Context, tenant string, meta *milvu
return mt.catalog.RestoreRBAC(mt.ctx, tenant, meta)
}
// check if the privielge group name is defined by users
// check if the privilege group name is defined by users
func (mt *MetaTable) IsCustomPrivilegeGroup(groupName string) (bool, error) {
privGroups, err := mt.catalog.ListPrivilegeGroups(mt.ctx)
if err != nil {
@ -1574,7 +1574,7 @@ func (mt *MetaTable) OperatePrivilegeGroup(groupName string, privileges []*milvu
if group.GroupName == p.Name {
privileges = append(privileges, group.Privileges...)
} else {
return merr.WrapErrParameterInvalidMsg("there is no privilege name or privielge group name [%s] defined in system to operate", p.Name)
return merr.WrapErrParameterInvalidMsg("there is no privilege name or privilege group name [%s] defined in system to operate", p.Name)
}
}
}

View File

@ -2638,6 +2638,10 @@ func (c *Core) OperatePrivilege(ctx context.Context, in *milvuspb.OperatePrivile
ctxLog.Error("", zap.Error(err))
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_OperatePrivilegeFailure), nil
}
if err := c.validatePrivilegeGroupParams(ctx, privName, in.Entity.DbName, in.Entity.ObjectName); err != nil {
ctxLog.Error("", zap.Error(err))
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_OperatePrivilegeFailure), nil
}
// set up object type for metastore, to be compatible with v1 version
in.Entity.Object.Name = util.GetObjectType(privName)
default:
@ -2686,7 +2690,7 @@ func (c *Core) OperatePrivilege(ctx context.Context, in *milvuspb.OperatePrivile
}
grants := []*milvuspb.GrantEntity{in.Entity}
allGroups, err := c.getPrivilegeGroups()
allGroups, err := c.getDefaultAndCustomPrivilegeGroups()
if err != nil {
return nil, err
}
@ -2774,6 +2778,42 @@ func (c *Core) operatePrivilegeCommonCheck(ctx context.Context, in *milvuspb.Ope
return nil
}
func (c *Core) validatePrivilegeGroupParams(ctx context.Context, entity string, dbName string, collectionName string) error {
allGroups, err := c.getDefaultAndCustomPrivilegeGroups()
if err != nil {
return err
}
groups := lo.SliceToMap(allGroups, func(group *milvuspb.PrivilegeGroupInfo) (string, []*milvuspb.PrivilegeEntity) {
return group.GroupName, group.Privileges
})
privs, exists := groups[entity]
if !exists || len(privs) == 0 {
// it is a privilege, no need to check with other params
return nil
}
// since all privileges are same level in a group, just check the first privilege
level := util.GetPrivilegeLevel(privs[0].GetName())
switch level {
case milvuspb.PrivilegeLevel_Cluster.String():
if !util.IsAnyWord(dbName) || !util.IsAnyWord(collectionName) {
return merr.WrapErrParameterInvalidMsg("dbName and collectionName should be * for the cluster level privilege: %s", entity)
}
return nil
case milvuspb.PrivilegeLevel_Database.String():
if collectionName != "" && collectionName != util.AnyWord {
return merr.WrapErrParameterInvalidMsg("collectionName should be * for the database level privilege: %s", entity)
}
return nil
case milvuspb.PrivilegeLevel_Collection.String():
if util.IsAnyWord(dbName) && !util.IsAnyWord(collectionName) && collectionName != "" {
return merr.WrapErrParameterInvalidMsg("please specify database name for the collection level privilege: %s", entity)
}
return nil
default:
return errors.New("not found the privilege level")
}
}
func (c *Core) getMetastorePrivilegeName(ctx context.Context, privName string) (string, error) {
// if it is built-in privilege, return the privilege name directly
if util.IsPrivilegeNameDefined(privName) {
@ -2875,7 +2915,7 @@ func (c *Core) ListPolicy(ctx context.Context, in *internalpb.ListPolicyRequest)
}, nil
}
// expand privilege groups and turn to policies
allGroups, err := c.getPrivilegeGroups()
allGroups, err := c.getDefaultAndCustomPrivilegeGroups()
if err != nil {
errMsg := "fail to get privilege groups"
ctxLog.Warn(errMsg, zap.Error(err))
@ -3223,12 +3263,12 @@ func (c *Core) OperatePrivilegeGroup(ctx context.Context, in *milvuspb.OperatePr
return p.Name
})
// check if privileges are the same object type
objectTypes := lo.SliceToMap(newPrivs, func(p *milvuspb.PrivilegeEntity) (string, struct{}) {
return util.GetObjectType(p.Name), struct{}{}
// check if privileges are the same privilege level
privilegeLevels := lo.SliceToMap(newPrivs, func(p *milvuspb.PrivilegeEntity) (string, struct{}) {
return util.GetPrivilegeLevel(p.Name), struct{}{}
})
if len(objectTypes) > 1 {
return nil, errors.New("privileges are not the same object type")
if len(privilegeLevels) > 1 {
return nil, errors.New("privileges are not the same privilege level")
}
case milvuspb.OperatePrivilegeGroupType_RemovePrivilegesFromGroup:
newPrivs, _ := lo.Difference(v, in.Privileges)
@ -3374,8 +3414,8 @@ func (c *Core) expandPrivilegeGroups(grants []*milvuspb.GrantEntity, groups map[
}), nil
}
// getPrivilegeGroups returns default privilege groups and user-defined privilege groups.
func (c *Core) getPrivilegeGroups() ([]*milvuspb.PrivilegeGroupInfo, error) {
// getDefaultAndCustomPrivilegeGroups returns default privilege groups and user-defined privilege groups.
func (c *Core) getDefaultAndCustomPrivilegeGroups() ([]*milvuspb.PrivilegeGroupInfo, error) {
allGroups, err := c.meta.ListPrivilegeGroups()
allGroups = append(allGroups, Params.RbacConfig.GetDefaultPrivilegeGroups()...)
if err != nil {

View File

@ -22,6 +22,7 @@ import (
"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/common"
"github.com/milvus-io/milvus/pkg/util/typeutil"
)
@ -292,6 +293,124 @@ var (
}
)
// rbac v2 uses privilege level to group privileges rather than object type
var (
CollectionReadOnlyPrivileges = ConvertPrivileges([]string{
commonpb.ObjectPrivilege_PrivilegeQuery.String(),
commonpb.ObjectPrivilege_PrivilegeSearch.String(),
commonpb.ObjectPrivilege_PrivilegeIndexDetail.String(),
commonpb.ObjectPrivilege_PrivilegeGetFlushState.String(),
commonpb.ObjectPrivilege_PrivilegeGetLoadState.String(),
commonpb.ObjectPrivilege_PrivilegeGetLoadingProgress.String(),
commonpb.ObjectPrivilege_PrivilegeHasPartition.String(),
commonpb.ObjectPrivilege_PrivilegeShowPartitions.String(),
commonpb.ObjectPrivilege_PrivilegeDescribeCollection.String(),
commonpb.ObjectPrivilege_PrivilegeDescribeAlias.String(),
commonpb.ObjectPrivilege_PrivilegeGetStatistics.String(),
commonpb.ObjectPrivilege_PrivilegeListAliases.String(),
})
CollectionReadWritePrivileges = append(CollectionReadOnlyPrivileges,
ConvertPrivileges([]string{
commonpb.ObjectPrivilege_PrivilegeLoad.String(),
commonpb.ObjectPrivilege_PrivilegeRelease.String(),
commonpb.ObjectPrivilege_PrivilegeInsert.String(),
commonpb.ObjectPrivilege_PrivilegeDelete.String(),
commonpb.ObjectPrivilege_PrivilegeUpsert.String(),
commonpb.ObjectPrivilege_PrivilegeImport.String(),
commonpb.ObjectPrivilege_PrivilegeFlush.String(),
commonpb.ObjectPrivilege_PrivilegeCompaction.String(),
commonpb.ObjectPrivilege_PrivilegeLoadBalance.String(),
commonpb.ObjectPrivilege_PrivilegeCreateIndex.String(),
commonpb.ObjectPrivilege_PrivilegeDropIndex.String(),
commonpb.ObjectPrivilege_PrivilegeCreatePartition.String(),
commonpb.ObjectPrivilege_PrivilegeDropPartition.String(),
})...,
)
CollectionAdminPrivileges = append(CollectionReadWritePrivileges,
ConvertPrivileges([]string{
commonpb.ObjectPrivilege_PrivilegeCreateAlias.String(),
commonpb.ObjectPrivilege_PrivilegeDropAlias.String(),
})...,
)
DatabaseReadOnlyPrivileges = ConvertPrivileges([]string{
commonpb.ObjectPrivilege_PrivilegeShowCollections.String(),
commonpb.ObjectPrivilege_PrivilegeDescribeDatabase.String(),
})
DatabaseReadWritePrivileges = append(DatabaseReadOnlyPrivileges,
ConvertPrivileges([]string{
commonpb.ObjectPrivilege_PrivilegeAlterDatabase.String(),
})...,
)
DatabaseAdminPrivileges = append(DatabaseReadWritePrivileges,
ConvertPrivileges([]string{
commonpb.ObjectPrivilege_PrivilegeCreateCollection.String(),
commonpb.ObjectPrivilege_PrivilegeDropCollection.String(),
})...,
)
ClusterReadOnlyPrivileges = ConvertPrivileges([]string{
commonpb.ObjectPrivilege_PrivilegeListDatabases.String(),
commonpb.ObjectPrivilege_PrivilegeSelectOwnership.String(),
commonpb.ObjectPrivilege_PrivilegeSelectUser.String(),
commonpb.ObjectPrivilege_PrivilegeDescribeResourceGroup.String(),
commonpb.ObjectPrivilege_PrivilegeListResourceGroups.String(),
commonpb.ObjectPrivilege_PrivilegeListPrivilegeGroups.String(),
})
ClusterReadWritePrivileges = append(ClusterReadOnlyPrivileges,
ConvertPrivileges([]string{
commonpb.ObjectPrivilege_PrivilegeFlushAll.String(),
commonpb.ObjectPrivilege_PrivilegeTransferNode.String(),
commonpb.ObjectPrivilege_PrivilegeTransferReplica.String(),
commonpb.ObjectPrivilege_PrivilegeUpdateResourceGroups.String(),
})...,
)
ClusterAdminPrivileges = append(ClusterReadWritePrivileges,
ConvertPrivileges([]string{
commonpb.ObjectPrivilege_PrivilegeBackupRBAC.String(),
commonpb.ObjectPrivilege_PrivilegeRestoreRBAC.String(),
commonpb.ObjectPrivilege_PrivilegeCreateDatabase.String(),
commonpb.ObjectPrivilege_PrivilegeDropDatabase.String(),
commonpb.ObjectPrivilege_PrivilegeCreateOwnership.String(),
commonpb.ObjectPrivilege_PrivilegeDropOwnership.String(),
commonpb.ObjectPrivilege_PrivilegeManageOwnership.String(),
commonpb.ObjectPrivilege_PrivilegeCreateResourceGroup.String(),
commonpb.ObjectPrivilege_PrivilegeDropResourceGroup.String(),
commonpb.ObjectPrivilege_PrivilegeUpdateUser.String(),
commonpb.ObjectPrivilege_PrivilegeRenameCollection.String(),
commonpb.ObjectPrivilege_PrivilegeCreatePrivilegeGroup.String(),
commonpb.ObjectPrivilege_PrivilegeDropPrivilegeGroup.String(),
commonpb.ObjectPrivilege_PrivilegeOperatePrivilegeGroup.String(),
})...,
)
)
// ConvertPrivileges converts each privilege from metastore format to API format.
func ConvertPrivileges(privileges []string) []string {
return lo.Map(privileges, func(name string, _ int) string {
return MetaStore2API(name)
})
}
func GetPrivilegeLevel(privilege string) string {
if lo.Contains(ClusterAdminPrivileges, privilege) {
return milvuspb.PrivilegeLevel_Cluster.String()
}
if lo.Contains(DatabaseAdminPrivileges, privilege) {
return milvuspb.PrivilegeLevel_Database.String()
}
if lo.Contains(CollectionAdminPrivileges, privilege) {
return milvuspb.PrivilegeLevel_Collection.String()
}
return ""
}
// StringSet convert array to map for conveniently check if the array contains an element
func StringSet(strings []string) map[string]struct{} {
stringsMap := make(map[string]struct{})

View File

@ -22,26 +22,24 @@ import (
"github.com/stretchr/testify/assert"
)
func TestRbacConfig_Init(t *testing.T) {
func TestRbacConfig_DefaultPrivileges(t *testing.T) {
params := ComponentParam{}
params.Init(NewBaseTable(SkipRemote(true)))
cfg := &params.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(), 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"])
assert.Equal(t, cfg.ClusterReadOnlyPrivileges.GetAsStrings(), cfg.GetDefaultPrivilegeGroupPrivileges("ClusterReadOnly"))
assert.Equal(t, cfg.ClusterReadWritePrivileges.GetAsStrings(), cfg.GetDefaultPrivilegeGroupPrivileges("ClusterReadWrite"))
assert.Equal(t, cfg.ClusterAdminPrivileges.GetAsStrings(), cfg.GetDefaultPrivilegeGroupPrivileges("ClusterAdmin"))
assert.Equal(t, cfg.DBReadOnlyPrivileges.GetAsStrings(), cfg.GetDefaultPrivilegeGroupPrivileges("DatabaseReadOnly"))
assert.Equal(t, cfg.DBReadWritePrivileges.GetAsStrings(), cfg.GetDefaultPrivilegeGroupPrivileges("DatabaseReadWrite"))
assert.Equal(t, cfg.DBAdminPrivileges.GetAsStrings(), cfg.GetDefaultPrivilegeGroupPrivileges("DatabaseAdmin"))
assert.Equal(t, cfg.CollectionReadOnlyPrivileges.GetAsStrings(), cfg.GetDefaultPrivilegeGroupPrivileges("CollectionReadOnly"))
assert.Equal(t, cfg.CollectionReadWritePrivileges.GetAsStrings(), cfg.GetDefaultPrivilegeGroupPrivileges("CollectionReadWrite"))
assert.Equal(t, cfg.CollectionAdminPrivileges.GetAsStrings(), cfg.GetDefaultPrivilegeGroupPrivileges("CollectionAdmin"))
}
func TestRbacConfig_Override(t *testing.T) {
func TestRbacConfig_OverridePrivileges(t *testing.T) {
params := ComponentParam{}
params.Init(NewBaseTable(SkipRemote(true)))

View File

@ -10,103 +10,6 @@ import (
"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"`
@ -134,7 +37,7 @@ func (p *rbacConfig) init(base *BaseTable) {
p.ClusterReadOnlyPrivileges = ParamItem{
Key: "common.security.rbac.cluster.readonly.privileges",
DefaultValue: strings.Join(clusterReadOnlyPrivilegeGroup, ","),
DefaultValue: strings.Join(util.ClusterReadOnlyPrivileges, ","),
Version: "2.4.16",
Doc: "Cluster level readonly privileges",
Export: true,
@ -143,7 +46,7 @@ func (p *rbacConfig) init(base *BaseTable) {
p.ClusterReadWritePrivileges = ParamItem{
Key: "common.security.rbac.cluster.readwrite.privileges",
DefaultValue: strings.Join(clusterReadWritePrivilegeGroup, ","),
DefaultValue: strings.Join(util.ClusterReadWritePrivileges, ","),
Version: "2.4.16",
Doc: "Cluster level readwrite privileges",
Export: true,
@ -152,7 +55,7 @@ func (p *rbacConfig) init(base *BaseTable) {
p.ClusterAdminPrivileges = ParamItem{
Key: "common.security.rbac.cluster.admin.privileges",
DefaultValue: strings.Join(clusterAdminPrivilegeGroup, ","),
DefaultValue: strings.Join(util.ClusterAdminPrivileges, ","),
Version: "2.4.16",
Doc: "Cluster level admin privileges",
Export: true,
@ -161,7 +64,7 @@ func (p *rbacConfig) init(base *BaseTable) {
p.DBReadOnlyPrivileges = ParamItem{
Key: "common.security.rbac.database.readonly.privileges",
DefaultValue: strings.Join(databaseReadOnlyPrivilegeGroup, ","),
DefaultValue: strings.Join(util.DatabaseReadOnlyPrivileges, ","),
Version: "2.4.16",
Doc: "Database level readonly privileges",
Export: true,
@ -170,7 +73,7 @@ func (p *rbacConfig) init(base *BaseTable) {
p.DBReadWritePrivileges = ParamItem{
Key: "common.security.rbac.database.readwrite.privileges",
DefaultValue: strings.Join(databaseReadWritePrivilegeGroup, ","),
DefaultValue: strings.Join(util.DatabaseReadWritePrivileges, ","),
Version: "2.4.16",
Doc: "Database level readwrite privileges",
Export: true,
@ -179,7 +82,7 @@ func (p *rbacConfig) init(base *BaseTable) {
p.DBAdminPrivileges = ParamItem{
Key: "common.security.rbac.database.admin.privileges",
DefaultValue: strings.Join(databaseAdminPrivilegeGroup, ","),
DefaultValue: strings.Join(util.DatabaseAdminPrivileges, ","),
Version: "2.4.16",
Doc: "Database level admin privileges",
Export: true,
@ -188,7 +91,7 @@ func (p *rbacConfig) init(base *BaseTable) {
p.CollectionReadOnlyPrivileges = ParamItem{
Key: "common.security.rbac.collection.readonly.privileges",
DefaultValue: strings.Join(collectionReadOnlyPrivilegeGroup, ","),
DefaultValue: strings.Join(util.CollectionReadOnlyPrivileges, ","),
Version: "2.4.16",
Doc: "Collection level readonly privileges",
Export: true,
@ -197,7 +100,7 @@ func (p *rbacConfig) init(base *BaseTable) {
p.CollectionReadWritePrivileges = ParamItem{
Key: "common.security.rbac.collection.readwrite.privileges",
DefaultValue: strings.Join(collectionReadWritePrivilegeGroup, ","),
DefaultValue: strings.Join(util.CollectionReadWritePrivileges, ","),
Version: "2.4.16",
Doc: "Collection level readwrite privileges",
Export: true,
@ -206,7 +109,7 @@ func (p *rbacConfig) init(base *BaseTable) {
p.CollectionAdminPrivileges = ParamItem{
Key: "common.security.rbac.collection.admin.privileges",
DefaultValue: strings.Join(collectionAdminPrivilegeGroup, ","),
DefaultValue: strings.Join(util.CollectionAdminPrivileges, ","),
Version: "2.4.16",
Doc: "Collection level admin privileges",
Export: true,
@ -219,15 +122,15 @@ func (p *rbacConfig) GetDefaultPrivilegeGroups() []*milvuspb.PrivilegeGroupInfo
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},
{util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupClusterReadOnly.String()), p.ClusterReadOnlyPrivileges.GetAsStrings},
{util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupClusterReadWrite.String()), p.ClusterReadWritePrivileges.GetAsStrings},
{util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupClusterAdmin.String()), p.ClusterAdminPrivileges.GetAsStrings},
{util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupDatabaseReadOnly.String()), p.DBReadOnlyPrivileges.GetAsStrings},
{util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupDatabaseReadWrite.String()), p.DBReadWritePrivileges.GetAsStrings},
{util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupDatabaseAdmin.String()), p.DBAdminPrivileges.GetAsStrings},
{util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupCollectionReadOnly.String()), p.CollectionReadOnlyPrivileges.GetAsStrings},
{util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupCollectionReadWrite.String()), p.CollectionReadWritePrivileges.GetAsStrings},
{util.MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGroupCollectionAdmin.String()), p.CollectionAdminPrivileges.GetAsStrings},
}
builtinGroups := make([]*milvuspb.PrivilegeGroupInfo, 0, len(privilegeGroupConfigs))
@ -245,21 +148,34 @@ func (p *rbacConfig) GetDefaultPrivilegeGroups() []*milvuspb.PrivilegeGroupInfo
func (p *rbacConfig) GetDefaultPrivilegeGroup(privName string) *milvuspb.PrivilegeGroupInfo {
for _, group := range p.GetDefaultPrivilegeGroups() {
if group.GroupName == privName {
if group.GetGroupName() == privName {
return group
}
}
return nil
}
func (p *rbacConfig) GetDefaultPrivilegeGroupPrivileges(groupName string) []string {
group := p.GetDefaultPrivilegeGroup(groupName)
if group == nil {
return nil
}
return lo.Map(group.GetPrivileges(), func(priv *milvuspb.PrivilegeEntity, _ int) string {
return priv.GetName()
})
}
func (p *rbacConfig) GetDefaultPrivilegeGroupNames() []string {
return lo.Keys(builtinPrivilegeGroups)
return lo.Map(p.GetDefaultPrivilegeGroups(), func(group *milvuspb.PrivilegeGroupInfo, _ int) string {
return group.GroupName
})
}
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
for _, groupName := range p.GetDefaultPrivilegeGroupNames() {
if strings.Contains(groupName, milvuspb.PrivilegeLevel_Collection.String()) && groupName == privName {
return true
}
}
return false
}

View File

@ -268,7 +268,8 @@ func (s *PrivilegeGroupTestSuite) TestGrantV2CustomPrivilegeGroup() {
selectResp, _ = s.validateGrants(ctx, role, commonpb.ObjectType_Global.String(), util.AnyWord, util.AnyWord)
s.Len(selectResp.GetEntities(), 2)
// add different object type privileges to group1 is not allowed
// add different privilege group level privileges to group1 is not allowed
s.Equal(milvuspb.PrivilegeLevel_Database.String(), util.GetPrivilegeLevel("CreateCollection"))
resp, _ = s.Cluster.Proxy.OperatePrivilegeGroup(ctx, &milvuspb.OperatePrivilegeGroupRequest{
GroupName: "group1",
Type: milvuspb.OperatePrivilegeGroupType_AddPrivilegesToGroup,

View File

@ -104,9 +104,9 @@ func (s *RBACBackupTestSuite) TestBackup() {
createRole(roleName)
// grant collection level search privilege to role test_role
operatePrivilege(roleName, "Search", util.AnyWord, util.AnyWord, milvuspb.OperatePrivilegeType_Grant)
operatePrivilege(roleName, "Search", util.AnyWord, util.DefaultDBName, milvuspb.OperatePrivilegeType_Grant)
// create privielge group test_group
// create privilege group test_group
groupName := "test_group"
createPrivGroupResp, err := s.Cluster.Proxy.CreatePrivilegeGroup(ctx, &milvuspb.CreatePrivilegeGroupRequest{
GroupName: groupName,
@ -114,6 +114,11 @@ func (s *RBACBackupTestSuite) TestBackup() {
s.NoError(err)
s.True(merr.Ok(createPrivGroupResp))
collectionPrivileges := []*milvuspb.PrivilegeEntity{{Name: "Query"}, {Name: "Insert"}}
for _, p := range collectionPrivileges {
s.Equal(milvuspb.PrivilegeLevel_Collection.String(), util.GetPrivilegeLevel(p.Name))
}
// add query and insert privilege to group test_group
addPrivsToGroupResp, err := s.Cluster.Proxy.OperatePrivilegeGroup(ctx, &milvuspb.OperatePrivilegeGroupRequest{
GroupName: groupName,
@ -124,7 +129,7 @@ func (s *RBACBackupTestSuite) TestBackup() {
s.True(merr.Ok(addPrivsToGroupResp))
// grant privilege group test_group to role test_role
operatePrivilege(roleName, groupName, util.AnyWord, util.AnyWord, milvuspb.OperatePrivilegeType_Grant)
operatePrivilege(roleName, groupName, util.AnyWord, util.DefaultDBName, milvuspb.OperatePrivilegeType_Grant)
userName := "test_user"
passwd := "test_passwd"
@ -166,10 +171,10 @@ func (s *RBACBackupTestSuite) TestBackup() {
s.False(merr.Ok(restoreRBACResp))
// revoke privilege search from role test_role before dropping the role
operatePrivilege(roleName, "Search", util.AnyWord, util.AnyWord, milvuspb.OperatePrivilegeType_Revoke)
operatePrivilege(roleName, "Search", util.AnyWord, util.DefaultDBName, milvuspb.OperatePrivilegeType_Revoke)
// revoke privilege group test_group from role test_role before dropping the role
operatePrivilege(roleName, groupName, util.AnyWord, util.AnyWord, milvuspb.OperatePrivilegeType_Revoke)
operatePrivilege(roleName, groupName, util.AnyWord, util.DefaultDBName, milvuspb.OperatePrivilegeType_Revoke)
// drop privilege group test_group
dropPrivGroupResp, err := s.Cluster.Proxy.DropPrivilegeGroup(ctx, &milvuspb.DropPrivilegeGroupRequest{
@ -206,9 +211,9 @@ func (s *RBACBackupTestSuite) TestBackup() {
s.Equal(backupRBACResp2.GetRBACMeta().String(), backupRBACResp.GetRBACMeta().String())
// clean rbac meta
operatePrivilege(roleName, "Search", util.AnyWord, util.AnyWord, milvuspb.OperatePrivilegeType_Revoke)
operatePrivilege(roleName, "Search", util.AnyWord, util.DefaultDBName, milvuspb.OperatePrivilegeType_Revoke)
operatePrivilege(roleName, groupName, util.AnyWord, util.AnyWord, milvuspb.OperatePrivilegeType_Revoke)
operatePrivilege(roleName, groupName, util.AnyWord, util.DefaultDBName, milvuspb.OperatePrivilegeType_Revoke)
dropPrivGroupResp2, err := s.Cluster.Proxy.DropPrivilegeGroup(ctx, &milvuspb.DropPrivilegeGroupRequest{
GroupName: groupName,