@@ -19,103 +19,81 @@ 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"
|
||||
kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
|
||||
informers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
|
||||
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 {
|
||||
ListRolesOfUser(scope iamv1alpha2.Scope, username string) ([]iamv1alpha2.Role, error)
|
||||
GetRoleOfUserInTargetScope(scope iamv1alpha2.Scope, target string, username string) (*iamv1alpha2.Role, error)
|
||||
GetPolicyRule(name string) (*iamv1alpha2.PolicyRule, error)
|
||||
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 {
|
||||
informers informers.SharedInformerFactory
|
||||
ksClient kubesphere.Interface
|
||||
ksinformer ksinformers.SharedInformerFactory
|
||||
k8sinformer k8sinformers.SharedInformerFactory
|
||||
resourceGetter *resourcev1alpha3.ResourceGetter
|
||||
}
|
||||
|
||||
func NewAMOperator(ksClient kubesphere.Interface, informers informers.SharedInformerFactory) AccessManagementInterface {
|
||||
func NewAMOperator(factory informers.InformerFactory) AccessManagementInterface {
|
||||
return &amOperator{
|
||||
informers: informers,
|
||||
ksClient: ksClient,
|
||||
ksinformer: factory.KubeSphereSharedInformerFactory(),
|
||||
k8sinformer: factory.KubernetesSharedInformerFactory(),
|
||||
resourceGetter: resourcev1alpha3.NewResourceGetter(factory),
|
||||
}
|
||||
}
|
||||
|
||||
func containsUser(subjets []iamv1alpha2.Subject, username string) bool {
|
||||
for _, sub := range subjets {
|
||||
if sub.Kind == iamv1alpha2.UserKind && sub.Name == username {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (am *amOperator) GetGlobalRoleOfUser(username string) (*iamv1alpha2.GlobalRole, error) {
|
||||
|
||||
func (am *amOperator) ListRolesOfUser(scope iamv1alpha2.Scope, username string) ([]iamv1alpha2.Role, error) {
|
||||
|
||||
lister := am.informers.Iam().V1alpha2().RoleBindings().Lister()
|
||||
|
||||
roleBindings, err := lister.List(labels.Everything())
|
||||
roleBindings, err := am.ksinformer.Iam().V1alpha2().GlobalRoleBindings().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roleBindingsInScope := filterRoleBindingByScope(roleBindings, scope)
|
||||
userRoleBindings := make([]*iamv1alpha2.GlobalRoleBinding, 0)
|
||||
|
||||
roles := make([]iamv1alpha2.Role, 0)
|
||||
|
||||
for _, roleBinding := range roleBindingsInScope {
|
||||
if containsUser(roleBinding.Subjects, username) {
|
||||
role, err := am.informers.
|
||||
Iam().V1alpha2().Roles().Lister().Get(roleBinding.RoleRef.Name)
|
||||
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roles = append(roles, *role)
|
||||
for _, roleBinding := range roleBindings {
|
||||
if contains(roleBinding.Subjects, username) {
|
||||
userRoleBindings = append(userRoleBindings, roleBinding)
|
||||
}
|
||||
}
|
||||
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
func filterRoleBindingByScope(roles []*iamv1alpha2.RoleBinding, scope iamv1alpha2.Scope) []*iamv1alpha2.RoleBinding {
|
||||
result := make([]*iamv1alpha2.RoleBinding, 0)
|
||||
for _, role := range roles {
|
||||
if role.Scope == scope {
|
||||
result = append(result, role)
|
||||
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
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (am *amOperator) GetPolicyRule(name string) (*iamv1alpha2.PolicyRule, error) {
|
||||
lister := am.informers.Iam().V1alpha2().PolicyRules().Lister()
|
||||
return lister.Get(name)
|
||||
}
|
||||
|
||||
// Users can only bind one role at each level
|
||||
func (am *amOperator) GetRoleOfUserInTargetScope(scope iamv1alpha2.Scope, target, username string) (*iamv1alpha2.Role, error) {
|
||||
roles, err := am.ListRolesOfUser(scope, username)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
for _, role := range roles {
|
||||
if role.Target.Name == target {
|
||||
return &role, nil
|
||||
if len(roleBindings) > 1 {
|
||||
klog.Warningf("conflict global role binding, username: %s", username)
|
||||
}
|
||||
return role, nil
|
||||
}
|
||||
|
||||
err = &errors.StatusError{ErrStatus: metav1.Status{
|
||||
@@ -124,11 +102,274 @@ func (am *amOperator) GetRoleOfUserInTargetScope(scope iamv1alpha2.Scope, target
|
||||
Reason: metav1.StatusReasonNotFound,
|
||||
Details: &metav1.StatusDetails{
|
||||
Group: iamv1alpha2.SchemeGroupVersion.Group,
|
||||
Kind: iamv1alpha2.RoleBindingKind,
|
||||
Kind: iamv1alpha2.ResourceKindGlobalRoleBinding,
|
||||
},
|
||||
Message: fmt.Sprintf("role bind not found in %s %s scope", target, scope),
|
||||
Message: fmt.Sprintf("global role binding not found for %s", username),
|
||||
}}
|
||||
|
||||
klog.Error(err)
|
||||
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 "Role":
|
||||
role, err := am.k8sinformer.Rbac().V1().Roles().Lister().Roles(bindingNamespace).Get(roleRef.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return role.Rules, nil
|
||||
|
||||
case "ClusterRole":
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user