migrate legacy API

Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2020-04-20 07:01:43 +08:00
parent 3f89eaef7e
commit 7db2ba662c
103 changed files with 5962 additions and 2363 deletions

View File

@@ -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)
}
}