未验证 提交 e1fd9492 编写于 作者: K KubeSphere CI Bot 提交者: GitHub

Merge pull request #2230 from wansir/master

fix: multi-cluster proxy authentication
......@@ -38,6 +38,7 @@ import (
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizerfactory"
authorizationoptions "kubesphere.io/kubesphere/pkg/apiserver/authorization/options"
"kubesphere.io/kubesphere/pkg/apiserver/authorization/path"
"kubesphere.io/kubesphere/pkg/apiserver/authorization/proxy"
unionauthorizer "kubesphere.io/kubesphere/pkg/apiserver/authorization/union"
apiserverconfig "kubesphere.io/kubesphere/pkg/apiserver/config"
"kubesphere.io/kubesphere/pkg/apiserver/dispatch"
......@@ -267,7 +268,7 @@ func (s *APIServer) buildHandlerChain(stopCh <-chan struct{}) {
excludedPaths := []string{"/oauth/*", "/kapis/config.kubesphere.io/*", "/kapis/version"}
pathAuthorizer, _ := path.NewAuthorizer(excludedPaths)
amOperator := am.NewReadOnlyOperator(s.InformerFactory)
authorizers = unionauthorizer.New(pathAuthorizer, authorizerfactory.NewRBACAuthorizer(amOperator))
authorizers = unionauthorizer.New(pathAuthorizer, proxy.NewAuthorizer(s.Config.MultiClusterOptions.Enable), authorizerfactory.NewRBACAuthorizer(amOperator))
}
handler = filters.WithAuthorization(handler, authorizers)
......
......@@ -230,37 +230,6 @@ func (r *RBACAuthorizer) visitRulesFor(requestAttributes authorizer.Attributes,
}
}
if requestAttributes.GetResourceScope() == request.ClusterScope || requestAttributes.GetResourceScope() == request.NamespaceScope {
if clusterRoleBindings, err := r.am.ListClusterRoleBindings(""); err != nil {
if !visitor(nil, "", nil, err) {
return
}
} else {
sourceDescriber := &clusterRoleBindingDescriber{}
for _, clusterRoleBinding := range clusterRoleBindings {
subjectIndex, applies := appliesTo(requestAttributes.GetUser(), clusterRoleBinding.Subjects, "")
if !applies {
continue
}
regoPolicy, rules, err := r.am.GetRoleReferenceRules(clusterRoleBinding.RoleRef, "")
if err != nil {
visitor(nil, "", nil, err)
continue
}
sourceDescriber.binding = clusterRoleBinding
sourceDescriber.subject = &clusterRoleBinding.Subjects[subjectIndex]
if !visitor(sourceDescriber, regoPolicy, nil, nil) {
return
}
for i := range rules {
if !visitor(sourceDescriber, "", &rules[i], nil) {
return
}
}
}
}
}
if requestAttributes.GetResourceScope() == request.WorkspaceScope || requestAttributes.GetResourceScope() == request.NamespaceScope {
var workspace string
......@@ -338,6 +307,35 @@ func (r *RBACAuthorizer) visitRulesFor(requestAttributes authorizer.Attributes,
}
}
}
if clusterRoleBindings, err := r.am.ListClusterRoleBindings(""); err != nil {
if !visitor(nil, "", nil, err) {
return
}
} else {
sourceDescriber := &clusterRoleBindingDescriber{}
for _, clusterRoleBinding := range clusterRoleBindings {
subjectIndex, applies := appliesTo(requestAttributes.GetUser(), clusterRoleBinding.Subjects, "")
if !applies {
continue
}
regoPolicy, rules, err := r.am.GetRoleReferenceRules(clusterRoleBinding.RoleRef, "")
if err != nil {
visitor(nil, "", nil, err)
continue
}
sourceDescriber.binding = clusterRoleBinding
sourceDescriber.subject = &clusterRoleBinding.Subjects[subjectIndex]
if !visitor(sourceDescriber, regoPolicy, nil, nil) {
return
}
for i := range rules {
if !visitor(sourceDescriber, "", &rules[i], nil) {
return
}
}
}
}
}
// appliesTo returns whether any of the bindingSubjects applies to the specified subject,
......
/*
Copyright 2020 The KubeSphere Authors.
Licensed 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
/*
Copyright 2020 The KubeSphere Authors.
Licensed 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 (
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer"
)
// NewAuthorizer returns an authorizer which accepts cluster proxy request.
// If multi-cluster mode is enabled, request should authorize by target apiserver.
func NewAuthorizer(multiClusterEnabled bool) authorizer.Authorizer {
return authorizer.AuthorizerFunc(func(a authorizer.Attributes) (authorizer.Decision, string, error) {
// in multi cluster mode, the request will be dispatch.
if multiClusterEnabled && a.GetCluster() != "" {
return authorizer.DecisionAllow, "", nil
}
return authorizer.DecisionNoOpinion, "", nil
})
}
/*
Copyright 2018 The Kubernetes Authors.
Licensed 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 (
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer"
"testing"
)
func TestNewAuthorizer(t *testing.T) {
tests := []struct {
multiClusterEnabled bool
request authorizer.AttributesRecord
expectResult authorizer.Decision
}{
{
multiClusterEnabled: false,
request: authorizer.AttributesRecord{
Workspace: "ws",
Namespace: "ns",
KubernetesRequest: false,
ResourceRequest: false,
},
expectResult: authorizer.DecisionNoOpinion,
},
{
multiClusterEnabled: false,
request: authorizer.AttributesRecord{
Cluster: "cluster1",
Workspace: "ws",
Namespace: "ns",
KubernetesRequest: false,
ResourceRequest: false,
},
expectResult: authorizer.DecisionNoOpinion,
},
{
multiClusterEnabled: true,
request: authorizer.AttributesRecord{
Cluster: "cluster1",
Workspace: "ws",
Namespace: "ns",
KubernetesRequest: false,
ResourceRequest: false,
},
expectResult: authorizer.DecisionAllow,
},
{
multiClusterEnabled: true,
request: authorizer.AttributesRecord{
Workspace: "ws",
Namespace: "ns",
KubernetesRequest: false,
ResourceRequest: false,
},
expectResult: authorizer.DecisionNoOpinion,
},
}
for i, test := range tests {
a := NewAuthorizer(test.multiClusterEnabled)
result, _, _ := a.Authorize(test.request)
if result != test.expectResult {
t.Errorf("case %d, got %#v, expected %#v", i, result, test.expectResult)
}
}
}
......@@ -299,10 +299,6 @@ const (
func (r *RequestInfoFactory) resolveResourceScope(request RequestInfo) string {
if request.Cluster != "" {
return ClusterScope
}
if request.Namespace != "" {
return NamespaceScope
}
......@@ -311,5 +307,5 @@ func (r *RequestInfoFactory) resolveResourceScope(request RequestInfo) string {
return WorkspaceScope
}
return GlobalScope
return ClusterScope
}
......@@ -447,6 +447,7 @@ func (r *Controller) initRoles(workspace *tenantv1alpha2.WorkspaceTemplate) erro
}
// make sure workspace label always exist
role.Labels[tenantv1alpha1.WorkspaceLabel] = workspace.Name
role.Name = roleName
old, err := r.workspaceRoleLister.Get(roleName)
if err != nil {
if errors.IsNotFound(err) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册