Skip to content

Commit

Permalink
feat: [2.5] root privileges can be customized
Browse files Browse the repository at this point in the history
Signed-off-by: SimFG <[email protected]>
  • Loading branch information
SimFG committed Jan 16, 2025
1 parent 1602390 commit 82f0423
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 4 deletions.
1 change: 1 addition & 0 deletions configs/milvus.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,7 @@ common:
# like the old password verification when updating the credential
superUsers:
defaultRootPassword: "Milvus" # default password for root user. The maximum length is 72 characters, and double quotes are required.
rootShouldBindRole: false # Whether the root user should bind a role when the authorization is enabled.
rbac:
overrideBuiltInPrivilegeGroups:
enabled: false # Whether to override build-in privilege groups
Expand Down
7 changes: 7 additions & 0 deletions internal/distributed/proxy/httpserver/handler_v1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,11 @@ func initHTTPServer(proxy types.ProxyComponent, needAuth bool) *gin.Engine {
----|----------------|----------------|----------------
*/
func genAuthMiddleWare(needAuth bool) gin.HandlerFunc {
InitMockGlobalMetaCache()
proxy.AddRootUserToAdminRole()
if needAuth {
return func(c *gin.Context) {
// proxy.RemoveRootUserFromAdminRole()
c.Set(ContextUsername, "")
username, password, ok := ParseUsernamePassword(c)
if !ok {
Expand All @@ -161,6 +164,10 @@ func genAuthMiddleWare(needAuth bool) gin.HandlerFunc {
}
}

func InitMockGlobalMetaCache() {
proxy.InitEmptyGlobalCache()
}

func Print(code int32, message string) string {
return fmt.Sprintf("{\"%s\":%d,\"%s\":\"%s\"}", HTTPReturnCode, code, HTTPReturnMessage, message)
}
Expand Down
4 changes: 2 additions & 2 deletions internal/distributed/proxy/httpserver/handler_v2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,8 @@ func TestGrpcWrapper(t *testing.T) {
assert.Equal(t, http.StatusForbidden, w.Code)
err = json.Unmarshal(w.Body.Bytes(), returnBody)
assert.Nil(t, err)
assert.Equal(t, int32(2), returnBody.Code)
assert.Equal(t, "service unavailable: internal: Milvus Proxy is not ready yet. please wait", returnBody.Message)
assert.Equal(t, int32(65535), returnBody.Code)
assert.Equal(t, "rpc error: code = PermissionDenied desc = PrivilegeLoad: permission deny to test in the `default` database", returnBody.Message)
fmt.Println(w.Body.String())
})
}
Expand Down
63 changes: 63 additions & 0 deletions internal/proxy/meta_cache_testonly.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//go:build test
// +build test

/*
* Licensed to the LF AI & Data foundation under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package proxy

import (
"github.com/cockroachdb/errors"
"github.com/stretchr/testify/mock"

"github.com/milvus-io/milvus/internal/mocks"
"github.com/milvus-io/milvus/pkg/common"
"github.com/milvus-io/milvus/pkg/util/funcutil"
"github.com/milvus-io/milvus/pkg/util/typeutil"
)

func AddRootUserToAdminRole() {
err := globalMetaCache.RefreshPolicyInfo(typeutil.CacheOp{OpType: typeutil.CacheAddUserToRole, OpKey: funcutil.EncodeUserRoleCache("root", "admin")})
if err != nil {
panic(err)

Check warning on line 37 in internal/proxy/meta_cache_testonly.go

View check run for this annotation

Codecov / codecov/patch

internal/proxy/meta_cache_testonly.go#L37

Added line #L37 was not covered by tests
}
}

func RemoveRootUserFromAdminRole() {
err := globalMetaCache.RefreshPolicyInfo(typeutil.CacheOp{OpType: typeutil.CacheRemoveUserFromRole, OpKey: funcutil.EncodeUserRoleCache("root", "admin")})
if err != nil {
panic(err)

Check warning on line 44 in internal/proxy/meta_cache_testonly.go

View check run for this annotation

Codecov / codecov/patch

internal/proxy/meta_cache_testonly.go#L41-L44

Added lines #L41 - L44 were not covered by tests
}
}

func InitEmptyGlobalCache() {
var err error
emptyMock := common.NewEmptyMockT()
rootcoord := mocks.NewMockRootCoordClient(emptyMock)
rootcoord.EXPECT().DescribeCollection(mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("collection not found"))
querycoord := mocks.NewMockQueryCoordClient(emptyMock)
mgr := newShardClientMgr()
globalMetaCache, err = NewMetaCache(rootcoord, querycoord, mgr)
if err != nil {
panic(err)

Check warning on line 57 in internal/proxy/meta_cache_testonly.go

View check run for this annotation

Codecov / codecov/patch

internal/proxy/meta_cache_testonly.go#L57

Added line #L57 was not covered by tests
}
}

func SetGlobalMetaCache(metaCache *MetaCache) {
globalMetaCache = metaCache

Check warning on line 62 in internal/proxy/meta_cache_testonly.go

View check run for this annotation

Codecov / codecov/patch

internal/proxy/meta_cache_testonly.go#L61-L62

Added lines #L61 - L62 were not covered by tests
}
2 changes: 1 addition & 1 deletion internal/proxy/privilege_interceptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func PrivilegeInterceptor(ctx context.Context, req interface{}) (context.Context
log.Warn("GetCurUserFromContext fail", zap.Error(err))
return ctx, err
}
if username == util.UserRoot {
if !Params.CommonCfg.RootShouldBindRole.GetAsBool() && username == util.UserRoot {
return ctx, nil
}
roleNames, err := GetRole(username)
Expand Down
34 changes: 34 additions & 0 deletions internal/proxy/privilege_interceptor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,40 @@ func TestPrivilegeInterceptor(t *testing.T) {
})
}

func TestRootShouldBindRole(t *testing.T) {
paramtable.Init()
Params.Save(Params.CommonCfg.AuthorizationEnabled.Key, "true")
defer Params.Reset(Params.CommonCfg.AuthorizationEnabled.Key)
rootCtx := GetContext(context.Background(), "root:Milvus")
t.Run("not bind role", func(t *testing.T) {
Params.Save(Params.CommonCfg.RootShouldBindRole.Key, "false")
defer Params.Reset(Params.CommonCfg.RootShouldBindRole.Key)

InitEmptyGlobalCache()
_, err := PrivilegeInterceptor(rootCtx, &milvuspb.LoadCollectionRequest{
CollectionName: "col1",
})
assert.NoError(t, err)
})

t.Run("bind role", func(t *testing.T) {
Params.Save(Params.CommonCfg.RootShouldBindRole.Key, "true")
defer Params.Reset(Params.CommonCfg.RootShouldBindRole.Key)

InitEmptyGlobalCache()
_, err := PrivilegeInterceptor(rootCtx, &milvuspb.LoadCollectionRequest{
CollectionName: "col1",
})
assert.Error(t, err)

AddRootUserToAdminRole()
_, err = PrivilegeInterceptor(rootCtx, &milvuspb.LoadCollectionRequest{
CollectionName: "col1",
})
assert.NoError(t, err)
})
}

func TestResourceGroupPrivilege(t *testing.T) {
ctx := context.Background()

Expand Down
6 changes: 5 additions & 1 deletion internal/rootcoord/root_coord.go
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,11 @@ func (c *Core) initCredentials(initCtx context.Context) error {
}
log.Ctx(initCtx).Info("RootCoord init user root")
err = c.meta.AddCredential(initCtx, &internalpb.CredentialInfo{Username: util.UserRoot, EncryptedPassword: encryptedRootPassword})
return err
if err != nil {
log.Ctx(initCtx).Warn("RootCoord init user root failed", zap.Error(err))
return err
}

Check warning on line 584 in internal/rootcoord/root_coord.go

View check run for this annotation

Codecov / codecov/patch

internal/rootcoord/root_coord.go#L582-L584

Added lines #L582 - L584 were not covered by tests
return nil
}
return nil
}
Expand Down
52 changes: 52 additions & 0 deletions pkg/common/mock_testonly.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//go:build test

/*
* Licensed to the LF AI & Data foundation under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package common

import (
"context"
"fmt"

"github.com/milvus-io/milvus/pkg/log"
)

type MockTestingT struct {
ctx context.Context
}

func NewEmptyMockT() *MockTestingT {
return &MockTestingT{
ctx: context.Background(),
}
}

func (m *MockTestingT) Logf(format string, args ...interface{}) {
log.Ctx(m.ctx).Info(fmt.Sprintf(format, args...))
}

func (m *MockTestingT) Errorf(format string, args ...interface{}) {
log.Ctx(m.ctx).Error(fmt.Sprintf(format, args...))
}

func (m *MockTestingT) FailNow() {
log.Ctx(m.ctx).Panic("FailNow called")
}

func (m *MockTestingT) Cleanup(func()) {}
10 changes: 10 additions & 0 deletions pkg/util/paramtable/component_param.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ type commonConfig struct {
AuthorizationEnabled ParamItem `refreshable:"false"`
SuperUsers ParamItem `refreshable:"true"`
DefaultRootPassword ParamItem `refreshable:"false"`
RootShouldBindRole ParamItem `refreshable:"true"`

ClusterName ParamItem `refreshable:"false"`

Expand Down Expand Up @@ -669,6 +670,15 @@ like the old password verification when updating the credential`,
}
p.DefaultRootPassword.Init(base.mgr)

p.RootShouldBindRole = ParamItem{
Key: "common.security.rootShouldBindRole",
Version: "2.5.4",
Doc: "Whether the root user should bind a role when the authorization is enabled.",
DefaultValue: "false",
Export: true,
}
p.RootShouldBindRole.Init(base.mgr)

p.ClusterName = ParamItem{
Key: "common.cluster.name",
Version: "2.0.0",
Expand Down

0 comments on commit 82f0423

Please sign in to comment.