Files
kubesphere/pkg/models/iam/am/am.go
hongming 8976ee242f remove useless go moudle
Signed-off-by: hongming <talonwan@yunify.com>
2020-04-29 10:28:25 +08:00

375 lines
12 KiB
Go

/*
*
* 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 (
"fmt"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
k8sinformers "k8s.io/client-go/informers"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
"kubesphere.io/kubesphere/pkg/apiserver/query"
ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/informers"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
"net/http"
)
type AccessManagementInterface interface {
GetGlobalRoleOfUser(username string) (*iamv1alpha2.GlobalRole, error)
GetWorkspaceRoleOfUser(username, workspace string) (*iamv1alpha2.WorkspaceRole, error)
GetClusterRoleOfUser(username, cluster string) (*rbacv1.ClusterRole, error)
GetNamespaceRoleOfUser(username, namespace string) (*rbacv1.Role, error)
ListRoles(username string, query *query.Query) (*api.ListResult, error)
ListClusterRoles(query *query.Query) (*api.ListResult, error)
ListWorkspaceRoles(query *query.Query) (*api.ListResult, error)
ListGlobalRoles(query *query.Query) (*api.ListResult, error)
ListGlobalRoleBindings(username string) ([]*iamv1alpha2.GlobalRoleBinding, error)
ListClusterRoleBindings(username string) ([]*rbacv1.ClusterRoleBinding, error)
ListWorkspaceRoleBindings(username, workspace string) ([]*iamv1alpha2.WorkspaceRoleBinding, error)
ListRoleBindings(username, namespace string) ([]*rbacv1.RoleBinding, error)
GetRoleReferenceRules(roleRef rbacv1.RoleRef, bindingNamespace string) ([]rbacv1.PolicyRule, error)
}
type amOperator struct {
ksinformer ksinformers.SharedInformerFactory
k8sinformer k8sinformers.SharedInformerFactory
resourceGetter *resourcev1alpha3.ResourceGetter
}
func NewAMOperator(factory informers.InformerFactory) AccessManagementInterface {
return &amOperator{
ksinformer: factory.KubeSphereSharedInformerFactory(),
k8sinformer: factory.KubernetesSharedInformerFactory(),
resourceGetter: resourcev1alpha3.NewResourceGetter(factory),
}
}
func (am *amOperator) GetGlobalRoleOfUser(username string) (*iamv1alpha2.GlobalRole, error) {
roleBindings, err := am.ksinformer.Iam().V1alpha2().GlobalRoleBindings().Lister().List(labels.Everything())
if err != nil {
klog.Error(err)
return nil, err
}
userRoleBindings := make([]*iamv1alpha2.GlobalRoleBinding, 0)
for _, roleBinding := range roleBindings {
if contains(roleBinding.Subjects, username) {
userRoleBindings = append(userRoleBindings, roleBinding)
}
}
if len(userRoleBindings) > 0 {
role, err := am.ksinformer.Iam().V1alpha2().GlobalRoles().Lister().Get(userRoleBindings[0].RoleRef.Name)
if err != nil {
klog.Error(err)
return nil, err
}
if len(roleBindings) > 1 {
klog.Warningf("conflict global role binding, username: %s", username)
}
return role, nil
}
err = &errors.StatusError{ErrStatus: metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusNotFound,
Reason: metav1.StatusReasonNotFound,
Details: &metav1.StatusDetails{
Group: iamv1alpha2.SchemeGroupVersion.Group,
Kind: iamv1alpha2.ResourceKindGlobalRoleBinding,
},
Message: fmt.Sprintf("global role binding not found for %s", username),
}}
return nil, err
}
func (am *amOperator) GetWorkspaceRoleOfUser(username, workspace string) (*iamv1alpha2.WorkspaceRole, error) {
roleBindings, err := am.ksinformer.Iam().V1alpha2().WorkspaceRoleBindings().Lister().List(labels.SelectorFromValidatedSet(labels.Set{tenantv1alpha1.WorkspaceLabel: workspace}))
if err != nil {
klog.Error(err)
return nil, err
}
userRoleBindings := make([]*iamv1alpha2.WorkspaceRoleBinding, 0)
for _, roleBinding := range roleBindings {
if contains(roleBinding.Subjects, username) {
userRoleBindings = append(userRoleBindings, roleBinding)
}
}
if len(userRoleBindings) > 0 {
role, err := am.ksinformer.Iam().V1alpha2().WorkspaceRoles().Lister().Get(userRoleBindings[0].RoleRef.Name)
if err != nil {
klog.Error(err)
return nil, err
}
if len(roleBindings) > 1 {
klog.Warningf("conflict workspace role binding, username: %s", username)
}
return role, nil
}
err = &errors.StatusError{ErrStatus: metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusNotFound,
Reason: metav1.StatusReasonNotFound,
Details: &metav1.StatusDetails{
Group: iamv1alpha2.SchemeGroupVersion.Group,
Kind: iamv1alpha2.ResourceKindWorkspaceRoleBinding,
},
Message: fmt.Sprintf("workspace role binding not found for %s", username),
}}
return nil, err
}
func (am *amOperator) GetNamespaceRoleOfUser(username, namespace string) (*rbacv1.Role, error) {
roleBindings, err := am.k8sinformer.Rbac().V1().RoleBindings().Lister().List(labels.Everything())
if err != nil {
klog.Error(err)
return nil, err
}
userRoleBindings := make([]*rbacv1.RoleBinding, 0)
for _, roleBinding := range roleBindings {
if contains(roleBinding.Subjects, username) {
userRoleBindings = append(userRoleBindings, roleBinding)
}
}
if len(userRoleBindings) > 0 {
role, err := am.k8sinformer.Rbac().V1().Roles().Lister().Roles(namespace).Get(userRoleBindings[0].RoleRef.Name)
if err != nil {
klog.Error(err)
return nil, err
}
if len(roleBindings) > 1 {
klog.Warningf("conflict role binding, username: %s", username)
}
return role, nil
}
err = &errors.StatusError{ErrStatus: metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusNotFound,
Reason: metav1.StatusReasonNotFound,
Details: &metav1.StatusDetails{
Group: rbacv1.SchemeGroupVersion.Group,
Kind: "RoleBinding",
},
Message: fmt.Sprintf("role binding not found for %s in %s", username, namespace),
}}
return nil, err
}
// Get federated clusterrole of user if cluster is not empty, if cluster is empty means current cluster
func (am *amOperator) GetClusterRoleOfUser(username, cluster string) (*rbacv1.ClusterRole, error) {
roleBindings, err := am.k8sinformer.Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
if err != nil {
klog.Error(err)
return nil, err
}
userRoleBindings := make([]*rbacv1.ClusterRoleBinding, 0)
for _, roleBinding := range roleBindings {
if contains(roleBinding.Subjects, username) {
userRoleBindings = append(userRoleBindings, roleBinding)
}
}
if len(userRoleBindings) > 0 {
role, err := am.k8sinformer.Rbac().V1().ClusterRoles().Lister().Get(userRoleBindings[0].RoleRef.Name)
if err != nil {
klog.Error(err)
return nil, err
}
if len(roleBindings) > 1 {
klog.Warningf("conflict cluster role binding, username: %s", username)
}
return role, nil
}
err = &errors.StatusError{ErrStatus: metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusNotFound,
Reason: metav1.StatusReasonNotFound,
Details: &metav1.StatusDetails{
Group: rbacv1.SchemeGroupVersion.Group,
Kind: "ClusterRoleBinding",
},
Message: fmt.Sprintf("cluster role binding not found for %s in %s", username, cluster),
}}
return nil, err
}
func (am *amOperator) ListWorkspaceRoleBindings(username, workspace string) ([]*iamv1alpha2.WorkspaceRoleBinding, error) {
roleBindings, err := am.ksinformer.Iam().V1alpha2().WorkspaceRoleBindings().Lister().List(labels.Everything())
if err != nil {
return nil, err
}
result := make([]*iamv1alpha2.WorkspaceRoleBinding, 0)
for _, roleBinding := range roleBindings {
inSpecifiedWorkspace := workspace == "" || roleBinding.Labels[tenantv1alpha1.WorkspaceLabel] == workspace
if contains(roleBinding.Subjects, username) && inSpecifiedWorkspace {
result = append(result, roleBinding)
}
}
return result, nil
}
func (am *amOperator) ListClusterRoleBindings(username string) ([]*rbacv1.ClusterRoleBinding, error) {
roleBindings, err := am.k8sinformer.Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
if err != nil {
return nil, err
}
result := make([]*rbacv1.ClusterRoleBinding, 0)
for _, roleBinding := range roleBindings {
if contains(roleBinding.Subjects, username) {
result = append(result, roleBinding)
}
}
return result, nil
}
func (am *amOperator) ListGlobalRoleBindings(username string) ([]*iamv1alpha2.GlobalRoleBinding, error) {
roleBindings, err := am.ksinformer.Iam().V1alpha2().GlobalRoleBindings().Lister().List(labels.Everything())
if err != nil {
return nil, err
}
result := make([]*iamv1alpha2.GlobalRoleBinding, 0)
for _, roleBinding := range roleBindings {
if contains(roleBinding.Subjects, username) {
result = append(result, roleBinding)
}
}
return result, nil
}
func (am *amOperator) ListRoleBindings(username, namespace string) ([]*rbacv1.RoleBinding, error) {
roleBindings, err := am.k8sinformer.Rbac().V1().RoleBindings().Lister().RoleBindings(namespace).List(labels.Everything())
if err != nil {
klog.Error(err)
return nil, err
}
result := make([]*rbacv1.RoleBinding, 0)
for _, roleBinding := range roleBindings {
if contains(roleBinding.Subjects, username) {
result = append(result, roleBinding)
}
}
return result, nil
}
func contains(subjects []rbacv1.Subject, username string) bool {
for _, subject := range subjects {
if subject.Kind == rbacv1.UserKind && (username == "" || subject.Name == username) {
return true
}
}
return false
}
func (am *amOperator) ListRoles(namespace string, query *query.Query) (*api.ListResult, error) {
return am.resourceGetter.List("roles", namespace, query)
}
func (am *amOperator) ListClusterRoles(query *query.Query) (*api.ListResult, error) {
return am.resourceGetter.List("clusterroles", "", query)
}
func (am *amOperator) ListWorkspaceRoles(queryParam *query.Query) (*api.ListResult, error) {
return am.resourceGetter.List(iamv1alpha2.ResourcesPluralWorkspaceRole, "", queryParam)
}
func (am *amOperator) ListGlobalRoles(query *query.Query) (*api.ListResult, error) {
return am.resourceGetter.List(iamv1alpha2.ResourcesPluralGlobalRole, "", query)
}
// GetRoleReferenceRules attempts to resolve the RoleBinding or ClusterRoleBinding.
func (am *amOperator) GetRoleReferenceRules(roleRef rbacv1.RoleRef, bindingNamespace string) ([]rbacv1.PolicyRule, error) {
switch roleRef.Kind {
case iamv1alpha2.ResourceKindRole:
role, err := am.k8sinformer.Rbac().V1().Roles().Lister().Roles(bindingNamespace).Get(roleRef.Name)
if err != nil {
return nil, err
}
return role.Rules, nil
case iamv1alpha2.ResourceKindClusterRole:
clusterRole, err := am.k8sinformer.Rbac().V1().ClusterRoles().Lister().Get(roleRef.Name)
if err != nil {
return nil, err
}
return clusterRole.Rules, nil
case iamv1alpha2.ResourceKindGlobalRole:
globalRole, err := am.ksinformer.Iam().V1alpha2().GlobalRoles().Lister().Get(roleRef.Name)
if err != nil {
return nil, err
}
return globalRole.Rules, nil
case iamv1alpha2.ResourceKindWorkspaceRole:
workspaceRole, err := am.ksinformer.Iam().V1alpha2().WorkspaceRoles().Lister().Get(roleRef.Name)
if err != nil {
return nil, err
}
return workspaceRole.Rules, nil
default:
return nil, fmt.Errorf("unsupported role reference kind: %q", roleRef.Kind)
}
}