improve IAM module

Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2020-05-22 09:35:05 +08:00
parent 0d12529051
commit 8f93266ec0
640 changed files with 50221 additions and 18179 deletions

View File

@@ -18,18 +18,19 @@
package am
import (
"encoding/json"
"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/client-go/kubernetes"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
devopsv1alpha3 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
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 "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
"kubesphere.io/kubesphere/pkg/informers"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
"net/http"
@@ -38,7 +39,7 @@ import (
type AccessManagementInterface interface {
GetGlobalRoleOfUser(username string) (*iamv1alpha2.GlobalRole, error)
GetWorkspaceRoleOfUser(username, workspace string) (*iamv1alpha2.WorkspaceRole, error)
GetClusterRoleOfUser(username, cluster string) (*rbacv1.ClusterRole, error)
GetClusterRoleOfUser(username 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)
@@ -50,42 +51,55 @@ type AccessManagementInterface interface {
ListWorkspaceRoleBindings(username, workspace string) ([]*iamv1alpha2.WorkspaceRoleBinding, error)
ListRoleBindings(username, namespace string) ([]*rbacv1.RoleBinding, error)
GetRoleReferenceRules(roleRef rbacv1.RoleRef, bindingNamespace string) ([]rbacv1.PolicyRule, error)
GetRoleReferenceRules(roleRef rbacv1.RoleRef, namespace string) (string, []rbacv1.PolicyRule, error)
GetGlobalRole(globalRole string) (*iamv1alpha2.GlobalRole, error)
GetWorkspaceRole(workspace string, name string) (*iamv1alpha2.WorkspaceRole, error)
CreateOrUpdateGlobalRoleBinding(username string, globalRole string) error
CreateOrUpdateWorkspaceRole(workspace string, workspaceRole *iamv1alpha2.WorkspaceRole) (*iamv1alpha2.WorkspaceRole, error)
CreateOrUpdateGlobalRole(globalRole *iamv1alpha2.GlobalRole) (*iamv1alpha2.GlobalRole, error)
DeleteWorkspaceRole(workspace string, name string) error
DeleteGlobalRole(name string) error
CreateOrUpdateClusterRole(clusterRole *rbacv1.ClusterRole) (*rbacv1.ClusterRole, error)
DeleteClusterRole(name string) error
GetClusterRole(name string) (*rbacv1.ClusterRole, error)
GetNamespaceRole(namespace string, name string) (*rbacv1.Role, error)
CreateOrUpdateNamespaceRole(namespace string, role *rbacv1.Role) (*rbacv1.Role, error)
DeleteNamespaceRole(namespace string, name string) error
CreateOrUpdateWorkspaceRoleBinding(username string, workspace string, role string) error
RemoveUserFromWorkspace(username string, workspace string) error
CreateOrUpdateNamespaceRoleBinding(username string, namespace string, role string) error
RemoveUserFromNamespace(username string, namespace string) error
CreateOrUpdateClusterRoleBinding(username string, role string) error
RemoveUserFromCluster(username string) error
GetControlledNamespace(devops string) (string, error)
}
type amOperator struct {
ksinformer ksinformers.SharedInformerFactory
k8sinformer k8sinformers.SharedInformerFactory
resourceGetter *resourcev1alpha3.ResourceGetter
ksclient kubesphere.Interface
k8sclient kubernetes.Interface
}
func NewAMOperator(factory informers.InformerFactory) AccessManagementInterface {
func NewReadOnlyOperator(factory informers.InformerFactory) AccessManagementInterface {
return &amOperator{
ksinformer: factory.KubeSphereSharedInformerFactory(),
k8sinformer: factory.KubernetesSharedInformerFactory(),
resourceGetter: resourcev1alpha3.NewResourceGetter(factory),
}
}
func NewOperator(factory informers.InformerFactory, ksclient kubesphere.Interface, k8sclient kubernetes.Interface) AccessManagementInterface {
return &amOperator{
resourceGetter: resourcev1alpha3.NewResourceGetter(factory),
ksclient: ksclient,
k8sclient: k8sclient,
}
}
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)
}
}
userRoleBindings, err := am.ListGlobalRoleBindings(username)
if len(userRoleBindings) > 0 {
role, err := am.ksinformer.Iam().V1alpha2().GlobalRoles().Lister().Get(userRoleBindings[0].RoleRef.Name)
role, err := am.GetGlobalRole(userRoleBindings[0].RoleRef.Name)
if err != nil {
klog.Error(err)
return nil, err
@@ -93,7 +107,13 @@ func (am *amOperator) GetGlobalRoleOfUser(username string) (*iamv1alpha2.GlobalR
if len(userRoleBindings) > 1 {
klog.Warningf("conflict global role binding, username: %s", username)
}
return role, nil
out := role.DeepCopy()
if out.Annotations == nil {
out.Annotations = make(map[string]string, 0)
}
out.Annotations[iamv1alpha2.GlobalRoleAnnotation] = role.Name
return out, nil
}
err = &errors.StatusError{ErrStatus: metav1.Status{
@@ -112,23 +132,15 @@ func (am *amOperator) GetGlobalRoleOfUser(username string) (*iamv1alpha2.GlobalR
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}))
userRoleBindings, err := am.ListWorkspaceRoleBindings(username, 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)
role, err := am.GetWorkspaceRole(workspace, userRoleBindings[0].RoleRef.Name)
if err != nil {
klog.Error(err)
@@ -139,7 +151,12 @@ func (am *amOperator) GetWorkspaceRoleOfUser(username, workspace string) (*iamv1
klog.Warningf("conflict workspace role binding, username: %s", username)
}
return role, nil
out := role.DeepCopy()
if out.Annotations == nil {
out.Annotations = make(map[string]string, 0)
}
out.Annotations[iamv1alpha2.WorkspaceRoleAnnotation] = role.Name
return out, nil
}
err = &errors.StatusError{ErrStatus: metav1.Status{
@@ -157,23 +174,15 @@ func (am *amOperator) GetWorkspaceRoleOfUser(username, workspace string) (*iamv1
}
func (am *amOperator) GetNamespaceRoleOfUser(username, namespace string) (*rbacv1.Role, error) {
roleBindings, err := am.k8sinformer.Rbac().V1().RoleBindings().Lister().List(labels.Everything())
userRoleBindings, err := am.ListRoleBindings(username, namespace)
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)
role, err := am.GetNamespaceRole(namespace, userRoleBindings[0].RoleRef.Name)
if err != nil {
klog.Error(err)
return nil, err
@@ -181,7 +190,13 @@ func (am *amOperator) GetNamespaceRoleOfUser(username, namespace string) (*rbacv
if len(userRoleBindings) > 1 {
klog.Warningf("conflict role binding, username: %s", username)
}
return role, nil
out := role.DeepCopy()
if out.Annotations == nil {
out.Annotations = make(map[string]string, 0)
}
out.Annotations[iamv1alpha2.RoleAnnotation] = role.Name
return out, nil
}
err = &errors.StatusError{ErrStatus: metav1.Status{
@@ -190,7 +205,7 @@ func (am *amOperator) GetNamespaceRoleOfUser(username, namespace string) (*rbacv
Reason: metav1.StatusReasonNotFound,
Details: &metav1.StatusDetails{
Group: rbacv1.SchemeGroupVersion.Group,
Kind: "RoleBinding",
Kind: iamv1alpha2.ResourceKindRoleBinding,
},
Message: fmt.Sprintf("role binding not found for %s in %s", username, namespace),
}}
@@ -198,33 +213,31 @@ func (am *amOperator) GetNamespaceRoleOfUser(username, namespace string) (*rbacv
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())
func (am *amOperator) GetClusterRoleOfUser(username string) (*rbacv1.ClusterRole, error) {
userRoleBindings, err := am.ListClusterRoleBindings(username)
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)
role, err := am.GetClusterRole(userRoleBindings[0].RoleRef.Name)
if err != nil {
klog.Error(err)
return nil, err
}
if len(userRoleBindings) > 1 {
klog.Warningf("conflict cluster role binding, username: %s", username)
}
return role, nil
out := role.DeepCopy()
if out.Annotations == nil {
out.Annotations = make(map[string]string, 0)
}
out.Annotations[iamv1alpha2.ClusterRoleAnnotation] = role.Name
return out, nil
}
err = &errors.StatusError{ErrStatus: metav1.Status{
Status: metav1.StatusFailure,
@@ -234,14 +247,14 @@ func (am *amOperator) GetClusterRoleOfUser(username, cluster string) (*rbacv1.Cl
Group: rbacv1.SchemeGroupVersion.Group,
Kind: "ClusterRoleBinding",
},
Message: fmt.Sprintf("cluster role binding not found for %s in %s", username, cluster),
Message: fmt.Sprintf("cluster role binding not found for %s", username),
}}
return nil, err
}
func (am *amOperator) ListWorkspaceRoleBindings(username, workspace string) ([]*iamv1alpha2.WorkspaceRoleBinding, error) {
roleBindings, err := am.ksinformer.Iam().V1alpha2().WorkspaceRoleBindings().Lister().List(labels.Everything())
roleBindings, err := am.resourceGetter.List(iamv1alpha2.ResourcesPluralWorkspaceRoleBinding, "", query.New())
if err != nil {
return nil, err
@@ -249,7 +262,8 @@ func (am *amOperator) ListWorkspaceRoleBindings(username, workspace string) ([]*
result := make([]*iamv1alpha2.WorkspaceRoleBinding, 0)
for _, roleBinding := range roleBindings {
for _, obj := range roleBindings.Items {
roleBinding := obj.(*iamv1alpha2.WorkspaceRoleBinding)
inSpecifiedWorkspace := workspace == "" || roleBinding.Labels[tenantv1alpha1.WorkspaceLabel] == workspace
if contains(roleBinding.Subjects, username) && inSpecifiedWorkspace {
result = append(result, roleBinding)
@@ -261,7 +275,7 @@ func (am *amOperator) ListWorkspaceRoleBindings(username, workspace string) ([]*
func (am *amOperator) ListClusterRoleBindings(username string) ([]*rbacv1.ClusterRoleBinding, error) {
roleBindings, err := am.k8sinformer.Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
roleBindings, err := am.resourceGetter.List(iamv1alpha2.ResourcesPluralClusterRoleBinding, "", query.New())
if err != nil {
return nil, err
@@ -269,7 +283,8 @@ func (am *amOperator) ListClusterRoleBindings(username string) ([]*rbacv1.Cluste
result := make([]*rbacv1.ClusterRoleBinding, 0)
for _, roleBinding := range roleBindings {
for _, obj := range roleBindings.Items {
roleBinding := obj.(*rbacv1.ClusterRoleBinding)
if contains(roleBinding.Subjects, username) {
result = append(result, roleBinding)
}
@@ -279,7 +294,7 @@ func (am *amOperator) ListClusterRoleBindings(username string) ([]*rbacv1.Cluste
}
func (am *amOperator) ListGlobalRoleBindings(username string) ([]*iamv1alpha2.GlobalRoleBinding, error) {
roleBindings, err := am.ksinformer.Iam().V1alpha2().GlobalRoleBindings().Lister().List(labels.Everything())
roleBindings, err := am.resourceGetter.List(iamv1alpha2.ResourcesPluralGlobalRoleBinding, "", query.New())
if err != nil {
return nil, err
@@ -287,7 +302,8 @@ func (am *amOperator) ListGlobalRoleBindings(username string) ([]*iamv1alpha2.Gl
result := make([]*iamv1alpha2.GlobalRoleBinding, 0)
for _, roleBinding := range roleBindings {
for _, obj := range roleBindings.Items {
roleBinding := obj.(*iamv1alpha2.GlobalRoleBinding)
if contains(roleBinding.Subjects, username) {
result = append(result, roleBinding)
}
@@ -298,7 +314,7 @@ func (am *amOperator) ListGlobalRoleBindings(username string) ([]*iamv1alpha2.Gl
func (am *amOperator) ListRoleBindings(username, namespace string) ([]*rbacv1.RoleBinding, error) {
roleBindings, err := am.k8sinformer.Rbac().V1().RoleBindings().Lister().RoleBindings(namespace).List(labels.Everything())
roleBindings, err := am.resourceGetter.List(iamv1alpha2.ResourcesPluralRoleBinding, namespace, query.New())
if err != nil {
klog.Error(err)
@@ -307,7 +323,8 @@ func (am *amOperator) ListRoleBindings(username, namespace string) ([]*rbacv1.Ro
result := make([]*rbacv1.RoleBinding, 0)
for _, roleBinding := range roleBindings {
for _, obj := range roleBindings.Items {
roleBinding := obj.(*rbacv1.RoleBinding)
if contains(roleBinding.Subjects, username) {
result = append(result, roleBinding)
}
@@ -341,34 +358,557 @@ func (am *amOperator) ListGlobalRoles(query *query.Query) (*api.ListResult, erro
return am.resourceGetter.List(iamv1alpha2.ResourcesPluralGlobalRole, "", query)
}
func (am *amOperator) GetGlobalRole(globalRole string) (*iamv1alpha2.GlobalRole, error) {
obj, err := am.resourceGetter.Get(iamv1alpha2.ResourcesPluralGlobalRole, "", globalRole)
if err != nil {
klog.Error(err)
return nil, err
}
return obj.(*iamv1alpha2.GlobalRole), nil
}
func (am *amOperator) CreateOrUpdateGlobalRoleBinding(username string, globalRole string) error {
_, err := am.GetGlobalRole(globalRole)
if err != nil {
klog.Error(err)
return err
}
roleBindings, err := am.ListGlobalRoleBindings(username)
if err != nil {
klog.Error(err)
return err
}
for _, roleBinding := range roleBindings {
if globalRole == roleBinding.RoleRef.Name {
return nil
}
err := am.ksclient.IamV1alpha2().GlobalRoleBindings().Delete(roleBinding.Name, metav1.NewDeleteOptions(0))
if err != nil {
if errors.IsNotFound(err) {
continue
}
klog.Error(err)
return err
}
}
globalRoleBinding := iamv1alpha2.GlobalRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%s", username, globalRole),
Labels: map[string]string{iamv1alpha2.UserReferenceLabel: username},
},
Subjects: []rbacv1.Subject{
{
Kind: rbacv1.UserKind,
APIGroup: rbacv1.SchemeGroupVersion.Group,
Name: username,
},
},
RoleRef: rbacv1.RoleRef{
APIGroup: iamv1alpha2.SchemeGroupVersion.Group,
Kind: iamv1alpha2.ResourceKindGlobalRole,
Name: globalRole,
},
}
if _, err := am.ksclient.IamV1alpha2().GlobalRoleBindings().Create(&globalRoleBinding); err != nil {
return err
}
return nil
}
func (am *amOperator) CreateOrUpdateWorkspaceRole(workspace string, workspaceRole *iamv1alpha2.WorkspaceRole) (*iamv1alpha2.WorkspaceRole, error) {
if workspaceRole.Labels == nil {
workspaceRole.Labels = make(map[string]string, 0)
}
workspaceRole.Labels[tenantv1alpha1.WorkspaceLabel] = workspace
workspaceRole.Rules = make([]rbacv1.PolicyRule, 0)
var aggregateRoles []string
if err := json.Unmarshal([]byte(workspaceRole.Annotations[iamv1alpha2.AggregationRolesAnnotation]), &aggregateRoles); err == nil {
for _, roleName := range aggregateRoles {
role, err := am.GetWorkspaceRole("", roleName)
if err != nil {
klog.Error(err)
return nil, err
}
workspaceRole.Rules = append(workspaceRole.Rules, role.Rules...)
}
}
old, err := am.GetWorkspaceRole("", workspaceRole.Name)
if err != nil && !errors.IsNotFound(err) {
klog.Error(err)
return nil, err
}
var created *iamv1alpha2.WorkspaceRole
if old != nil {
created, err = am.ksclient.IamV1alpha2().WorkspaceRoles().Update(workspaceRole)
} else {
created, err = am.ksclient.IamV1alpha2().WorkspaceRoles().Create(workspaceRole)
}
return created, err
}
func (am *amOperator) CreateOrUpdateWorkspaceRoleBinding(username string, workspace string, role string) error {
_, err := am.GetWorkspaceRole(workspace, role)
if err != nil {
klog.Error(err)
return err
}
roleBindings, err := am.ListWorkspaceRoleBindings(username, workspace)
if err != nil {
klog.Error(err)
return err
}
for _, roleBinding := range roleBindings {
if role == roleBinding.RoleRef.Name {
return nil
}
err := am.ksclient.IamV1alpha2().WorkspaceRoleBindings().Delete(roleBinding.Name, metav1.NewDeleteOptions(0))
if err != nil {
if errors.IsNotFound(err) {
continue
}
klog.Error(err)
return err
}
}
roleBinding := iamv1alpha2.WorkspaceRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%s-%s", workspace, username, role),
Labels: map[string]string{iamv1alpha2.UserReferenceLabel: username,
tenantv1alpha1.WorkspaceLabel: workspace},
},
Subjects: []rbacv1.Subject{
{
Kind: rbacv1.UserKind,
APIGroup: rbacv1.SchemeGroupVersion.Group,
Name: username,
},
},
RoleRef: rbacv1.RoleRef{
APIGroup: iamv1alpha2.SchemeGroupVersion.Group,
Kind: iamv1alpha2.ResourceKindWorkspaceRole,
Name: role,
},
}
if _, err := am.ksclient.IamV1alpha2().WorkspaceRoleBindings().Create(&roleBinding); err != nil {
return err
}
return nil
}
func (am *amOperator) CreateOrUpdateClusterRoleBinding(username string, role string) error {
_, err := am.GetClusterRole(role)
if err != nil {
klog.Error(err)
return err
}
roleBindings, err := am.ListClusterRoleBindings(username)
if err != nil {
klog.Error(err)
return err
}
for _, roleBinding := range roleBindings {
if role == roleBinding.RoleRef.Name {
return nil
}
err := am.k8sclient.RbacV1().ClusterRoleBindings().Delete(roleBinding.Name, metav1.NewDeleteOptions(0))
if err != nil {
if errors.IsNotFound(err) {
continue
}
klog.Error(err)
return err
}
}
roleBinding := rbacv1.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%s", username, role),
Labels: map[string]string{iamv1alpha2.UserReferenceLabel: username},
},
Subjects: []rbacv1.Subject{
{
Kind: rbacv1.UserKind,
APIGroup: rbacv1.SchemeGroupVersion.Group,
Name: username,
},
},
RoleRef: rbacv1.RoleRef{
APIGroup: rbacv1.SchemeGroupVersion.Group,
Kind: iamv1alpha2.ResourceKindClusterRole,
Name: role,
},
}
if _, err := am.k8sclient.RbacV1().ClusterRoleBindings().Create(&roleBinding); err != nil {
return err
}
return nil
}
func (am *amOperator) CreateOrUpdateNamespaceRoleBinding(username string, namespace string, role string) error {
_, err := am.GetNamespaceRole(namespace, role)
if err != nil {
klog.Error(err)
return err
}
roleBindings, err := am.ListRoleBindings(username, namespace)
if err != nil {
klog.Error(err)
return err
}
for _, roleBinding := range roleBindings {
if role == roleBinding.RoleRef.Name {
return nil
}
err := am.k8sclient.RbacV1().RoleBindings(namespace).Delete(roleBinding.Name, metav1.NewDeleteOptions(0))
if err != nil {
if errors.IsNotFound(err) {
continue
}
klog.Error(err)
return err
}
}
roleBinding := rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%s", username, role),
Labels: map[string]string{iamv1alpha2.UserReferenceLabel: username},
},
Subjects: []rbacv1.Subject{
{
Kind: rbacv1.UserKind,
APIGroup: rbacv1.SchemeGroupVersion.Group,
Name: username,
},
},
RoleRef: rbacv1.RoleRef{
APIGroup: rbacv1.SchemeGroupVersion.Group,
Kind: iamv1alpha2.ResourceKindRole,
Name: role,
},
}
if _, err := am.k8sclient.RbacV1().RoleBindings(namespace).Create(&roleBinding); err != nil {
return err
}
return nil
}
func (am *amOperator) RemoveUserFromWorkspace(username string, workspace string) error {
roleBindings, err := am.ListWorkspaceRoleBindings(username, workspace)
if err != nil {
klog.Error(err)
return err
}
for _, roleBinding := range roleBindings {
err := am.ksclient.IamV1alpha2().WorkspaceRoleBindings().Delete(roleBinding.Name, metav1.NewDeleteOptions(0))
if err != nil {
if errors.IsNotFound(err) {
continue
}
klog.Error(err)
return err
}
}
return nil
}
func (am *amOperator) RemoveUserFromNamespace(username string, namespace string) error {
roleBindings, err := am.ListRoleBindings(username, namespace)
if err != nil {
klog.Error(err)
return err
}
for _, roleBinding := range roleBindings {
err := am.k8sclient.RbacV1().RoleBindings(namespace).Delete(roleBinding.Name, metav1.NewDeleteOptions(0))
if err != nil {
if errors.IsNotFound(err) {
continue
}
klog.Error(err)
return err
}
}
return nil
}
func (am *amOperator) RemoveUserFromCluster(username string) error {
roleBindings, err := am.ListClusterRoleBindings(username)
if err != nil {
klog.Error(err)
return err
}
for _, roleBinding := range roleBindings {
err := am.k8sclient.RbacV1().ClusterRoleBindings().Delete(roleBinding.Name, metav1.NewDeleteOptions(0))
if err != nil {
if errors.IsNotFound(err) {
continue
}
klog.Error(err)
return err
}
}
return nil
}
func (am *amOperator) CreateOrUpdateGlobalRole(globalRole *iamv1alpha2.GlobalRole) (*iamv1alpha2.GlobalRole, error) {
globalRole.Rules = make([]rbacv1.PolicyRule, 0)
var aggregateRoles []string
if err := json.Unmarshal([]byte(globalRole.Annotations[iamv1alpha2.AggregationRolesAnnotation]), &aggregateRoles); err == nil {
for _, roleName := range aggregateRoles {
role, err := am.GetGlobalRole(roleName)
if err != nil {
klog.Error(err)
return nil, err
}
globalRole.Rules = append(globalRole.Rules, role.Rules...)
}
}
old, err := am.GetGlobalRole(globalRole.Name)
if err != nil && !errors.IsNotFound(err) {
klog.Error(err)
return nil, err
}
var created *iamv1alpha2.GlobalRole
if old != nil {
created, err = am.ksclient.IamV1alpha2().GlobalRoles().Update(globalRole)
} else {
created, err = am.ksclient.IamV1alpha2().GlobalRoles().Create(globalRole)
}
return created, err
}
func (am *amOperator) CreateOrUpdateClusterRole(clusterRole *rbacv1.ClusterRole) (*rbacv1.ClusterRole, error) {
clusterRole.Rules = make([]rbacv1.PolicyRule, 0)
var aggregateRoles []string
if err := json.Unmarshal([]byte(clusterRole.Annotations[iamv1alpha2.AggregationRolesAnnotation]), &aggregateRoles); err == nil {
for _, roleName := range aggregateRoles {
role, err := am.GetClusterRole(roleName)
if err != nil {
klog.Error(err)
return nil, err
}
clusterRole.Rules = append(clusterRole.Rules, role.Rules...)
}
}
old, err := am.GetClusterRole(clusterRole.Name)
if err != nil && !errors.IsNotFound(err) {
klog.Error(err)
return nil, err
}
var created *rbacv1.ClusterRole
if old != nil {
created, err = am.k8sclient.RbacV1().ClusterRoles().Update(clusterRole)
} else {
created, err = am.k8sclient.RbacV1().ClusterRoles().Create(clusterRole)
}
return created, err
}
func (am *amOperator) CreateOrUpdateNamespaceRole(namespace string, role *rbacv1.Role) (*rbacv1.Role, error) {
role.Rules = make([]rbacv1.PolicyRule, 0)
role.Namespace = namespace
var aggregateRoles []string
if err := json.Unmarshal([]byte(role.Annotations[iamv1alpha2.AggregationRolesAnnotation]), &aggregateRoles); err == nil {
for _, roleName := range aggregateRoles {
role, err := am.GetNamespaceRole(namespace, roleName)
if err != nil {
klog.Error(err)
return nil, err
}
role.Rules = append(role.Rules, role.Rules...)
}
}
old, err := am.GetNamespaceRole(namespace, role.Name)
if err != nil && !errors.IsNotFound(err) {
klog.Error(err)
return nil, err
}
var created *rbacv1.Role
if old != nil {
created, err = am.k8sclient.RbacV1().Roles(namespace).Update(role)
} else {
created, err = am.k8sclient.RbacV1().Roles(namespace).Create(role)
}
return created, err
}
func (am *amOperator) DeleteWorkspaceRole(workspace string, name string) error {
workspaceRole, err := am.GetWorkspaceRole(workspace, name)
if err != nil {
return err
}
return am.ksclient.IamV1alpha2().WorkspaceRoles().Delete(workspaceRole.Name, metav1.NewDeleteOptions(0))
}
func (am *amOperator) DeleteGlobalRole(name string) error {
return am.ksclient.IamV1alpha2().GlobalRoles().Delete(name, metav1.NewDeleteOptions(0))
}
func (am *amOperator) DeleteClusterRole(name string) error {
return am.k8sclient.RbacV1().ClusterRoles().Delete(name, metav1.NewDeleteOptions(0))
}
func (am *amOperator) DeleteNamespaceRole(namespace string, name string) error {
return am.k8sclient.RbacV1().Roles(namespace).Delete(name, metav1.NewDeleteOptions(0))
}
// GetRoleReferenceRules attempts to resolve the RoleBinding or ClusterRoleBinding.
func (am *amOperator) GetRoleReferenceRules(roleRef rbacv1.RoleRef, bindingNamespace string) ([]rbacv1.PolicyRule, error) {
func (am *amOperator) GetRoleReferenceRules(roleRef rbacv1.RoleRef, namespace string) (string, []rbacv1.PolicyRule, error) {
switch roleRef.Kind {
case iamv1alpha2.ResourceKindRole:
role, err := am.k8sinformer.Rbac().V1().Roles().Lister().Roles(bindingNamespace).Get(roleRef.Name)
role, err := am.GetNamespaceRole(namespace, roleRef.Name)
if err != nil {
return nil, err
return "", nil, err
}
return role.Rules, nil
return role.Annotations[iamv1alpha2.RegoOverrideAnnotation], role.Rules, nil
case iamv1alpha2.ResourceKindClusterRole:
clusterRole, err := am.k8sinformer.Rbac().V1().ClusterRoles().Lister().Get(roleRef.Name)
clusterRole, err := am.GetClusterRole(roleRef.Name)
if err != nil {
return nil, err
return "", nil, err
}
return clusterRole.Rules, nil
return clusterRole.Annotations[iamv1alpha2.RegoOverrideAnnotation], clusterRole.Rules, nil
case iamv1alpha2.ResourceKindGlobalRole:
globalRole, err := am.ksinformer.Iam().V1alpha2().GlobalRoles().Lister().Get(roleRef.Name)
globalRole, err := am.GetGlobalRole(roleRef.Name)
if err != nil {
return nil, err
return "", nil, err
}
return globalRole.Rules, nil
return globalRole.Annotations[iamv1alpha2.RegoOverrideAnnotation], globalRole.Rules, nil
case iamv1alpha2.ResourceKindWorkspaceRole:
workspaceRole, err := am.ksinformer.Iam().V1alpha2().WorkspaceRoles().Lister().Get(roleRef.Name)
workspaceRole, err := am.GetWorkspaceRole("", roleRef.Name)
if err != nil {
return nil, err
return "", nil, err
}
return workspaceRole.Rules, nil
return workspaceRole.Annotations[iamv1alpha2.RegoOverrideAnnotation], workspaceRole.Rules, nil
default:
return nil, fmt.Errorf("unsupported role reference kind: %q", roleRef.Kind)
return "", nil, fmt.Errorf("unsupported role reference kind: %q", roleRef.Kind)
}
}
func (am *amOperator) GetWorkspaceRole(workspace string, name string) (*iamv1alpha2.WorkspaceRole, error) {
obj, err := am.resourceGetter.Get(iamv1alpha2.ResourcesPluralWorkspaceRole, "", name)
if err != nil {
klog.Error(err)
return nil, err
}
workspaceRole := obj.(*iamv1alpha2.WorkspaceRole)
if workspace != "" && workspaceRole.Labels[tenantv1alpha1.WorkspaceLabel] != workspace {
err := errors.NewNotFound(iamv1alpha2.Resource(iamv1alpha2.ResourcesSingularWorkspaceRole), name)
klog.Error(err)
return nil, err
}
return workspaceRole, nil
}
func (am *amOperator) GetNamespaceRole(namespace string, name string) (*rbacv1.Role, error) {
obj, err := am.resourceGetter.Get(iamv1alpha2.ResourcesPluralRole, namespace, name)
if err != nil {
klog.Error(err)
return nil, err
}
return obj.(*rbacv1.Role), nil
}
func (am *amOperator) GetClusterRole(name string) (*rbacv1.ClusterRole, error) {
obj, err := am.resourceGetter.Get(iamv1alpha2.ResourcesPluralClusterRole, "", name)
if err != nil {
klog.Error(err)
return nil, err
}
return obj.(*rbacv1.ClusterRole), nil
}
func (am *amOperator) GetControlledNamespace(devops string) (string, error) {
obj, err := am.resourceGetter.Get(devopsv1alpha3.ResourcePluralDevOpsProject, "", devops)
if err != nil {
klog.Error(err)
return "", err
}
devopsProject := obj.(*devopsv1alpha3.DevOpsProject)
return devopsProject.Status.AdminNamespace, nil
}

View File

@@ -28,13 +28,14 @@ import (
kubesphereclient "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
"kubesphere.io/kubesphere/pkg/informers"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
"net/mail"
)
type IdentityManagementInterface interface {
CreateUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error)
ListUsers(query *query.Query) (*api.ListResult, error)
DeleteUser(username string) error
ModifyUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error)
UpdateUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error)
DescribeUser(username string) (*iamv1alpha2.User, error)
Authenticate(username, password string) (*iamv1alpha2.User, error)
}
@@ -60,33 +61,85 @@ type defaultIMOperator struct {
resourceGetter *resourcev1alpha3.ResourceGetter
}
func (im *defaultIMOperator) ModifyUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error) {
func (im *defaultIMOperator) UpdateUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error) {
obj, err := im.resourceGetter.Get(iamv1alpha2.ResourcesPluralUser, "", user.Name)
if err != nil {
klog.Error(err)
return nil, err
}
old := obj.(*iamv1alpha2.User).DeepCopy()
user.Annotations[iamv1alpha2.PasswordEncryptedAnnotation] = old.Annotations[iamv1alpha2.PasswordEncryptedAnnotation]
user.Spec.EncryptedPassword = old.Spec.EncryptedPassword
return im.ksClient.IamV1alpha2().Users().Update(user)
}
func (im *defaultIMOperator) Authenticate(username, password string) (*iamv1alpha2.User, error) {
user, err := im.DescribeUser(username)
var user *iamv1alpha2.User
if err != nil {
klog.Error(err)
return nil, err
if _, err := mail.ParseAddress(username); err != nil {
obj, err := im.resourceGetter.Get(iamv1alpha2.ResourcesPluralUser, "", username)
if err != nil {
klog.Error(err)
return nil, err
}
user = obj.(*iamv1alpha2.User)
} else {
objs, err := im.resourceGetter.List(iamv1alpha2.ResourcesPluralUser, "", &query.Query{
Pagination: query.NoPagination,
Filters: map[query.Field]query.Value{iamv1alpha2.FieldEmail: query.Value(username)},
})
if err != nil {
klog.Error(err)
return nil, err
}
if len(objs.Items) != 1 {
if len(objs.Items) == 0 {
klog.Warningf("username or email: %s not exist", username)
} else {
klog.Errorf("duplicate user entries: %+v", objs)
}
return nil, AuthFailedIncorrectPassword
}
user = objs.Items[0].(*iamv1alpha2.User)
}
if checkPasswordHash(password, user.Spec.EncryptedPassword) {
return user, nil
}
return nil, AuthFailedIncorrectPassword
}
func (im *defaultIMOperator) ListUsers(query *query.Query) (*api.ListResult, error) {
result, err := im.resourceGetter.List(iamv1alpha2.ResourcesPluralUser, "", query)
func (im *defaultIMOperator) ListUsers(query *query.Query) (result *api.ListResult, err error) {
result, err = im.resourceGetter.List(iamv1alpha2.ResourcesPluralUser, "", query)
if err != nil {
klog.Error(err)
return nil, err
}
items := make([]interface{}, 0)
for _, item := range result.Items {
user := item.(*iamv1alpha2.User)
out := user.DeepCopy()
// ensure encrypted password will not be output
out.Spec.EncryptedPassword = ""
items = append(items, out)
}
result.Items = items
return result, nil
}
@@ -96,13 +149,19 @@ func checkPasswordHash(password, hash string) bool {
}
func (im *defaultIMOperator) DescribeUser(username string) (*iamv1alpha2.User, error) {
user, err := im.resourceGetter.Get(iamv1alpha2.ResourcesPluralUser, "", username)
obj, err := im.resourceGetter.Get(iamv1alpha2.ResourcesPluralUser, "", username)
if err != nil {
klog.Error(err)
return nil, err
}
return user.(*iamv1alpha2.User), nil
user := obj.(*iamv1alpha2.User)
out := user.DeepCopy()
// ensure encrypted password will not be output
out.Spec.EncryptedPassword = ""
return out, nil
}
func (im *defaultIMOperator) DeleteUser(username string) error {

View File

@@ -36,7 +36,7 @@ func NewLDAPOperator(ldapClient ldap.Interface) IdentityManagementInterface {
}
}
func (im *ldapOperator) ModifyUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error) {
func (im *ldapOperator) UpdateUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error) {
err := im.ldapClient.Update(user)