未验证 提交 1f26e621 编写于 作者: H hongming

update

Signed-off-by: Nhongming <talonwan@yunify.com>
上级 97693570
......@@ -39,16 +39,12 @@ define ALL_HELP_INFO
# debugging tools like delve.
endef
.PHONY: all
all: test hypersphere ks-apiserver ks-apigateway controller-manager
all: test hypersphere ks-apiserver controller-manager
# Build ks-apiserver binary
ks-apiserver: fmt vet
hack/gobuild.sh cmd/ks-apiserver
# Build ks-apigateway binary
ks-apigateway: fmt vet
hack/gobuild.sh cmd/ks-apigateway
# Build controller-manager binary
controller-manager: fmt vet
hack/gobuild.sh cmd/controller-manager
......
# Copyright 2018 The KubeSphere Authors. All rights reserved.
# Use of this source code is governed by a Apache license
# that can be found in the LICENSE file.
# Copyright 2018 The KubeSphere Authors. All rights reserved.
# Use of this source code is governed by a Apache license
# that can be found in the LICENSE file.
FROM golang:1.12 as ks-apigateway-builder
COPY / /go/src/kubesphere.io/kubesphere
WORKDIR /go/src/kubesphere.io/kubesphere
RUN CGO_ENABLED=0 GO111MODULE=on GOOS=linux GOARCH=amd64 GOFLAGS=-mod=vendor go build -i -ldflags '-w -s' -o ks-apigateway cmd/ks-apigateway/apiserver.go && \
go run tools/cmd/doc-gen/main.go --output=install/swagger-ui/api.json
FROM alpine:3.9
RUN apk add --update ca-certificates && update-ca-certificates
COPY --from=ks-apigateway-builder /go/src/kubesphere.io/kubesphere/ks-apigateway /usr/local/bin/
COPY --from=ks-apigateway-builder /go/src/kubesphere.io/kubesphere/install/swagger-ui /var/static/swagger-ui
CMD ["sh"]
# Copyright 2018 The KubeSphere Authors. All rights reserved.
# Use of this source code is governed by a Apache license
# that can be found in the LICENSE file.
# Copyright 2018 The KubeSphere Authors. All rights reserved.
# Use of this source code is governed by a Apache license
# that can be found in the LICENSE file.
FROM golang:1.12 as ks-iam-builder
COPY / /go/src/kubesphere.io/kubesphere
WORKDIR /go/src/kubesphere.io/kubesphere
RUN CGO_ENABLED=0 GO111MODULE=on GOOS=linux GOARCH=amd64 GOFLAGS=-mod=vendor go build -i -ldflags '-w -s' -o ks-iam cmd/ks-iam/apiserver.go
FROM alpine:3.9
RUN apk add --update ca-certificates && update-ca-certificates
COPY --from=ks-iam-builder /go/src/kubesphere.io/kubesphere/ks-iam /usr/local/bin/
CMD ["sh"]
......@@ -46,6 +46,8 @@ func NewAPIServerCommand() *cobra.Command {
S3Options: conf.S3Options,
OpenPitrixOptions: conf.OpenPitrixOptions,
LoggingOptions: conf.LoggingOptions,
LdapOptions: conf.LdapOptions,
CacheOptions: conf.RedisOptions,
AuthenticateOptions: conf.AuthenticateOptions,
}
}
......
......@@ -187,7 +187,7 @@ func (s *APIServer) buildHandlerChain() {
excludedPaths := []string{"/oauth/authorize", "/oauth/token"}
pathAuthorizer, _ := path.NewAuthorizer(excludedPaths)
authorizer := unionauthorizer.New(pathAuthorizer, authorizerfactory.NewOPAAuthorizer(am.NewAMOperator(s.KubernetesClient.Kubernetes(), s.InformerFactory.KubernetesSharedInformerFactory())))
authorizer := unionauthorizer.New(pathAuthorizer, authorizerfactory.NewOPAAuthorizer(am.NewFakeAMOperator(cache.NewSimpleCache())))
handler = filters.WithAuthorization(handler, authorizer)
handler = filters.WithMultipleClusterDispatcher(handler, dispatch.DefaultClusterDispatch)
handler = filters.WithKubeAPIServer(handler, s.KubernetesClient.Config(), &errorResponder{})
......
......@@ -48,9 +48,6 @@ type Attributes interface {
// The namespace of the object, if a request is for a REST object.
GetNamespace() string
// The devops project of the object, if a request is for a REST object.
GetDevopsProject() string
// The kind of object, if a request is for a REST object.
GetResource() string
......@@ -106,7 +103,6 @@ type AttributesRecord struct {
Cluster string
Workspace string
Namespace string
DevopsProject string
APIGroup string
APIVersion string
Resource string
......@@ -141,10 +137,6 @@ func (a AttributesRecord) GetNamespace() string {
return a.Namespace
}
func (a AttributesRecord) GetDevopsProject() string {
return a.DevopsProject
}
func (a AttributesRecord) GetResource() string {
return a.Resource
}
......
......@@ -22,79 +22,68 @@ import (
"context"
"github.com/open-policy-agent/opa/rego"
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer"
am2 "kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/iam/am"
)
type opaAuthorizer struct {
am am2.AccessManagementInterface
am am.AccessManagementInterface
}
func (o *opaAuthorizer) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
func (o *opaAuthorizer) Authorize(attr authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
platformRole, err := o.am.GetPlatformRole(a.GetUser().GetName())
platformRole, err := o.am.GetPlatformRole(attr.GetUser().GetName())
if err != nil {
return authorizer.DecisionDeny, "", err
}
// check platform role policy rules
if a, r, e := o.roleAuthorize(platformRole, a); a == authorizer.DecisionAllow {
if a, r, e := makeDecision(platformRole, attr); a == authorizer.DecisionAllow {
return a, r, e
}
// it's not in cluster resource, permission denied
// TODO declare implicit cluster info in request Info
if a.GetCluster() == "" {
if attr.GetCluster() == "" {
return authorizer.DecisionDeny, "permission undefined", nil
}
clusterRole, err := o.am.GetClusterRole(a.GetCluster(), a.GetUser().GetName())
clusterRole, err := o.am.GetClusterRole(attr.GetCluster(), attr.GetUser().GetName())
if err != nil {
return authorizer.DecisionDeny, "", err
}
// check cluster role policy rules
if a, r, e := o.roleAuthorize(clusterRole, a); a == authorizer.DecisionAllow {
if a, r, e := makeDecision(clusterRole, attr); a == authorizer.DecisionAllow {
return a, r, e
}
// it's not in cluster resource, permission denied
if a.GetWorkspace() == "" && a.GetNamespace() == "" && a.GetDevopsProject() == "" {
if attr.GetWorkspace() == "" && attr.GetNamespace() == "" {
return authorizer.DecisionDeny, "permission undefined", nil
}
workspaceRole, err := o.am.GetWorkspaceRole(a.GetWorkspace(), a.GetUser().GetName())
workspaceRole, err := o.am.GetWorkspaceRole(attr.GetWorkspace(), attr.GetUser().GetName())
if err != nil {
return authorizer.DecisionDeny, "", err
}
// check workspace role policy rules
if a, r, e := o.roleAuthorize(workspaceRole, a); a == authorizer.DecisionAllow {
if a, r, e := makeDecision(workspaceRole, attr); a == authorizer.DecisionAllow {
return a, r, e
}
// it's not in workspace resource, permission denied
if a.GetNamespace() == "" && a.GetDevopsProject() == "" {
if attr.GetNamespace() == "" {
return authorizer.DecisionDeny, "permission undefined", nil
}
if a.GetNamespace() != "" {
namespaceRole, err := o.am.GetNamespaceRole(a.GetNamespace(), a.GetUser().GetName())
if attr.GetNamespace() != "" {
namespaceRole, err := o.am.GetNamespaceRole(attr.GetNamespace(), attr.GetUser().GetName())
if err != nil {
return authorizer.DecisionDeny, "", err
}
// check namespace role policy rules
if a, r, e := o.roleAuthorize(namespaceRole, a); a == authorizer.DecisionAllow {
return a, r, e
}
}
if a.GetDevopsProject() != "" {
devOpsRole, err := o.am.GetDevOpsRole(a.GetNamespace(), a.GetUser().GetName())
if err != nil {
return authorizer.DecisionDeny, "", err
}
// check devops role policy rules
if a, r, e := o.roleAuthorize(devOpsRole, a); a == authorizer.DecisionAllow {
if a, r, e := makeDecision(namespaceRole, attr); a == authorizer.DecisionAllow {
return a, r, e
}
}
......@@ -102,14 +91,18 @@ func (o *opaAuthorizer) Authorize(a authorizer.Attributes) (authorized authorize
return authorizer.DecisionDeny, "", nil
}
func (o *opaAuthorizer) roleAuthorize(role am2.Role, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
// Make decision base on role
func makeDecision(role am.Role, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
// Call the rego.New function to create an object that can be prepared or evaluated
// After constructing a new rego.Rego object you can call PrepareForEval() to obtain an executable query
query, err := rego.New(rego.Query("data.authz.allow"), rego.Module("authz.rego", role.GetRego())).PrepareForEval(context.Background())
if err != nil {
return authorizer.DecisionDeny, "", err
}
// The policy decision is contained in the results returned by the Eval() call. You can inspect the decision and handle it accordingly.
results, err := query.Eval(context.Background(), rego.EvalInput(a))
if err != nil {
......@@ -123,6 +116,6 @@ func (o *opaAuthorizer) roleAuthorize(role am2.Role, a authorizer.Attributes) (a
return authorizer.DecisionDeny, "permission undefined", nil
}
func NewOPAAuthorizer(am am2.AccessManagementInterface) *opaAuthorizer {
func NewOPAAuthorizer(am am.AccessManagementInterface) *opaAuthorizer {
return &opaAuthorizer{am: am}
}
......@@ -19,66 +19,79 @@
package authorizerfactory
import (
"context"
"github.com/open-policy-agent/opa/rego"
"k8s.io/apiserver/pkg/authentication/user"
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer"
"kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
"testing"
)
func TestPlatformRole(t *testing.T) {
module := `package platform.authz
default allow = false
opa := NewOPAAuthorizer(am.NewFakeAMOperator(cache.NewSimpleCache()))
allow {
input.User.name == "admin"
}
allow {
is_admin
}
is_admin {
input.User.Groups[_] == "admin"
}
`
query, err := rego.New(rego.Query("data.authz.allow"), rego.Module("authz.rego", module)).PrepareForEval(context.Background())
if err != nil {
t.Fatal(err)
}
input := authorizer.AttributesRecord{
User: &user.DefaultInfo{
Name: "admin",
UID: "0",
Groups: []string{"admin"},
Extra: nil,
tests := []struct {
name string
request authorizer.AttributesRecord
expectedDecision authorizer.Decision
}{
{
name: "list nodes",
request: authorizer.AttributesRecord{
User: &user.DefaultInfo{
Name: "admin",
UID: "0",
Groups: []string{"admin"},
Extra: nil,
},
Verb: "list",
Cluster: "",
Workspace: "",
Namespace: "",
APIGroup: "",
APIVersion: "v1",
Resource: "nodes",
Subresource: "",
Name: "",
KubernetesRequest: true,
ResourceRequest: true,
Path: "/api/v1/nodes",
},
expectedDecision: authorizer.DecisionAllow,
},
{
name: "list nodes",
request: authorizer.AttributesRecord{
User: &user.DefaultInfo{
Name: user.Anonymous,
UID: "0",
Groups: []string{"admin"},
Extra: nil,
},
Verb: "list",
Cluster: "",
Workspace: "",
Namespace: "",
APIGroup: "",
APIVersion: "v1",
Resource: "nodes",
Subresource: "",
Name: "",
KubernetesRequest: true,
ResourceRequest: true,
Path: "/api/v1/nodes",
},
expectedDecision: authorizer.DecisionDeny,
},
Verb: "list",
Cluster: "",
Workspace: "",
Namespace: "",
DevopsProject: "",
APIGroup: "",
APIVersion: "v1",
Resource: "nodes",
Subresource: "",
Name: "",
KubernetesRequest: true,
ResourceRequest: true,
Path: "/api/v1/nodes",
}
results, err := query.Eval(context.Background(), rego.EvalInput(input))
if err != nil {
t.Log(err)
}
if len(results) > 0 && results[0].Expressions[0].Value == true {
t.Log("allowed")
} else {
t.Log("deny")
for _, test := range tests {
decision, _, err := opa.Authorize(test.request)
if err != nil {
t.Error(err)
}
if decision != test.expectedDecision {
t.Errorf("%s: expected decision %v, actual %+v", test.name, test.expectedDecision, decision)
}
}
}
......@@ -64,7 +64,7 @@ func newTestConfig() *Config {
GroupSearchBase: "ou=Groups,dc=example,dc=org",
},
RedisOptions: &cache.Options{
Host: "localhost:6379",
Host: "localhost",
Port: 6379,
Password: "P@88w0rd",
DB: 0,
......
......@@ -68,7 +68,6 @@ func GetAuthorizerAttributes(ctx context.Context) (authorizer.Attributes, error)
attribs.Resource = requestInfo.Resource
attribs.Subresource = requestInfo.Subresource
attribs.Namespace = requestInfo.Namespace
attribs.DevopsProject = requestInfo.DevopsProject
attribs.Name = requestInfo.Name
return &attribs, nil
......
......@@ -3,7 +3,11 @@ package request
import (
"context"
"fmt"
"k8s.io/apimachinery/pkg/api/validation/path"
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/klog"
"net/http"
"strings"
......@@ -19,6 +23,13 @@ type RequestInfoResolver interface {
// master's Mux.
var specialVerbs = sets.NewString("proxy", "watch")
// specialVerbsNoSubresources contains root verbs which do not allow subresources
var specialVerbsNoSubresources = sets.NewString("proxy")
// namespaceSubresources contains subresources of namespace
// this list allows the parser to distinguish between a namespace subresource, and a namespaced resource
var namespaceSubresources = sets.NewString("status", "finalize")
var kubernetesAPIPrefixes = sets.NewString("api", "apis")
// RequestInfo holds information parsed from the http.Request,
......@@ -34,9 +45,6 @@ type RequestInfo struct {
// Cluster of requested resource, this is empty in single-cluster environment
Cluster string
// Devops project of requested resource, this may be empty
DevopsProject string
}
type RequestInfoFactory struct {
......@@ -101,16 +109,9 @@ func (r *RequestInfoFactory) NewRequestInfo(req *http.Request) (*RequestInfo, er
currentParts = currentParts[1:]
if !r.GrouplessAPIPrefixes.Has(requestInfo.APIPrefix) {
if len(currentParts) < 2 {
return &requestInfo, nil
}
if currentParts[0] == "clusters" {
requestInfo.Cluster = currentParts[1]
currentParts = currentParts[2:]
}
// one part (APIPrefix) has already been consumed, so this is actually "do we have four parts?"
if len(currentParts) < 3 {
// return a non-resource request
return &requestInfo, nil
}
......@@ -122,6 +123,18 @@ func (r *RequestInfoFactory) NewRequestInfo(req *http.Request) (*RequestInfo, er
requestInfo.APIVersion = currentParts[0]
currentParts = currentParts[1:]
if currentParts[0] == "clusters" {
requestInfo.Cluster = currentParts[1]
currentParts = currentParts[2:]
} else if len(currentParts) > 0 {
requestInfo.Cluster = "host-cluster"
}
if currentParts[0] == "workspaces" {
requestInfo.Workspace = currentParts[1]
currentParts = currentParts[2:]
}
if specialVerbs.Has(currentParts[0]) {
if len(currentParts) < 2 {
return &requestInfo, fmt.Errorf("unable to determine kind and namespace from url: %v", req.URL)
......@@ -146,6 +159,73 @@ func (r *RequestInfoFactory) NewRequestInfo(req *http.Request) (*RequestInfo, er
}
}
// URL forms: /namespaces/{namespace}/{kind}/*, where parts are adjusted to be relative to kind
if currentParts[0] == "namespaces" {
if len(currentParts) > 1 {
requestInfo.Namespace = currentParts[1]
// if there is another step after the namespace name and it is not a known namespace subresource
// move currentParts to include it as a resource in its own right
if len(currentParts) > 2 && !namespaceSubresources.Has(currentParts[2]) {
currentParts = currentParts[2:]
}
}
} else {
requestInfo.Namespace = metav1.NamespaceNone
}
// parsing successful, so we now know the proper value for .Parts
requestInfo.Parts = currentParts
// parts look like: resource/resourceName/subresource/other/stuff/we/don't/interpret
switch {
case len(requestInfo.Parts) >= 3 && !specialVerbsNoSubresources.Has(requestInfo.Verb):
requestInfo.Subresource = requestInfo.Parts[2]
fallthrough
case len(requestInfo.Parts) >= 2:
requestInfo.Name = requestInfo.Parts[1]
fallthrough
case len(requestInfo.Parts) >= 1:
requestInfo.Resource = requestInfo.Parts[0]
}
// if there's no name on the request and we thought it was a get before, then the actual verb is a list or a watch
if len(requestInfo.Name) == 0 && requestInfo.Verb == "get" {
opts := metainternalversion.ListOptions{}
if err := metainternalversion.ParameterCodec.DecodeParameters(req.URL.Query(), metav1.SchemeGroupVersion, &opts); err != nil {
// An error in parsing request will result in default to "list" and not setting "name" field.
klog.Errorf("Couldn't parse request %#v: %v", req.URL.Query(), err)
// Reset opts to not rely on partial results from parsing.
// However, if watch is set, let's report it.
opts = metainternalversion.ListOptions{}
if values := req.URL.Query()["watch"]; len(values) > 0 {
switch strings.ToLower(values[0]) {
case "false", "0":
default:
opts.Watch = true
}
}
}
if opts.Watch {
requestInfo.Verb = "watch"
} else {
requestInfo.Verb = "list"
}
if opts.FieldSelector != nil {
if name, ok := opts.FieldSelector.RequiresExactMatch("metadata.name"); ok {
if len(path.IsValidPathSegmentName(name)) == 0 {
requestInfo.Name = name
}
}
}
}
// if there's no name on the request and we thought it was a delete before, then the actual verb is deletecollection
if len(requestInfo.Name) == 0 && requestInfo.Verb == "delete" {
requestInfo.Verb = "deletecollection"
}
return &requestInfo, nil
}
......
......@@ -43,6 +43,8 @@ func TestRequestInfoFactory_NewRequestInfo(t *testing.T) {
expectedResource string
expectedIsResourceRequest bool
expectedCluster string
expectedWorkspace string
exceptedNamespace string
}{
{
name: "login",
......@@ -54,15 +56,88 @@ func TestRequestInfoFactory_NewRequestInfo(t *testing.T) {
expectedIsResourceRequest: false,
expectedCluster: "",
},
{
name: "list cluster roles",
url: "/apis/rbac.authorization.k8s.io/v1/clusters/cluster1/clusterroles",
method: http.MethodGet,
expectedErr: nil,
expectedVerb: "list",
expectedResource: "clusterroles",
expectedIsResourceRequest: true,
expectedCluster: "cluster1",
},
{
name: "list cluster nodes",
url: "/api/v1/clusters/cluster1/nodes",
method: http.MethodGet,
expectedErr: nil,
expectedVerb: "list",
expectedResource: "nodes",
expectedIsResourceRequest: true,
expectedCluster: "cluster1",
},
{
name: "list cluster nodes",
url: "/api/v1/clusters/cluster1/nodes",
method: http.MethodGet,
expectedErr: nil,
expectedVerb: "list",
expectedResource: "nodes",
expectedIsResourceRequest: true,
expectedCluster: "cluster1",
},
{
name: "list cluster nodes",
url: "/api/v1/nodes",
method: http.MethodGet,
expectedErr: nil,
expectedVerb: "list",
expectedResource: "nodes",
expectedIsResourceRequest: true,
expectedCluster: "host-cluster",
},
{
name: "list roles",
url: "/apis/rbac.authorization.k8s.io/v1/clusters/cluster1/namespaces/namespace1/roles",
method: http.MethodGet,
expectedErr: nil,
expectedVerb: "list",
expectedResource: "roles",
expectedIsResourceRequest: true,
exceptedNamespace: "namespace1",
expectedCluster: "cluster1",
},
{
name: "list roles",
url: "/apis/rbac.authorization.k8s.io/v1/namespaces/namespace1/roles",
method: http.MethodGet,
expectedErr: nil,
expectedVerb: "list",
expectedResource: "roles",
expectedIsResourceRequest: true,
expectedCluster: "host-cluster",
},
{
name: "list namespaces",
url: "/kapis/resources.kubesphere.io/v1alpha2/namespaces",
url: "/kapis/resources.kubesphere.io/v1alpha3/workspaces/workspace1/namespaces",
method: http.MethodGet,
expectedErr: nil,
expectedVerb: "list",
expectedResource: "namespaces",
expectedIsResourceRequest: true,
expectedCluster: "",
expectedWorkspace: "workspace1",
expectedCluster: "host-cluster",
},
{
name: "list namespaces",
url: "/kapis/resources.kubesphere.io/v1alpha3/clusters/cluster1/workspaces/workspace1/namespaces",
method: http.MethodGet,
expectedErr: nil,
expectedVerb: "list",
expectedResource: "namespaces",
expectedIsResourceRequest: true,
expectedWorkspace: "workspace1",
expectedCluster: "cluster1",
},
}
......@@ -80,15 +155,24 @@ func TestRequestInfoFactory_NewRequestInfo(t *testing.T) {
t.Errorf("%s: expected error %v, actual %v", test.name, test.expectedErr, err)
}
} else {
if test.expectedVerb != requestInfo.Verb {
if test.expectedVerb != "" && test.expectedVerb != requestInfo.Verb {
t.Errorf("%s: expected verb %v, actual %+v", test.name, test.expectedVerb, requestInfo.Verb)
}
if test.expectedResource != requestInfo.Resource {
if test.expectedResource != "" && test.expectedResource != requestInfo.Resource {
t.Errorf("%s: expected resource %v, actual %+v", test.name, test.expectedResource, requestInfo.Resource)
}
if test.expectedIsResourceRequest != requestInfo.IsResourceRequest {
t.Errorf("%s: expected is resource request %v, actual %+v", test.name, test.expectedIsResourceRequest, requestInfo.IsResourceRequest)
}
if test.expectedCluster != "" && test.expectedCluster != requestInfo.Cluster {
t.Errorf("%s: expected cluster %v, actual %+v", test.name, test.expectedCluster, requestInfo.Cluster)
}
if test.expectedWorkspace != "" && test.expectedWorkspace != requestInfo.Workspace {
t.Errorf("%s: expected workspace %v, actual %+v", test.name, test.expectedWorkspace, requestInfo.Workspace)
}
if test.exceptedNamespace != "" && test.exceptedNamespace != requestInfo.Namespace {
t.Errorf("%s: expected namespace %v, actual %+v", test.name, test.exceptedNamespace, requestInfo.Namespace)
}
}
}
}
......@@ -8,7 +8,7 @@ import (
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
am2 "kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/monitoring"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/models/tenant"
......@@ -21,14 +21,14 @@ import (
type tenantHandler struct {
tenant tenant.Interface
am am2.AccessManagementInterface
am am.AccessManagementInterface
}
func newTenantHandler(k8sClient k8s.Client, factory informers.InformerFactory, db *mysql.Database) *tenantHandler {
return &tenantHandler{
tenant: tenant.New(k8sClient.Kubernetes(), factory.KubernetesSharedInformerFactory(), factory.KubeSphereSharedInformerFactory(), db),
am: am2.NewAMOperator(k8sClient.Kubernetes(), factory.KubernetesSharedInformerFactory()),
am: am.NewAMOperator(k8sClient.Kubernetes(), factory.KubernetesSharedInformerFactory()),
}
}
......
......@@ -18,7 +18,6 @@
package am
import (
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
......@@ -38,7 +37,6 @@ type AccessManagementInterface interface {
GetClusterRole(cluster, username string) (Role, error)
GetWorkspaceRole(workspace, username string) (Role, error)
GetNamespaceRole(namespace, username string) (Role, error)
GetDevOpsRole(project, username string) (Role, error)
}
type Role interface {
......@@ -52,26 +50,6 @@ type amOperator struct {
kubeClient kubernetes.Interface
}
func (am *amOperator) ListClusterRoleBindings(clusterRole string) ([]*rbacv1.ClusterRoleBinding, error) {
panic("implement me")
}
func (am *amOperator) GetRoles(namespace, username string) ([]*rbacv1.Role, error) {
panic("implement me")
}
func (am *amOperator) GetClusterPolicyRules(username string) ([]rbacv1.PolicyRule, error) {
panic("implement me")
}
func (am *amOperator) GetPolicyRules(namespace, username string) ([]rbacv1.PolicyRule, error) {
panic("implement me")
}
func (am *amOperator) GetWorkspaceRole(workspace, username string) (Role, error) {
panic("implement me")
}
func NewAMOperator(kubeClient kubernetes.Interface, informers informers.SharedInformerFactory) AccessManagementInterface {
resourceGetter := resource.ResourceGetter{}
resourceGetter.Add(v1alpha2.Role, role.NewRoleSearcher(informers))
......@@ -91,6 +69,10 @@ func (am *amOperator) GetClusterRole(cluster, username string) (Role, error) {
panic("implement me")
}
func (am *amOperator) GetWorkspaceRole(workspace, username string) (Role, error) {
panic("implement me")
}
func (am *amOperator) GetNamespaceRole(namespace, username string) (Role, error) {
panic("implement me")
}
......
/*
*
* 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 am
import (
"k8s.io/apiserver/pkg/authentication/user"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
)
type fakeRole struct {
Name string
Rego string
}
type fakeOperator struct {
cache cache.Interface
}
func newFakeRole(username string) Role {
if username == user.Anonymous {
return &fakeRole{
Name: "anonymous",
Rego: "package authz\ndefault allow = false",
}
}
return &fakeRole{
Name: "admin",
Rego: "package authz\ndefault allow = true",
}
}
func (f fakeOperator) GetPlatformRole(username string) (Role, error) {
return newFakeRole(username), nil
}
func (f fakeOperator) GetClusterRole(cluster, username string) (Role, error) {
return newFakeRole(username), nil
}
func (f fakeOperator) GetWorkspaceRole(workspace, username string) (Role, error) {
return newFakeRole(username), nil
}
func (f fakeOperator) GetNamespaceRole(namespace, username string) (Role, error) {
return newFakeRole(username), nil
}
func (f fakeRole) GetName() string {
return f.Name
}
func (f fakeRole) GetRego() string {
return f.Rego
}
func NewFakeAMOperator(cache cache.Interface) AccessManagementInterface {
return &fakeOperator{cache: cache}
}
......@@ -20,9 +20,9 @@ package tenant
import (
"k8s.io/api/core/v1"
k8sinformers "k8s.io/client-go/informers"
kubernetes "k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/constants"
am2 "kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
......@@ -37,7 +37,7 @@ type NamespaceInterface interface {
type namespaceSearcher struct {
k8s kubernetes.Interface
informers k8sinformers.SharedInformerFactory
am am2.AccessManagementInterface
am am.AccessManagementInterface
}
func (s *namespaceSearcher) CreateNamespace(workspace string, namespace *v1.Namespace, username string) (*v1.Namespace, error) {
......@@ -53,7 +53,7 @@ func (s *namespaceSearcher) CreateNamespace(workspace string, namespace *v1.Name
return s.k8s.CoreV1().Namespaces().Create(namespace)
}
func newNamespaceOperator(k8s kubernetes.Interface, informers k8sinformers.SharedInformerFactory, am am2.AccessManagementInterface) NamespaceInterface {
func newNamespaceOperator(k8s kubernetes.Interface, informers k8sinformers.SharedInformerFactory, am am.AccessManagementInterface) NamespaceInterface {
return &namespaceSearcher{k8s: k8s, informers: informers, am: am}
}
......
......@@ -24,7 +24,7 @@ import (
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/models"
am2 "kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
)
......@@ -43,7 +43,7 @@ type Interface interface {
type tenantOperator struct {
workspaces WorkspaceInterface
namespaces NamespaceInterface
am am2.AccessManagementInterface
am am.AccessManagementInterface
devops DevOpsProjectOperator
}
......@@ -68,7 +68,7 @@ func (t *tenantOperator) DeleteNamespace(workspace, namespace string) error {
}
func New(client kubernetes.Interface, informers k8sinformers.SharedInformerFactory, ksinformers ksinformers.SharedInformerFactory, db *mysql.Database) Interface {
amOperator := am2.NewAMOperator(client, informers)
amOperator := am.NewAMOperator(client, informers)
return &tenantOperator{
workspaces: newWorkspaceOperator(client, informers, ksinformers, amOperator, db),
namespaces: newNamespaceOperator(client, informers, amOperator),
......
......@@ -27,7 +27,7 @@ import (
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/db"
"kubesphere.io/kubesphere/pkg/models/devops"
am2 "kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
......@@ -64,14 +64,14 @@ type workspaceOperator struct {
client kubernetes.Interface
informers informers.SharedInformerFactory
ksInformers externalversions.SharedInformerFactory
am am2.AccessManagementInterface
am am.AccessManagementInterface
// TODO: use db interface instead of mysql client
// we can refactor this after rewrite devops using crd
db *mysql.Database
}
func newWorkspaceOperator(client kubernetes.Interface, informers informers.SharedInformerFactory, ksinformers externalversions.SharedInformerFactory, am am2.AccessManagementInterface, db *mysql.Database) WorkspaceInterface {
func newWorkspaceOperator(client kubernetes.Interface, informers informers.SharedInformerFactory, ksinformers externalversions.SharedInformerFactory, am am.AccessManagementInterface, db *mysql.Database) WorkspaceInterface {
return &workspaceOperator{
client: client,
informers: informers,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册