diff --git a/actions/auth/authprovider.go b/actions/auth/authprovider.go index 64f68a52b..7bc55f3f0 100644 --- a/actions/auth/authprovider.go +++ b/actions/auth/authprovider.go @@ -9,6 +9,7 @@ import ( v3 "github.com/rancher/shepherd/clients/rancher/generated/management/v3" "github.com/rancher/shepherd/extensions/defaults" "github.com/rancher/shepherd/pkg/session" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/rbac" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -218,7 +219,7 @@ func UpdateAccessMode(client *rancher.Client, providerName, accessMode string, a // SetupRequiredAccessModePrincipals creates cluster role binding and prepares principal IDs for required access mode tests func SetupRequiredAccessModePrincipals(authAdmin *rancher.Client, clusterID string, authConfig *AuthConfig, providerName, userSearchBase, groupSearchBase string) ([]string, error) { groupPrincipalID := GetGroupPrincipalID(providerName, authConfig.Group, userSearchBase, groupSearchBase) - _, err := rbac.CreateGroupClusterRoleTemplateBinding(authAdmin, clusterID, groupPrincipalID, rbac.ClusterMember.String()) + _, err := rbacapi.CreateGroupClusterRoleTemplateBinding(authAdmin, clusterID, groupPrincipalID, rbac.ClusterMember.String()) if err != nil { return nil, fmt.Errorf("failed to create cluster role binding: %w", err) } diff --git a/actions/kubeapi/clusters/clusters.go b/actions/kubeapi/clusters/clusters.go index e6362546f..115f7ce56 100644 --- a/actions/kubeapi/clusters/clusters.go +++ b/actions/kubeapi/clusters/clusters.go @@ -3,12 +3,15 @@ package clusters import ( "github.com/rancher/shepherd/clients/rancher" "github.com/rancher/shepherd/pkg/wrangler" - rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" +) + +const ( + LocalCluster = "local" ) // GetClusterWranglerContext returns the context for the cluster func GetClusterWranglerContext(client *rancher.Client, clusterID string) (*wrangler.Context, error) { - if clusterID == rbacapi.LocalCluster { + if clusterID == LocalCluster { return client.WranglerContext, nil } diff --git a/actions/kubeapi/projects/delete.go b/actions/kubeapi/projects/delete.go index 6ffe6076f..7f08e7024 100644 --- a/actions/kubeapi/projects/delete.go +++ b/actions/kubeapi/projects/delete.go @@ -5,14 +5,14 @@ import ( "github.com/rancher/shepherd/clients/rancher" "github.com/rancher/shepherd/extensions/defaults" - rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kwait "k8s.io/apimachinery/pkg/util/wait" ) // DeleteProject is a helper function that uses the dynamic client to delete a Project from a cluster. func DeleteProject(client *rancher.Client, projectNamespace string, projectName string) error { - dynamicClient, err := client.GetDownStreamClusterClient(rbacapi.LocalCluster) + dynamicClient, err := client.GetDownStreamClusterClient(clusterapi.LocalCluster) if err != nil { return err } diff --git a/actions/kubeapi/projects/list.go b/actions/kubeapi/projects/list.go index 1f7b4f10e..0f2b85188 100644 --- a/actions/kubeapi/projects/list.go +++ b/actions/kubeapi/projects/list.go @@ -6,13 +6,13 @@ import ( v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3" "github.com/rancher/shepherd/clients/rancher" "github.com/rancher/shepherd/pkg/api/scheme" - rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // ListProjects is a helper function that uses the dynamic client to list projects in a cluster. func ListProjects(client *rancher.Client, namespace string, listOpt metav1.ListOptions) (*v3.ProjectList, error) { - dynamicClient, err := client.GetDownStreamClusterClient(rbacapi.LocalCluster) + dynamicClient, err := client.GetDownStreamClusterClient(clusterapi.LocalCluster) if err != nil { return nil, err } diff --git a/actions/kubeapi/projects/update.go b/actions/kubeapi/projects/update.go index feae72187..18c69ebed 100644 --- a/actions/kubeapi/projects/update.go +++ b/actions/kubeapi/projects/update.go @@ -7,13 +7,13 @@ import ( "github.com/rancher/shepherd/clients/rancher" "github.com/rancher/shepherd/extensions/unstructured" "github.com/rancher/shepherd/pkg/api/scheme" - rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // UpdateProject is a helper function that uses the dynamic client to update a project in a cluster. func UpdateProject(client *rancher.Client, existingProject *v3.Project, updatedProject *v3.Project) (*v3.Project, error) { - dynamicClient, err := client.GetDownStreamClusterClient(rbacapi.LocalCluster) + dynamicClient, err := client.GetDownStreamClusterClient(clusterapi.LocalCluster) if err != nil { return nil, err } diff --git a/actions/kubeapi/rbac/create.go b/actions/kubeapi/rbac/create.go index c6c2b6904..0e4ce4782 100644 --- a/actions/kubeapi/rbac/create.go +++ b/actions/kubeapi/rbac/create.go @@ -2,13 +2,20 @@ package rbac import ( "context" + "fmt" v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3" "github.com/rancher/shepherd/clients/rancher" + management "github.com/rancher/shepherd/clients/rancher/generated/management/v3" + "github.com/rancher/shepherd/extensions/defaults" + extauthz "github.com/rancher/shepherd/extensions/kubeapi/authorization" "github.com/rancher/shepherd/extensions/unstructured" "github.com/rancher/shepherd/pkg/api/scheme" + namegen "github.com/rancher/shepherd/pkg/namegenerator" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kwait "k8s.io/apimachinery/pkg/util/wait" ) // CreateRole is a helper function that uses the dynamic client to create a role on a namespace for a specific cluster. @@ -72,7 +79,7 @@ func CreateRoleBinding(client *rancher.Client, clusterName, roleBindingName, nam // CreateGlobalRole is a helper function that uses the dynamic client to create a global role in the local cluster. func CreateGlobalRole(client *rancher.Client, globalRole *v3.GlobalRole) (*v3.GlobalRole, error) { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) + dynamicClient, err := client.GetDownStreamClusterClient(clusterapi.LocalCluster) if err != nil { return nil, err } @@ -92,91 +99,213 @@ func CreateGlobalRole(client *rancher.Client, globalRole *v3.GlobalRole) (*v3.Gl return newGlobalRole, nil } -// CreateGlobalRoleBinding is a helper function that uses the dynamic client to create a global role binding for a specific user. -func CreateGlobalRoleBinding(client *rancher.Client, globalRoleBinding *v3.GlobalRoleBinding) (*v3.GlobalRoleBinding, error) { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) +// CreateGlobalRoleBinding creates a global role binding for the user with the provided global role using wrangler context +func CreateGlobalRoleBinding(client *rancher.Client, globalRoleName, userName, groupPrincipalName, userPrincipalName string) (*v3.GlobalRoleBinding, error) { + grbObj := &v3.GlobalRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "grb-", + }, + UserName: userName, + GroupPrincipalName: groupPrincipalName, + UserPrincipalName: userPrincipalName, + GlobalRoleName: globalRoleName, + } + + grb, err := client.WranglerContext.Mgmt.GlobalRoleBinding().Create(grbObj) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to create global role binding for global role %s: %w", globalRoleName, err) } - globalRoleBindingResource := dynamicClient.Resource(GlobalRoleBindingGroupVersionResource) - unstructuredResp, err := globalRoleBindingResource.Create(context.TODO(), unstructured.MustToUnstructured(globalRoleBinding), metav1.CreateOptions{}) + err = WaitForGrbExistence(client, grb.Name) if err != nil { return nil, err } - newGlobalRoleBinding := &v3.GlobalRoleBinding{} - err = scheme.Scheme.Convert(unstructuredResp, newGlobalRoleBinding, unstructuredResp.GroupVersionKind()) + return grb, nil +} + +// WaitForGrbExistence waits until the GlobalRoleBinding exists based on the provided field (User, UserPrincipal, or Group) +func WaitForGrbExistence(client *rancher.Client, grbName string) error { + return kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (bool, error) { + _, err := client.WranglerContext.Mgmt.GlobalRoleBinding().Get(grbName, metav1.GetOptions{}) + if err != nil { + return false, nil + } + return true, nil + }) +} + +// CreateRoleTemplate creates a cluster or project role template with the provided rules using wrangler context +func CreateRoleTemplate(client *rancher.Client, context string, rules []rbacv1.PolicyRule, inheritedRoleTemplates []*v3.RoleTemplate, external, locked bool, externalRules []rbacv1.PolicyRule) (*v3.RoleTemplate, error) { + var roleTemplateNames []string + for _, inheritedRole := range inheritedRoleTemplates { + if inheritedRole != nil { + roleTemplateNames = append(roleTemplateNames, inheritedRole.Name) + } + } + + displayName := namegen.AppendRandomString("role-template") + + roleTemplate := &v3.RoleTemplate{ + ObjectMeta: metav1.ObjectMeta{ + Name: displayName, + }, + Context: context, + Rules: rules, + DisplayName: displayName, + RoleTemplateNames: roleTemplateNames, + External: external, + ExternalRules: externalRules, + Locked: locked, + } + + createdRoleTemplate, err := client.WranglerContext.Mgmt.RoleTemplate().Create(roleTemplate) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to create RoleTemplate: %w", err) } - return newGlobalRoleBinding, nil + return GetRoleTemplateByName(client, createdRoleTemplate.Name) } -// CreateRoleTemplate is a helper function that uses the dynamic client to create a cluster/project role template for a specific user -func CreateRoleTemplate(client *rancher.Client, roleTemplate *v3.RoleTemplate) (*v3.RoleTemplate, error) { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) +// CreateClusterRoleTemplateBinding creates a cluster role template binding for the user with the provided role template using wrangler context +func CreateClusterRoleTemplateBinding(client *rancher.Client, clusterID string, user *management.User, roleTemplateID string) (*v3.ClusterRoleTemplateBinding, error) { + crtbObj := &v3.ClusterRoleTemplateBinding{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: clusterID, + GenerateName: "crtb-", + }, + ClusterName: clusterID, + UserName: user.ID, + RoleTemplateName: roleTemplateID, + } + + crtb, err := client.WranglerContext.Mgmt.ClusterRoleTemplateBinding().Create(crtbObj) if err != nil { return nil, err } - roleTemplateResource := dynamicClient.Resource(RoleTemplateGroupVersionResource) - unstructuredResp, err := roleTemplateResource.Create(context.Background(), unstructured.MustToUnstructured(roleTemplate), metav1.CreateOptions{}) + err = WaitForCrtbStatus(client, crtb.Namespace, crtb.Name) if err != nil { return nil, err } - newRoleTemplate := &v3.RoleTemplate{} - err = scheme.Scheme.Convert(unstructuredResp, newRoleTemplate, unstructuredResp.GroupVersionKind()) + userClient, err := client.AsUser(user) + if err != nil { + return nil, fmt.Errorf("client as user %s: %w", user.Name, err) + } + + err = extauthz.WaitForAllowed(userClient, clusterID, nil) if err != nil { return nil, err } - return newRoleTemplate, nil + return crtb, nil } -// CreateProjectRoleTemplateBinding is a helper function that uses the dynamic client to create a project role template binding in the local cluster. -func CreateProjectRoleTemplateBinding(client *rancher.Client, prtb *v3.ProjectRoleTemplateBinding) (*v3.ProjectRoleTemplateBinding, error) { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) +// CreateProjectRoleTemplateBinding creates a project role template binding for the user with the provided role template using wrangler context +func CreateProjectRoleTemplateBinding(client *rancher.Client, user *management.User, project *v3.Project, roleTemplateID string) (*v3.ProjectRoleTemplateBinding, error) { + projectName := fmt.Sprintf("%s:%s", project.Namespace, project.Name) + + prtbNamespace := project.Name + if project.Status.BackingNamespace != "" { + prtbNamespace = fmt.Sprintf("%s-%s", project.Spec.ClusterName, project.Name) + } + + prtbObj := &v3.ProjectRoleTemplateBinding{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: prtbNamespace, + GenerateName: "prtb-", + }, + ProjectName: projectName, + UserName: user.ID, + RoleTemplateName: roleTemplateID, + } + + prtbObj, err := client.WranglerContext.Mgmt.ProjectRoleTemplateBinding().Create(prtbObj) if err != nil { return nil, err } - projectRoleTemplateBindingResource := dynamicClient.Resource(ProjectRoleTemplateBindingGroupVersionResource).Namespace(prtb.Namespace) - unstructuredResp, err := projectRoleTemplateBindingResource.Create(context.TODO(), unstructured.MustToUnstructured(prtb), metav1.CreateOptions{}) + prtb, err := WaitForPrtbExistence(client, project, prtbObj, user) + if err != nil { return nil, err } - newprtb := &v3.ProjectRoleTemplateBinding{} - err = scheme.Scheme.Convert(unstructuredResp, newprtb, unstructuredResp.GroupVersionKind()) + userClient, err := client.AsUser(user) + if err != nil { + return nil, fmt.Errorf("client as user %s: %w", user.Name, err) + } + + err = extauthz.WaitForAllowed(userClient, project.Namespace, nil) if err != nil { return nil, err } - return newprtb, nil + return prtb, nil } -// CreateClusterRoleTemplateBinding is a helper function that uses the dynamic client to create a cluster role template binding for a specific user -// in the given downstream cluster. -func CreateClusterRoleTemplateBinding(client *rancher.Client, crtb *v3.ClusterRoleTemplateBinding) (*v3.ClusterRoleTemplateBinding, error) { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) +// CreateGroupClusterRoleTemplateBinding creates Cluster Role Template bindings +func CreateGroupClusterRoleTemplateBinding(client *rancher.Client, clusterID string, groupPrincipalID string, roleTemplateID string) (*v3.ClusterRoleTemplateBinding, error) { + crtbObj := &v3.ClusterRoleTemplateBinding{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: clusterID, + GenerateName: "crtb-", + Annotations: map[string]string{ + "field.cattle.io/creatorId": client.UserID, + }, + }, + ClusterName: clusterID, + GroupPrincipalName: groupPrincipalID, + RoleTemplateName: roleTemplateID, + } + + crtb, err := client.WranglerContext.Mgmt.ClusterRoleTemplateBinding().Create(crtbObj) if err != nil { return nil, err } - clusterRoleTemplateBindingResource := dynamicClient.Resource(ClusterRoleTemplateBindingGroupVersionResource).Namespace(crtb.Namespace) - unstructuredResp, err := clusterRoleTemplateBindingResource.Create(context.Background(), unstructured.MustToUnstructured(crtb), metav1.CreateOptions{}) + err = WaitForCrtbStatus(client, crtb.Namespace, crtb.Name) if err != nil { return nil, err } - newClusterRoleTemplateBinding := &v3.ClusterRoleTemplateBinding{} - err = scheme.Scheme.Convert(unstructuredResp, newClusterRoleTemplateBinding, unstructuredResp.GroupVersionKind()) + return crtb, nil +} + +// CreateGroupProjectRoleTemplateBinding creates Project Role Template bindings for groups +func CreateGroupProjectRoleTemplateBinding(client *rancher.Client, projectID string, projectNamespace string, groupPrincipalID string, roleTemplateID string) (*v3.ProjectRoleTemplateBinding, error) { + prtbObj := &v3.ProjectRoleTemplateBinding{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: projectNamespace, + GenerateName: "prtb-", + }, + ProjectName: projectID, + GroupPrincipalName: groupPrincipalID, + RoleTemplateName: roleTemplateID, + } + + prtb, err := client.WranglerContext.Mgmt.ProjectRoleTemplateBinding().Create(prtbObj) if err != nil { return nil, err } - return newClusterRoleTemplateBinding, nil + return prtb, nil +} + +// CreateGlobalRoleWithInheritedClusterRolesWrangler creates a global role with inherited cluster roles +func CreateGlobalRoleWithInheritedClusterRolesWrangler(client *rancher.Client, inheritedRoles []string) (*v3.GlobalRole, error) { + globalRole := v3.GlobalRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: namegen.AppendRandomString("testgr"), + }, + InheritedClusterRoles: inheritedRoles, + } + + createdGlobalRole, err := client.WranglerContext.Mgmt.GlobalRole().Create(&globalRole) + if err != nil { + return nil, fmt.Errorf("failed to create global role with inherited cluster roles: %w", err) + } + + return createdGlobalRole, nil } diff --git a/actions/kubeapi/rbac/delete.go b/actions/kubeapi/rbac/delete.go index 0f2e16516..f723afa83 100644 --- a/actions/kubeapi/rbac/delete.go +++ b/actions/kubeapi/rbac/delete.go @@ -2,55 +2,160 @@ package rbac import ( "context" + "fmt" "github.com/rancher/shepherd/clients/rancher" + "github.com/rancher/shepherd/extensions/defaults" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kwait "k8s.io/apimachinery/pkg/util/wait" ) -// DeleteGlobalRoleBinding is a helper function that uses the dynamic client to delete a Global Role Binding by name -func DeleteGlobalRoleBinding(client *rancher.Client, globalRoleBindingName string) error { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) +// DeleteGlobalRole is a helper function that uses the dynamic client to delete a Global Role by name +func DeleteGlobalRole(client *rancher.Client, globalRoleName string) error { + dynamicClient, err := client.GetDownStreamClusterClient(clusterapi.LocalCluster) if err != nil { return err } - globalRoleBindingResource := dynamicClient.Resource(GlobalRoleBindingGroupVersionResource) + globalRoleResource := dynamicClient.Resource(GlobalRoleGroupVersionResource) - err = globalRoleBindingResource.Delete(context.TODO(), globalRoleBindingName, metav1.DeleteOptions{}) + err = globalRoleResource.Delete(context.TODO(), globalRoleName, metav1.DeleteOptions{}) if err != nil { return err } return nil } -// DeleteGlobalRole is a helper function that uses the dynamic client to delete a Global Role by name -func DeleteGlobalRole(client *rancher.Client, globalRoleName string) error { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) +// DeleteRoletemplate is a helper function that uses the dynamic client to delete a Custom Cluster Role/ Project Role template by name +func DeleteRoletemplate(client *rancher.Client, roleName string) error { + dynamicClient, err := client.GetDownStreamClusterClient(clusterapi.LocalCluster) if err != nil { return err } - globalRoleResource := dynamicClient.Resource(GlobalRoleGroupVersionResource) + roleResource := dynamicClient.Resource(RoleTemplateGroupVersionResource) - err = globalRoleResource.Delete(context.TODO(), globalRoleName, metav1.DeleteOptions{}) + err = roleResource.Delete(context.TODO(), roleName, metav1.DeleteOptions{}) if err != nil { return err } return nil } -// DeleteRoletemplate is a helper function that uses the dynamic client to delete a Custom Cluster Role/ Project Role template by name -func DeleteRoletemplate(client *rancher.Client, roleName string) error { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) +// DeleteClusterRoleTemplateBinding deletes the cluster role template binding using wrangler context +func DeleteClusterRoleTemplateBinding(client *rancher.Client, crtbNamespace, crtbName string) error { + err := client.WranglerContext.Mgmt.ClusterRoleTemplateBinding().Delete(crtbNamespace, crtbName, &metav1.DeleteOptions{}) if err != nil { - return err + return fmt.Errorf("failed to delete ClusterRoleTemplateBinding %s: %w", crtbName, err) } - roleResource := dynamicClient.Resource(RoleTemplateGroupVersionResource) + err = kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveHundredMillisecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, err error) { + _, err = client.WranglerContext.Mgmt.ClusterRoleTemplateBinding().Get(crtbNamespace, crtbName, metav1.GetOptions{}) + + if apierrors.IsNotFound(err) { + return true, nil + } + + if err != nil { + return false, fmt.Errorf("error checking CRTB deletion status: %w", err) + } + + return false, nil + }) - err = roleResource.Delete(context.TODO(), roleName, metav1.DeleteOptions{}) if err != nil { - return err + return fmt.Errorf("timed out waiting for ClusterRoleTemplateBinding %s to be deleted: %w", crtbName, err) } + return nil } + +// DeleteProjectRoleTemplateBinding deletes the project role template binding using wrangler context +func DeleteProjectRoleTemplateBinding(client *rancher.Client, prtbNamespace, prtbName string) error { + err := client.WranglerContext.Mgmt.ProjectRoleTemplateBinding().Delete(prtbNamespace, prtbName, &metav1.DeleteOptions{}) + if err != nil { + return fmt.Errorf("failed to delete ProjectRoleTemplateBinding %s: %w", prtbName, err) + } + + err = kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, err error) { + _, err = client.WranglerContext.Mgmt.ProjectRoleTemplateBinding().Get(prtbNamespace, prtbName, metav1.GetOptions{}) + + if apierrors.IsNotFound(err) { + return true, nil + } + + if err != nil { + return false, fmt.Errorf("error checking PRTB deletion status: %w", err) + } + + return false, nil + }) + + if err != nil { + return fmt.Errorf("timed out waiting for ProjectRoleTemplateBinding %s to be deleted: %w", prtbName, err) + } + + return nil +} + +// DeleteRoleTemplate deletes a role template by name using wrangler context +func DeleteRoleTemplate(client *rancher.Client, rtName string) error { + err := client.WranglerContext.Mgmt.RoleTemplate().Delete(rtName, nil) + if err != nil { + return fmt.Errorf("failed to delete role template %s: %w", rtName, err) + } + + err = WaitForRoleTemplateDeletion(client, rtName) + if err != nil { + return fmt.Errorf("role template %s not deleted in time: %w", rtName, err) + } + + return nil +} + +// WaitForRoleTemplateDeletion waits until the RoleTemplate is deleted +func WaitForRoleTemplateDeletion(client *rancher.Client, rtName string) error { + return kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, err error) { + _, err = client.WranglerContext.Mgmt.RoleTemplate().Get(rtName, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + return true, nil + } + if err != nil { + return false, nil + } + return false, nil + }, + ) +} + +// DeleteGlobalRoleBinding deletes a global role binding by name using wrangler context +func DeleteGlobalRoleBinding(client *rancher.Client, globalRoleBindingName string) error { + err := client.WranglerContext.Mgmt.GlobalRoleBinding().Delete(globalRoleBindingName, nil) + if err != nil { + return fmt.Errorf("failed to delete global role binding %s: %w", globalRoleBindingName, err) + } + + err = WaitForGlobalRoleBindingDeletion(client, globalRoleBindingName) + if err != nil { + return fmt.Errorf("global role binding %s not deleted in time: %w", globalRoleBindingName, err) + } + + return nil +} + +// WaitForGlobalRoleBindingDeletion waits until the GlobalRoleBinding is deleted +func WaitForGlobalRoleBindingDeletion(client *rancher.Client, globalRoleBindingName string) error { + return kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, err error) { + _, err = client.WranglerContext.Mgmt.GlobalRoleBinding().Get(globalRoleBindingName, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + return true, nil + } + if err != nil { + return false, nil + } + return false, nil + }, + ) +} diff --git a/actions/kubeapi/rbac/list.go b/actions/kubeapi/rbac/list.go index 1e72f1b33..41d00c795 100644 --- a/actions/kubeapi/rbac/list.go +++ b/actions/kubeapi/rbac/list.go @@ -6,6 +6,7 @@ import ( v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3" "github.com/rancher/shepherd/clients/rancher" "github.com/rancher/shepherd/pkg/api/scheme" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -62,7 +63,7 @@ func ListClusterRoleBindings(client *rancher.Client, clusterName string, listOpt // ListGlobalRoleBindings is a helper function that uses the dynamic client to list globalrolebindings from local cluster. func ListGlobalRoleBindings(client *rancher.Client, listOpt metav1.ListOptions) (*v3.GlobalRoleBindingList, error) { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) + dynamicClient, err := client.GetDownStreamClusterClient(clusterapi.LocalCluster) if err != nil { return nil, err } @@ -87,7 +88,7 @@ func ListGlobalRoleBindings(client *rancher.Client, listOpt metav1.ListOptions) // ListClusterRoleTemplateBindings is a helper function that uses the dynamic client to list clusterroletemplatebindings from local cluster. func ListClusterRoleTemplateBindings(client *rancher.Client, listOpt metav1.ListOptions) (*v3.ClusterRoleTemplateBindingList, error) { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) + dynamicClient, err := client.GetDownStreamClusterClient(clusterapi.LocalCluster) if err != nil { return nil, err } @@ -112,7 +113,7 @@ func ListClusterRoleTemplateBindings(client *rancher.Client, listOpt metav1.List // ListGlobalRoles is a helper function that uses the dynamic client to list globalroles from local cluster. func ListGlobalRoles(client *rancher.Client, listOpt metav1.ListOptions) (*v3.GlobalRoleList, error) { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) + dynamicClient, err := client.GetDownStreamClusterClient(clusterapi.LocalCluster) if err != nil { return nil, err } @@ -137,7 +138,7 @@ func ListGlobalRoles(client *rancher.Client, listOpt metav1.ListOptions) (*v3.Gl // ListRoleTemplates is a helper function that uses the dynamic client to list role templates from local cluster. func ListRoleTemplates(client *rancher.Client, listOpt metav1.ListOptions) (*v3.RoleTemplateList, error) { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) + dynamicClient, err := client.GetDownStreamClusterClient(clusterapi.LocalCluster) if err != nil { return nil, err } @@ -162,7 +163,7 @@ func ListRoleTemplates(client *rancher.Client, listOpt metav1.ListOptions) (*v3. // ListProjectRoleTemplateBindings is a helper function that uses the dynamic client to list projectroletemplatebindings from local cluster. func ListProjectRoleTemplateBindings(client *rancher.Client, listOpt metav1.ListOptions) (*v3.ProjectRoleTemplateBindingList, error) { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) + dynamicClient, err := client.GetDownStreamClusterClient(clusterapi.LocalCluster) if err != nil { return nil, err } diff --git a/actions/kubeapi/rbac/rbac.go b/actions/kubeapi/rbac/rbac.go index c3bc9da89..9a0db546a 100644 --- a/actions/kubeapi/rbac/rbac.go +++ b/actions/kubeapi/rbac/rbac.go @@ -1,14 +1,86 @@ package rbac import ( + "context" + "fmt" + "strings" + + "github.com/rancher/norman/types" + v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3" + "github.com/rancher/shepherd/clients/rancher" + management "github.com/rancher/shepherd/clients/rancher/generated/management/v3" + "github.com/rancher/shepherd/extensions/defaults" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" + "github.com/sirupsen/logrus" rbacv1 "k8s.io/api/rbac/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/selection" + kwait "k8s.io/apimachinery/pkg/util/wait" ) const ( - GroupName = "management.cattle.io" - Version = "v3" - LocalCluster = "local" + ManagementAPIGroup = "management.cattle.io" + Version = "v3" + ResourceAggregator = "-aggregator" + ClusterMgmtResourceAggregator = "-cluster-mgmt-aggregator" + ProjectMgmtResourceAggregator = "-project-mgmt-aggregator" + ClusterMgmtResource = "-cluster-mgmt" + ProjectMgmtResource = "-project-mgmt" + AggregatedRoleTemplatesFeatureFlag = "aggregated-roletemplates" + ClusterContext = "cluster" + ProjectContext = "project" + RkeCattleAPIGroup = "rke.cattle.io" + ProjectCattleAPIGroup = "project.cattle.io" + AppsAPIGroup = "apps" + CompletedSummary = "Completed" + MembershipBindingOwnerLabel = "membership-binding-owner" + UsersResource = "users" + UserAttributeResource = "userattribute" + GroupsResource = "groups" + GroupMembersResource = "groupmembers" + ProjectResource = "projects" + PrtbResource = "projectroletemplatebindings" + SecretsResource = "secrets" + DeploymentsResource = "deployments" + PodsResource = "pods" + ManageUsersVerb = "manage-users" + UpdatePsaVerb = "updatepsa" +) + +var ( + ClusterMgmtResources = map[string]string{ + "clusterscans": ManagementAPIGroup, + "clusterregistrationtokens": ManagementAPIGroup, + "clusterroletemplatebindings": ManagementAPIGroup, + "etcdbackups": ManagementAPIGroup, + "nodes": ManagementAPIGroup, + "nodepools": ManagementAPIGroup, + "projects": ManagementAPIGroup, + "etcdsnapshots": RkeCattleAPIGroup, + } + + ProjectMgmtResources = map[string]string{ + "sourcecodeproviderconfigs": ProjectCattleAPIGroup, + "projectroletemplatebindings": ManagementAPIGroup, + "secrets": "", + } + + PolicyRules = map[string][]rbacv1.PolicyRule{ + "readProjects": definePolicyRules([]string{"get", "list"}, []string{"projects"}, []string{ManagementAPIGroup}), + "createProjects": definePolicyRules([]string{"create"}, []string{"projects"}, []string{ManagementAPIGroup}), + "updateProjects": definePolicyRules([]string{"update", "patch"}, []string{"projects"}, []string{ManagementAPIGroup}), + "deleteProjects": definePolicyRules([]string{"delete"}, []string{"projects"}, []string{ManagementAPIGroup}), + "manageProjects": definePolicyRules([]string{"create", "update", "patch", "delete"}, []string{"projects"}, []string{ManagementAPIGroup}), + "readPrtbs": definePolicyRules([]string{"get", "list"}, []string{"projectroletemplatebindings"}, []string{ManagementAPIGroup}), + "updatePrtbs": definePolicyRules([]string{"update", "patch"}, []string{"projectroletemplatebindings"}, []string{ManagementAPIGroup}), + "readDeployments": definePolicyRules([]string{"get", "list"}, []string{"deployments"}, []string{AppsAPIGroup}), + "readPods": definePolicyRules([]string{"get", "list"}, []string{"pods"}, []string{""}), + "readNamespaces": definePolicyRules([]string{"get", "list"}, []string{"namespaces"}, []string{""}), + "readSecrets": definePolicyRules([]string{"get", "list"}, []string{"secrets"}, []string{""}), + } ) // RoleGroupVersionResource is the required Group Version Resource for accessing roles in a cluster, using the dynamic client. @@ -41,35 +113,518 @@ var ClusterRoleBindingGroupVersionResource = schema.GroupVersionResource{ // GlobalRoleGroupVersionResource is the required Group Version Resource for accessing global roles in a rancher server, using the dynamic client. var GlobalRoleGroupVersionResource = schema.GroupVersionResource{ - Group: GroupName, + Group: ManagementAPIGroup, Version: Version, Resource: "globalroles", } // GlobalRoleBindingGroupVersionResource is the required Group Version Resource for accessing clusterrolebindings in a cluster, using the dynamic client. var GlobalRoleBindingGroupVersionResource = schema.GroupVersionResource{ - Group: GroupName, + Group: ManagementAPIGroup, Version: Version, Resource: "globalrolebindings", } // ClusterRoleTemplateBindingGroupVersionResource is the required Group Version Resource for accessing clusterrolebindings in a cluster, using the dynamic client. var ClusterRoleTemplateBindingGroupVersionResource = schema.GroupVersionResource{ - Group: GroupName, + Group: ManagementAPIGroup, Version: Version, Resource: "clusterroletemplatebindings", } // RoleTemplateGroupVersionResource is the required Group Version Resource for accessing roletemplates in a cluster, using the dynamic client. var RoleTemplateGroupVersionResource = schema.GroupVersionResource{ - Group: GroupName, + Group: ManagementAPIGroup, Version: Version, Resource: "roletemplates", } // ProjectRoleTemplateBindingGroupVersionResource is the required Group Version Resource for accessing projectroletemplatebindings in a cluster, using the dynamic client. var ProjectRoleTemplateBindingGroupVersionResource = schema.GroupVersionResource{ - Group: GroupName, + Group: ManagementAPIGroup, Version: Version, Resource: "projectroletemplatebindings", } + +// GetGlobalRoleBindingByName is a helper function to fetch global role binding by name +func GetGlobalRoleBindingByName(client *rancher.Client, globalRoleBindingName string) (*v3.GlobalRoleBinding, error) { + var matchingGRB *v3.GlobalRoleBinding + + err := kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (bool, error) { + var getErr error + matchingGRB, getErr = client.WranglerContext.Mgmt.GlobalRoleBinding().Get(globalRoleBindingName, metav1.GetOptions{}) + if getErr != nil { + return false, nil + } + + return true, nil + }) + + if err != nil { + return nil, fmt.Errorf("error while polling for global role binding %s: %w", globalRoleBindingName, err) + } + + return matchingGRB, nil +} + +// GetGlobalRoleByName is a helper function to fetch global role by name +func GetGlobalRoleByName(client *rancher.Client, globalRoleName string) (*v3.GlobalRole, error) { + return client.WranglerContext.Mgmt.GlobalRole().Get(globalRoleName, metav1.GetOptions{}) +} + +// GetRoleTemplateByName is a helper function to fetch role template by name using wrangler context +func GetRoleTemplateByName(client *rancher.Client, roleTemplateName string) (*v3.RoleTemplate, error) { + var roleTemplate *v3.RoleTemplate + + err := kwait.PollUntilContextTimeout(context.Background(), defaults.FiveHundredMillisecondTimeout, defaults.TenSecondTimeout, false, func(ctx context.Context) (done bool, pollErr error) { + rt, err := client.WranglerContext.Mgmt.RoleTemplate().Get(roleTemplateName, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return false, nil + } + return false, err + } + + roleTemplate = rt + return true, nil + }) + + if err != nil { + return nil, fmt.Errorf("error while polling for role template: %w", err) + } + + return roleTemplate, nil +} + +// GetRoleTemplateContext is a helper function to fetch the context of a role template +func GetRoleTemplateContext(client *rancher.Client, roleTemplateName string) (string, error) { + roleTemplate, err := GetRoleTemplateByName(client, roleTemplateName) + if err != nil { + return "", fmt.Errorf("failed to get RoleTemplate %s: %w", roleTemplateName, err) + } + + if roleTemplate == nil { + return "", fmt.Errorf("RoleTemplate %s not found", roleTemplateName) + } + + return roleTemplate.Context, nil +} + +// GetClusterRolesForRoleTemplates gets ClusterRoles associated with the provided role templates +func GetClusterRolesForRoleTemplates(client *rancher.Client, clusterID string, rtNames ...string) (*rbacv1.ClusterRoleList, error) { + ctx, err := clusterapi.GetClusterWranglerContext(client, clusterID) + if err != nil { + return nil, err + } + + allClusterRoles, err := ctx.RBAC.ClusterRole().List(metav1.ListOptions{}) + if err != nil { + return nil, err + } + + var filtered rbacv1.ClusterRoleList + seen := map[string]bool{} + + for _, cr := range allClusterRoles.Items { + for _, rtName := range rtNames { + if strings.HasPrefix(cr.Name, rtName) && !seen[cr.Name] { + filtered.Items = append(filtered.Items, cr) + seen[cr.Name] = true + break + } + } + } + + return &filtered, nil +} + +// GetClusterRoleRules is a helper function to fetch rules for a cluster role +func GetClusterRoleRules(client *rancher.Client, clusterID string, clusterRoleName string) ([]rbacv1.PolicyRule, error) { + ctx, err := clusterapi.GetClusterWranglerContext(client, clusterID) + if err != nil { + return nil, err + } + + clusterRole, err := ctx.RBAC.ClusterRole().Get(clusterRoleName, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return nil, fmt.Errorf("ClusterRole %s not found", clusterRoleName) + } + return nil, fmt.Errorf("failed to get ClusterRole %s: %w", clusterRoleName, err) + } + + return clusterRole.Rules, nil +} + +// GetClusterRoleTemplateBindingsForGroup polls until a CRTB for the given group principal and cluster is found. +func GetClusterRoleTemplateBindingsForGroup(rancherClient *rancher.Client, groupPrincipalName, clusterID string) (*v3.ClusterRoleTemplateBinding, error) { + var matchingCRTB *v3.ClusterRoleTemplateBinding + err := kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, pollErr error) { + crtbList, err := ListClusterRoleTemplateBindings(rancherClient, metav1.ListOptions{}) + if err != nil { + return false, err + } + for _, crtb := range crtbList.Items { + if crtb.GroupPrincipalName == groupPrincipalName && crtb.ClusterName == clusterID { + matchingCRTB = &crtb + return true, nil + } + } + return false, nil + }) + if err != nil { + return nil, fmt.Errorf("error while polling for group crtb: %w", err) + } + return matchingCRTB, nil +} + +// WaitForCrtbStatus waits for the CRTB to reach the Completed status or checks for its existence if status field is not supported (older Rancher versions) +func WaitForCrtbStatus(client *rancher.Client, crtbNamespace, crtbName string) error { + ctx, cancel := context.WithTimeout(context.Background(), defaults.OneMinuteTimeout) + defer cancel() + + err := kwait.PollUntilContextTimeout(ctx, defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, err error) { + crtb, err := client.WranglerContext.Mgmt.ClusterRoleTemplateBinding().Get(crtbNamespace, crtbName, metav1.GetOptions{}) + if err != nil { + return false, nil + } + + if crtb.Status.Summary == CompletedSummary { + return true, nil + } + + if crtb != nil && crtb.Name == crtbName && crtb.Namespace == crtbNamespace { + return true, nil + } + + return false, nil + }) + + if err != nil { + return fmt.Errorf("timed out waiting for CRTB %s/%s to complete or exist: %w", crtbNamespace, crtbName, err) + } + + return nil +} + +// WaitForPrtbExistence waits for the PRTB to exist with the correct user and project +func WaitForPrtbExistence(client *rancher.Client, project *v3.Project, prtbObj *v3.ProjectRoleTemplateBinding, user *management.User) (*v3.ProjectRoleTemplateBinding, error) { + projectName := fmt.Sprintf("%s:%s", project.Namespace, project.Name) + + var prtb *v3.ProjectRoleTemplateBinding + err := kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.TwoMinuteTimeout, false, func(ctx context.Context) (bool, error) { + var err error + prtb, err = client.WranglerContext.Mgmt.ProjectRoleTemplateBinding().Get(prtbObj.Namespace, prtbObj.Name, metav1.GetOptions{}) + if err != nil { + return false, nil + } + if prtb != nil && prtb.UserName == user.ID && prtb.ProjectName == projectName { + return true, nil + } + + return false, nil + }) + if err != nil { + return nil, err + } + return prtb, nil +} + +// GetRoleBindingsForUsers gets RoleBindings where users are subjects in specific namespaces +func GetRoleBindingsForUsers(client *rancher.Client, userName string, namespaces []string) ([]rbacv1.RoleBinding, error) { + var userRBs []rbacv1.RoleBinding + + for _, namespace := range namespaces { + rbs, err := ListRoleBindings(client, clusterapi.LocalCluster, namespace, metav1.ListOptions{}) + if err != nil { + return nil, fmt.Errorf("failed to list RoleBindings in namespace %s: %w", namespace, err) + } + + for _, rb := range rbs.Items { + for _, subject := range rb.Subjects { + if subject.Kind == "User" && subject.Name == userName { + userRBs = append(userRBs, rb) + } + } + } + } + + return userRBs, nil +} + +func definePolicyRules(verbs, resources, apiGroups []string) []rbacv1.PolicyRule { + return []rbacv1.PolicyRule{{ + Verbs: verbs, + Resources: resources, + APIGroups: apiGroups, + }} +} + +// GetRoleBindings is a helper function to fetch rolebindings for a user +func GetRoleBindings(rancherClient *rancher.Client, clusterID string, userID string) ([]rbacv1.RoleBinding, error) { + logrus.Infof("Getting role bindings for user %s in cluster %s", userID, clusterID) + listOpt := metav1.ListOptions{} + roleBindings, err := ListRoleBindings(rancherClient, clusterID, "", listOpt) + if err != nil { + return nil, fmt.Errorf("failed to fetch RoleBindings: %w", err) + } + + var userRoleBindings []rbacv1.RoleBinding + for _, rb := range roleBindings.Items { + for _, subject := range rb.Subjects { + if subject.Name == userID { + userRoleBindings = append(userRoleBindings, rb) + break + } + } + } + logrus.Infof("Found %d role bindings for user %s", len(userRoleBindings), userID) + return userRoleBindings, nil +} + +// GetBindings is a helper function to fetch bindings for a user +func GetBindings(rancherClient *rancher.Client, userID string) (map[string]interface{}, error) { + bindings := make(map[string]interface{}) + + roleBindings, err := GetRoleBindings(rancherClient, clusterapi.LocalCluster, userID) + if err != nil { + return nil, fmt.Errorf("failed to get role bindings: %w", err) + } + bindings["RoleBindings"] = roleBindings + + clusterRoleBindings, err := ListClusterRoleBindings(rancherClient, clusterapi.LocalCluster, metav1.ListOptions{}) + if err != nil { + return nil, fmt.Errorf("failed to list cluster role bindings: %w", err) + } + bindings["ClusterRoleBindings"] = clusterRoleBindings.Items + + globalRoleBindings, err := rancherClient.Management.GlobalRoleBinding.ListAll(&types.ListOpts{}) + if err != nil { + return nil, fmt.Errorf("failed to list global role bindings: %w", err) + } + bindings["GlobalRoleBindings"] = globalRoleBindings.Data + + clusterRoleTemplateBindings, err := rancherClient.Management.ClusterRoleTemplateBinding.List(&types.ListOpts{}) + if err != nil { + return nil, fmt.Errorf("failed to list cluster role template bindings: %w", err) + } + bindings["ClusterRoleTemplateBindings"] = clusterRoleTemplateBindings.Data + + return bindings, nil +} + +// GetGlobalRoleBindingByUserAndRole is a helper function to fetch global role binding for a user associated with a specific global role +func GetGlobalRoleBindingByUserAndRole(client *rancher.Client, userID, globalRoleName string) (*v3.GlobalRoleBinding, error) { + var matchingGlobalRoleBinding *v3.GlobalRoleBinding + + err := kwait.PollUntilContextTimeout(context.TODO(), defaults.TenSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, pollErr error) { + grblist, err := client.WranglerContext.Mgmt.GlobalRoleBinding().List(metav1.ListOptions{}) + if err != nil { + return false, err + } + + for _, grb := range grblist.Items { + if grb.GlobalRoleName == globalRoleName && grb.UserName == userID { + matchingGlobalRoleBinding = &grb + return true, nil + } + } + + return false, nil + }) + + if err != nil { + return nil, fmt.Errorf("error while polling for global role binding: %w", err) + } + + return matchingGlobalRoleBinding, nil +} + +// GetClusterRoleTemplateBindingsForUser fetches clusterroletemplatebindings for a specific user +func GetClusterRoleTemplateBindingsForUser(rancherClient *rancher.Client, userID string) (*v3.ClusterRoleTemplateBinding, error) { + var matchingCRTB *v3.ClusterRoleTemplateBinding + err := kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, pollErr error) { + crtbList, err := ListClusterRoleTemplateBindings(rancherClient, metav1.ListOptions{}) + if err != nil { + return false, err + } + + for _, crtb := range crtbList.Items { + if crtb.UserName == userID { + matchingCRTB = &crtb + return true, nil + } + } + + return false, nil + }) + + if err != nil { + return nil, fmt.Errorf("error while polling for crtb: %w", err) + } + + return matchingCRTB, nil +} + +// ListCRTBsByLabel lists ClusterRoleTemplateBindings by label selector +func ListCRTBsByLabel(client *rancher.Client, labelKey, labelValue string, expectedCount int) (*v3.ClusterRoleTemplateBindingList, error) { + req, err := labels.NewRequirement(labelKey, selection.In, []string{labelValue}) + if err != nil { + return nil, err + } + + selector := labels.NewSelector().Add(*req) + var crtbs *v3.ClusterRoleTemplateBindingList + + ctx, cancel := context.WithTimeout(context.Background(), defaults.TwoMinuteTimeout) + defer cancel() + + err = kwait.PollUntilContextTimeout(ctx, defaults.FiveSecondTimeout, defaults.TwoMinuteTimeout, false, func(ctx context.Context) (done bool, pollErr error) { + crtbs, pollErr = ListClusterRoleTemplateBindings(client, metav1.ListOptions{ + LabelSelector: selector.String(), + }) + if pollErr != nil { + return false, pollErr + } + + if expectedCount == 0 { + return true, nil + } + + if len(crtbs.Items) == expectedCount { + return true, nil + } + + return false, nil + }) + + if err != nil { + if crtbs != nil { + return crtbs, fmt.Errorf("timed out waiting for ClusterRoleTemplateBindings count to match expected: %d, actual: %d, error: %w", + expectedCount, len(crtbs.Items), err) + } + return nil, err + } + + return crtbs, nil +} + +// GetRoleBindingsForCRTBs gets RoleBindings based on ClusterRoleTemplateBindings +func GetRoleBindingsForCRTBs(client *rancher.Client, crtbs *v3.ClusterRoleTemplateBindingList) (*rbacv1.RoleBindingList, error) { + var downstreamRBs rbacv1.RoleBindingList + + for _, crtb := range crtbs.Items { + roleTemplateName := crtb.RoleTemplateName + if strings.Contains(roleTemplateName, "rt") { + listOpt := metav1.ListOptions{ + FieldSelector: "metadata.name=" + roleTemplateName, + } + roleTemplateList, err := ListRoleTemplates(client, listOpt) + if err != nil { + return nil, err + } + if len(roleTemplateList.Items) > 0 { + roleTemplateName = roleTemplateList.Items[0].RoleTemplateNames[0] + } + } + + nameSelector := fmt.Sprintf("metadata.name=%s-%s", crtb.Name, roleTemplateName) + namespaceSelector := fmt.Sprintf("metadata.namespace=%s", crtb.ClusterName) + combinedSelector := fmt.Sprintf("%s,%s", nameSelector, namespaceSelector) + downstreamRBsForCRTB, err := ListRoleBindings(client, clusterapi.LocalCluster, "", metav1.ListOptions{ + FieldSelector: combinedSelector, + }) + if err != nil { + return nil, err + } + + downstreamRBs.Items = append(downstreamRBs.Items, downstreamRBsForCRTB.Items...) + } + + return &downstreamRBs, nil +} + +// GetClusterRoleBindingsForCRTBs gets ClusterRoleBindings based on ClusterRoleTemplateBindings using labels +func GetClusterRoleBindingsForCRTBs(client *rancher.Client, crtbs *v3.ClusterRoleTemplateBindingList) (*rbacv1.ClusterRoleBindingList, error) { + var downstreamCRBs rbacv1.ClusterRoleBindingList + + for _, crtb := range crtbs.Items { + labelKey := fmt.Sprintf("%s_%s", crtb.ClusterName, crtb.Name) + req, err := labels.NewRequirement(labelKey, selection.In, []string{MembershipBindingOwnerLabel}) + if err != nil { + return nil, err + } + + selector := labels.NewSelector().Add(*req) + downstreamCRBsForCRTB, err := ListClusterRoleBindings(client, clusterapi.LocalCluster, metav1.ListOptions{ + LabelSelector: selector.String(), + }) + if err != nil { + return nil, err + } + + downstreamCRBs.Items = append(downstreamCRBs.Items, downstreamCRBsForCRTB.Items...) + } + + return &downstreamCRBs, nil +} + +// GetClusterRoleBindingsForUsers gets ClusterRoleBindings where users from CRTBs are subjects +func GetClusterRoleBindingsForUsers(client *rancher.Client, crtbs *v3.ClusterRoleTemplateBindingList) ([]rbacv1.ClusterRoleBinding, error) { + var userCRBs []rbacv1.ClusterRoleBinding + + for _, crtb := range crtbs.Items { + crbs, err := ListClusterRoleBindings(client, clusterapi.LocalCluster, metav1.ListOptions{}) + if err != nil { + return nil, err + } + + for _, crb := range crbs.Items { + for _, subject := range crb.Subjects { + if subject.Kind == "User" && subject.Name == crtb.UserName { + userCRBs = append(userCRBs, crb) + } + } + } + } + + return userCRBs, nil +} + +// SetAggregatedClusterRoleFeatureFlag sets the aggregated cluster role feature flag to the specified value +func SetAggregatedClusterRoleFeatureFlag(client *rancher.Client, value bool) error { + feature, err := client.WranglerContext.Mgmt.Feature().Get(AggregatedRoleTemplatesFeatureFlag, metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("failed to fetch feature %s: %w", AggregatedRoleTemplatesFeatureFlag, err) + } + + feature.Spec.Value = &value + + _, err = client.WranglerContext.Mgmt.Feature().Update(feature) + if err != nil { + return fmt.Errorf("failed to update feature %s: %w", AggregatedRoleTemplatesFeatureFlag, err) + } + + return kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (bool, error) { + updatedFeature, getErr := client.WranglerContext.Mgmt.Feature().Get(AggregatedRoleTemplatesFeatureFlag, metav1.GetOptions{}) + if getErr != nil { + return false, nil + } + + if updatedFeature.Spec.Value != nil && *updatedFeature.Spec.Value == value { + return true, nil + } + + return false, nil + }) +} + +// IsFeatureEnabled checks if a feature is enabled based on its Spec.Value +func IsFeatureEnabled(client *rancher.Client, featureName string) (bool, error) { + feature, err := client.WranglerContext.Mgmt.Feature().Get(AggregatedRoleTemplatesFeatureFlag, metav1.GetOptions{}) + if err != nil { + return false, fmt.Errorf("failed to fetch feature %s: %w", featureName, err) + } + + return feature.Spec.Value != nil && *feature.Spec.Value, nil +} diff --git a/actions/kubeapi/rbac/update.go b/actions/kubeapi/rbac/update.go index f5e1c5877..e36eacd3b 100644 --- a/actions/kubeapi/rbac/update.go +++ b/actions/kubeapi/rbac/update.go @@ -2,17 +2,19 @@ package rbac import ( "context" + "fmt" v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3" "github.com/rancher/shepherd/clients/rancher" "github.com/rancher/shepherd/extensions/unstructured" "github.com/rancher/shepherd/pkg/api/scheme" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // UpdateGlobalRole is a helper function that uses the dynamic client to update a Global Role func UpdateGlobalRole(client *rancher.Client, updatedGlobalRole *v3.GlobalRole) (*v3.GlobalRole, error) { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) + dynamicClient, err := client.GetDownStreamClusterClient(clusterapi.LocalCluster) if err != nil { return nil, err } @@ -45,7 +47,7 @@ func UpdateGlobalRole(client *rancher.Client, updatedGlobalRole *v3.GlobalRole) // UpdateRoleTemplate is a helper function that uses the dynamic client to update an existing cluster role template func UpdateRoleTemplate(client *rancher.Client, updatedRoleTemplate *v3.RoleTemplate) (*v3.RoleTemplate, error) { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) + dynamicClient, err := client.GetDownStreamClusterClient(clusterapi.LocalCluster) if err != nil { return nil, err } @@ -79,7 +81,7 @@ func UpdateRoleTemplate(client *rancher.Client, updatedRoleTemplate *v3.RoleTemp // UpdateClusterRoleTemplateBindings is a helper function that uses the dynamic client to update an existing cluster role template binding func UpdateClusterRoleTemplateBindings(client *rancher.Client, existingCRTB *v3.ClusterRoleTemplateBinding, updatedCRTB *v3.ClusterRoleTemplateBinding) (*v3.ClusterRoleTemplateBinding, error) { - dynamicClient, err := client.GetDownStreamClusterClient(LocalCluster) + dynamicClient, err := client.GetDownStreamClusterClient(clusterapi.LocalCluster) if err != nil { return nil, err } @@ -110,3 +112,27 @@ func UpdateClusterRoleTemplateBindings(client *rancher.Client, existingCRTB *v3. return newCRTB, nil } + +// UpdateRoleTemplateInheritance updates the inheritance of a role template using wrangler context +func UpdateRoleTemplateInheritance(client *rancher.Client, roleTemplateName string, inheritedRoles []*v3.RoleTemplate) (*v3.RoleTemplate, error) { + var roleTemplateNames []string + for _, inheritedRole := range inheritedRoles { + if inheritedRole != nil { + roleTemplateNames = append(roleTemplateNames, inheritedRole.Name) + } + } + + existingRoleTemplate, err := GetRoleTemplateByName(client, roleTemplateName) + if err != nil { + return nil, fmt.Errorf("failed to get existing RoleTemplate: %w", err) + } + + existingRoleTemplate.RoleTemplateNames = roleTemplateNames + + updatedRoleTemplate, err := client.WranglerContext.Mgmt.RoleTemplate().Update(existingRoleTemplate) + if err != nil { + return nil, fmt.Errorf("failed to update RoleTemplate inheritance: %w", err) + } + + return GetRoleTemplateByName(client, updatedRoleTemplate.Name) +} diff --git a/actions/kubeapi/rbac/verify.go b/actions/kubeapi/rbac/verify.go new file mode 100644 index 000000000..0231633fc --- /dev/null +++ b/actions/kubeapi/rbac/verify.go @@ -0,0 +1,581 @@ +package rbac + +import ( + "fmt" + "reflect" + "regexp" + "slices" + "strings" + + v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3" + "github.com/rancher/shepherd/clients/rancher" + management "github.com/rancher/shepherd/clients/rancher/generated/management/v3" + "github.com/rancher/shepherd/pkg/wrangler" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" + projectapi "github.com/rancher/tests/actions/kubeapi/projects" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// VerifyClusterRoleTemplateBindingForUser is a helper function to verify the number of cluster role template bindings for a user +func VerifyClusterRoleTemplateBindingForUser(client *rancher.Client, username string, expectedCount int) ([]v3.ClusterRoleTemplateBinding, error) { + crtbList, err := ListClusterRoleTemplateBindings(client, metav1.ListOptions{}) + if err != nil { + return nil, fmt.Errorf("failed to list ClusterRoleTemplateBindings: %w", err) + } + + userCrtbs := []v3.ClusterRoleTemplateBinding{} + actualCount := 0 + for _, crtb := range crtbList.Items { + if crtb.UserName == username { + userCrtbs = append(userCrtbs, crtb) + actualCount++ + } + } + + if actualCount != expectedCount { + return nil, fmt.Errorf("expected %d ClusterRoleTemplateBindings for user %s, but found %d", + expectedCount, username, actualCount) + } + + return userCrtbs, nil +} + +// VerifyProjectRoleTemplateBindingForUser is a helper function to verify the number of project role template bindings for a user +func VerifyProjectRoleTemplateBindingForUser(client *rancher.Client, username string, expectedCount int) ([]v3.ProjectRoleTemplateBinding, error) { + prtbList, err := ListProjectRoleTemplateBindings(client, metav1.ListOptions{}) + if err != nil { + return nil, fmt.Errorf("failed to list ProjectRoleTemplateBindings: %w", err) + } + + userPrtbs := []v3.ProjectRoleTemplateBinding{} + actualCount := 0 + for _, prtb := range prtbList.Items { + if prtb.UserName == username { + userPrtbs = append(userPrtbs, prtb) + actualCount++ + } + } + + if actualCount != expectedCount { + return nil, fmt.Errorf("expected %d ProjectRoleTemplateBindings for user %s, but found %d", + expectedCount, username, actualCount) + } + + return userPrtbs, nil +} + +// VerifyRoleRules checks if the expected role rules match the actual rules. +func VerifyRoleRules(expected, actual map[string][]string) error { + for resource, expectedVerbs := range expected { + actualVerbs, exists := actual[resource] + if !exists { + return fmt.Errorf("resource %s not found in role rules", resource) + } + + expectedSet := make(map[string]struct{}) + for _, verb := range expectedVerbs { + expectedSet[verb] = struct{}{} + } + + for _, verb := range actualVerbs { + if _, found := expectedSet[verb]; !found { + return fmt.Errorf("verbs for resource %s do not match: expected %v, got %v", resource, expectedVerbs, actualVerbs) + } + } + } + return nil +} + +// VerifyUserPermission validates that a user has the expected permissions for a given resource +func VerifyUserPermission(client *rancher.Client, clusterID string, user *management.User, verb, resourceType, namespaceName, resourceName string, expected, isCRDInLocalCluster bool) error { + allowed, err := CheckUserAccess(client, clusterID, user, verb, resourceType, namespaceName, resourceName, isCRDInLocalCluster) + + if expected { + if err != nil { + if apierrors.IsForbidden(err) { + return fmt.Errorf("user should have '%s' access to %s/%s/%s, but got forbidden error: %v", verb, resourceType, namespaceName, resourceName, err) + } + return fmt.Errorf("error verifying user access to %s/%s/%s: %v", resourceType, namespaceName, resourceName, err) + } + if !allowed { + return fmt.Errorf("user should have '%s' access to %s/%s/%s, but access was denied", verb, resourceType, namespaceName, resourceName) + } + } else { + if err == nil && allowed { + return fmt.Errorf("expected '%s' access to %s/%s/%s to be denied, but access was granted", verb, resourceType, namespaceName, resourceName) + } + if err != nil && !apierrors.IsForbidden(err) { + return fmt.Errorf("expected forbidden error for %s/%s/%s, but got: %v", resourceType, namespaceName, resourceName, err) + } + } + + return nil +} + +// CheckUserAccess checks if a user has the specified access to a resource in a cluster. It returns true if the user has access, false otherwise. +func CheckUserAccess(client *rancher.Client, clusterID string, user *management.User, verb, resourceType, namespaceName, resourceName string, isCRDInLocalCluster bool) (bool, error) { + userClient, err := client.AsUser(user) + if err != nil { + return false, fmt.Errorf("failed to create user client: %w", err) + } + + var userContext *wrangler.Context + if isCRDInLocalCluster { + userContext, err = clusterapi.GetClusterWranglerContext(userClient, clusterapi.LocalCluster) + } else { + userContext, err = clusterapi.GetClusterWranglerContext(userClient, clusterID) + } + + if err != nil { + return false, fmt.Errorf("failed to get user context: %w", err) + } + + switch resourceType { + case "projects": + return CheckProjectAccess(userContext, verb, clusterID, resourceName) + case "namespaces": + return CheckNamespaceAccess(userContext, verb, resourceName) + case "deployments": + return CheckDeploymentAccess(userContext, verb, namespaceName, resourceName) + case "pods": + return CheckPodAccess(userContext, verb, namespaceName, resourceName) + case "secrets": + return CheckSecretAccess(userContext, verb, namespaceName, resourceName) + case "projectroletemplatebindings": + return CheckPrtbAccess(userContext, verb, namespaceName, resourceName) + case "configmaps": + return CheckConfigMapAccess(userContext, verb, namespaceName, resourceName) + default: + return false, fmt.Errorf("checks for resource type '%s' not added", resourceType) + } +} + +// CheckProjectAccess checks if a user has the specified access to a project in a cluster. It returns true if the user has access, false otherwise. +func CheckProjectAccess(userContext *wrangler.Context, verb, clusterID, projectName string) (bool, error) { + switch verb { + case "get": + _, err := userContext.Mgmt.Project().Get(clusterID, projectName, metav1.GetOptions{}) + return err == nil, err + case "list": + _, err := userContext.Mgmt.Project().List(clusterID, metav1.ListOptions{}) + return err == nil, err + case "create": + projectTemplate := projectapi.NewProjectTemplate(clusterID) + _, err := userContext.Mgmt.Project().Create(projectTemplate) + return err == nil, err + case "delete": + err := userContext.Mgmt.Project().Delete(clusterID, projectName, &metav1.DeleteOptions{}) + return err == nil, err + case "update": + project, err := userContext.Mgmt.Project().Get(clusterID, projectName, metav1.GetOptions{}) + if err != nil { + return false, err + } + if project.Labels == nil { + project.Labels = make(map[string]string) + } + project.Labels["hello"] = "world" + _, err = userContext.Mgmt.Project().Update(project) + return err == nil, err + case "patch": + patchData := []byte(`{"metadata":{"annotations":{"patched":"true"}}}`) + _, err := userContext.Mgmt.Project().Patch(clusterID, projectName, types.MergePatchType, patchData) + return err == nil, err + default: + return false, fmt.Errorf("verb '%s' not available in checks for projects", verb) + } +} + +// CheckNamespaceAccess checks if a user has the specified access to a namespace in a cluster. It returns true if the user has access, false otherwise. +func CheckNamespaceAccess(userContext *wrangler.Context, verb, namespaceName string) (bool, error) { + switch verb { + case "get": + _, err := userContext.Core.Namespace().Get(namespaceName, metav1.GetOptions{}) + return err == nil, err + case "list": + _, err := userContext.Core.Namespace().List(metav1.ListOptions{}) + return err == nil, err + case "delete": + err := userContext.Core.Namespace().Delete(namespaceName, &metav1.DeleteOptions{}) + return err == nil, err + default: + return false, fmt.Errorf("verb '%s' not available in checks for resource 'namespaces'", verb) + } +} + +// CheckPodAccess checks if a user has the specified access to a pod in a namespace. It returns true if the user has access, false otherwise. +func CheckPodAccess(userContext *wrangler.Context, verb, namespaceName, podName string) (bool, error) { + switch verb { + case "get": + _, err := userContext.Core.Pod().Get(namespaceName, podName, metav1.GetOptions{}) + return err == nil, err + case "list": + _, err := userContext.Core.Pod().List(namespaceName, metav1.ListOptions{}) + return err == nil, err + case "delete": + err := userContext.Core.Pod().Delete(namespaceName, podName, &metav1.DeleteOptions{}) + return err == nil, err + default: + return false, fmt.Errorf("verb '%s' not available in checks for resource 'pods'", verb) + } +} + +// CheckDeploymentAccess checks if a user has the specified access to a deployment in a namespace. It returns true if the user has access, false otherwise. +func CheckDeploymentAccess(userContext *wrangler.Context, verb, namespaceName, deploymentName string) (bool, error) { + switch verb { + case "get": + _, err := userContext.Apps.Deployment().Get(namespaceName, deploymentName, metav1.GetOptions{}) + return err == nil, err + case "list": + _, err := userContext.Apps.Deployment().List(namespaceName, metav1.ListOptions{}) + return err == nil, err + case "delete": + err := userContext.Apps.Deployment().Delete(namespaceName, deploymentName, &metav1.DeleteOptions{}) + return err == nil, err + default: + return false, fmt.Errorf("verb '%s' not available in checks for resource 'deployments'", verb) + } +} + +// CheckSecretAccess checks if a user has the specified access to a secret in a namespace. It returns true if the user has access, false otherwise. +func CheckSecretAccess(userContext *wrangler.Context, verb, namespaceName, secretName string) (bool, error) { + switch verb { + case "get": + _, err := userContext.Core.Secret().Get(namespaceName, secretName, metav1.GetOptions{}) + return err == nil, err + case "list": + _, err := userContext.Core.Secret().List(namespaceName, metav1.ListOptions{}) + return err == nil, err + case "delete": + err := userContext.Core.Secret().Delete(namespaceName, secretName, &metav1.DeleteOptions{}) + return err == nil, err + default: + return false, fmt.Errorf("verb '%s' not available in checks for resource 'namespaces'", verb) + } +} + +// CheckPrtbAccess checks if a user has the specified access to a project role template binding in a namespace. It returns true if the user has access, false otherwise. +func CheckPrtbAccess(userContext *wrangler.Context, verb, prtbNamespace, prtbName string) (bool, error) { + switch verb { + case "get": + _, err := userContext.Mgmt.ProjectRoleTemplateBinding().Get(prtbNamespace, prtbName, metav1.GetOptions{}) + return err == nil, err + case "list": + _, err := userContext.Mgmt.ProjectRoleTemplateBinding().List(prtbNamespace, metav1.ListOptions{}) + return err == nil, err + case "delete": + err := userContext.Mgmt.ProjectRoleTemplateBinding().Delete(prtbNamespace, prtbName, &metav1.DeleteOptions{}) + return err == nil, err + case "update": + prtb, err := userContext.Mgmt.ProjectRoleTemplateBinding().Get(prtbNamespace, prtbName, metav1.GetOptions{}) + if err != nil { + return false, err + } + if prtb.Labels == nil { + prtb.Labels = make(map[string]string) + } + prtb.Labels["hello"] = "world" + _, err = userContext.Mgmt.ProjectRoleTemplateBinding().Update(prtb) + return err == nil, err + case "patch": + patchData := []byte(`{"metadata":{"annotations":{"patched":"true"}}}`) + _, err := userContext.Mgmt.ProjectRoleTemplateBinding().Patch(prtbNamespace, prtbName, types.MergePatchType, patchData) + return err == nil, err + default: + return false, fmt.Errorf("verb '%s' not available in checks for prtbs", verb) + } +} + +// CheckConfigMapAccess checks if a user has the specified access to a ConfigMap in a namespace. It returns true if the user has access, false otherwise. +func CheckConfigMapAccess(userContext *wrangler.Context, verb, namespaceName, configMapName string) (bool, error) { + switch verb { + case "get": + _, err := userContext.Core.ConfigMap().Get(namespaceName, configMapName, metav1.GetOptions{}) + return err == nil, err + case "list": + _, err := userContext.Core.ConfigMap().List(namespaceName, metav1.ListOptions{}) + return err == nil, err + case "delete": + err := userContext.Core.ConfigMap().Delete(namespaceName, configMapName, &metav1.DeleteOptions{}) + return err == nil, err + default: + return false, fmt.Errorf("verb '%s' not available in checks for resource 'configmaps'", verb) + } +} + +// VerifyBindingsForCrtb verifies RoleBindings and ClusterRoleBindings for a given CRTB +func VerifyBindingsForCrtb(client *rancher.Client, clusterID string, crtb *v3.ClusterRoleTemplateBinding, expectedRoleBindingCount, expectedClusterRoleBindingCount int) error { + return verifyBindings(client, clusterID, crtb.UserName, crtb.RoleTemplateName, crtb.Name, []string{crtb.Namespace}, expectedRoleBindingCount, expectedClusterRoleBindingCount) +} + +// VerifyBindingsForPrtb verifies RoleBindings and ClusterRoleBindings for a given PRTB +func VerifyBindingsForPrtb(client *rancher.Client, clusterID string, prtb *v3.ProjectRoleTemplateBinding, namespaces []*corev1.Namespace, expectedRoleBindingCount, expectedClusterRoleBindingCount int) error { + namespaceNames := []string{} + defaultNamespace := strings.SplitN(prtb.ProjectName, ":", 2)[0] + + if len(namespaces) == 0 { + namespaceNames = append(namespaceNames, defaultNamespace) + } else { + for _, ns := range namespaces { + namespaceNames = append(namespaceNames, ns.Name) + } + } + + return verifyBindings(client, clusterID, prtb.UserName, prtb.RoleTemplateName, prtb.Name, namespaceNames, expectedRoleBindingCount, expectedClusterRoleBindingCount) +} + +// VerifyMainACRContainsAllRules verifies that the main ACR contains all rules from the main role template and its child role templates +func VerifyMainACRContainsAllRules(client *rancher.Client, clusterID, mainRTName string, childRTNames []string) error { + mainRules, err := GetClusterRoleRules(client, clusterID, mainRTName) + if err != nil { + return fmt.Errorf("failed to get mainRole rules: %w", err) + } + + var allChildRules []rbacv1.PolicyRule + for _, childRTName := range childRTNames { + childRules, err := GetClusterRoleRules(client, clusterID, childRTName) + if err != nil { + return fmt.Errorf("failed to get childRole rules %s: %w", childRTName, err) + } + allChildRules = append(allChildRules, childRules...) + } + + expectedRules := append(mainRules, allChildRules...) + + acrNameRegular := mainRTName + ResourceAggregator + actualRulesRegular, err := GetClusterRoleRules(client, clusterID, acrNameRegular) + if err != nil { + return fmt.Errorf("failed to get ACR %s: %w", acrNameRegular, err) + } + + if !ruleSlicesMatch(actualRulesRegular, expectedRules) { + return fmt.Errorf("ACR %s rules do not match expected combined rules", acrNameRegular) + } + + return nil +} + +// VerifyClusterMgmtACR verifies that the cluster management ACR contains all rules from the main role template and its child role templates +func VerifyClusterMgmtACR(client *rancher.Client, clusterID, mainRTName string, childRTNames []string) error { + acrName := mainRTName + ClusterMgmtResourceAggregator + return verifyMgmtACR(client, clusterID, acrName, mainRTName, childRTNames, ClusterContext) +} + +// VerifyProjectMgmtACR verifies that the project management ACR contains all rules from the main role template and its child role templates +func VerifyProjectMgmtACR(client *rancher.Client, clusterID, mainRTName string, childRTNames []string) error { + acrName := mainRTName + ProjectMgmtResourceAggregator + return verifyMgmtACR(client, clusterID, acrName, mainRTName, childRTNames, ProjectContext) +} + +func ruleSlicesMatch(rules1, rules2 []rbacv1.PolicyRule) bool { + rules1Copy := slices.Clone(rules1) + rules2Copy := slices.Clone(rules2) + + slices.SortFunc(rules1Copy, comparePolicyRules) + slices.SortFunc(rules2Copy, comparePolicyRules) + + return reflect.DeepEqual(rules1Copy, rules2Copy) +} + +func comparePolicyRules(a, b rbacv1.PolicyRule) int { + if cmp := compareSlices(a.Verbs, b.Verbs); cmp != 0 { + return cmp + } + if cmp := compareSlices(a.APIGroups, b.APIGroups); cmp != 0 { + return cmp + } + if cmp := compareSlices(a.Resources, b.Resources); cmp != 0 { + return cmp + } + if cmp := compareSlices(a.ResourceNames, b.ResourceNames); cmp != 0 { + return cmp + } + return compareSlices(a.NonResourceURLs, b.NonResourceURLs) +} + +func compareSlices(a, b []string) int { + minLen := len(a) + if len(b) < minLen { + minLen = len(b) + } + + for i := 0; i < minLen; i++ { + if a[i] < b[i] { + return -1 + } else if a[i] > b[i] { + return 1 + } + } + return len(a) - len(b) +} + +func verifyMgmtACR(client *rancher.Client, clusterID, acrName, mainRTName string, childRTNames []string, managementContext string) error { + mainRules, err := GetClusterRoleRules(client, clusterID, mainRTName) + if err != nil { + return err + } + + allChildRules := []rbacv1.PolicyRule{} + for _, childRTName := range childRTNames { + childRules, err := GetClusterRoleRules(client, clusterID, childRTName) + if err != nil { + return err + } + allChildRules = append(allChildRules, childRules...) + } + + expectedRules := append(mainRules, allChildRules...) + mgmtRules := filterMgmtRules(expectedRules, managementContext) + + acrRules, err := GetClusterRoleRules(client, clusterID, acrName) + if err != nil { + return fmt.Errorf("failed to get ACR %s: %w", acrName, err) + } + + if !ruleSlicesMatch(acrRules, mgmtRules) { + return fmt.Errorf("ACR %s rules do not match expected combined rules.\nExpected: %+v\nActual: %+v", acrName, mgmtRules, acrRules) + } + + return nil +} + +func filterMgmtRules(rules []rbacv1.PolicyRule, mgmtType string) []rbacv1.PolicyRule { + var filteredRules []rbacv1.PolicyRule + for _, rule := range rules { + if (mgmtType == ClusterContext && isMgmtRule(rule, ClusterContext)) || (mgmtType == ProjectContext && isMgmtRule(rule, ProjectContext)) { + filteredRules = append(filteredRules, rule) + } + } + return filteredRules +} + +func isMgmtRule(rule rbacv1.PolicyRule, resourceContext string) bool { + resourceMap := ClusterMgmtResources + if resourceContext == ProjectContext { + resourceMap = ProjectMgmtResources + } + + for _, group := range rule.APIGroups { + if (resourceContext == ClusterContext && (group == ManagementAPIGroup || group == RkeCattleAPIGroup)) || + (resourceContext == ProjectContext && (group == ProjectCattleAPIGroup || group == ManagementAPIGroup || group == "")) { + for _, resource := range rule.Resources { + if _, ok := resourceMap[resource]; ok { + return true + } + } + } + } + + return false +} + +func verifyBindings(client *rancher.Client, clusterID, userName, roleTemplateName, roleTemplateBindingName string, namespaces []string, expectedRBCount, expectedCRBCount int) error { + ctx, err := clusterapi.GetClusterWranglerContext(client, clusterID) + if err != nil { + return err + } + + for _, ns := range namespaces { + rbs, err := ctx.RBAC.RoleBinding().List(ns, metav1.ListOptions{}) + if err != nil { + return fmt.Errorf("failed to list RoleBindings in namespace %s: %w", ns, err) + } + + filtered := filterRoleBindings(rbs, userName, roleTemplateName) + if len(filtered) != expectedRBCount { + return fmt.Errorf("expected %d RoleBindings for user %s in namespace %s, got %d", + expectedRBCount, userName, ns, len(filtered)) + } + + if expectedRBCount > 0 { + expected := expectedRoleNames(clusterID, roleTemplateBindingName, roleTemplateName, expectedRBCount) + expectedSet := make(map[string]struct{}, len(expected)) + for _, name := range expected { + expectedSet[name] = struct{}{} + } + + for _, rb := range filtered { + if _, ok := expectedSet[rb.RoleRef.Name]; !ok { + return fmt.Errorf("unexpected RoleBinding RoleRef.Name %s, expected %v", + rb.RoleRef.Name, expected) + } + } + } + } + + crbs, err := ctx.RBAC.ClusterRoleBinding().List(metav1.ListOptions{}) + if err != nil { + return fmt.Errorf("failed to list ClusterRoleBindings: %w", err) + } + + filteredCRBs := filterClusterRoleBindings(crbs, userName, roleTemplateName) + if len(filteredCRBs) != expectedCRBCount { + return fmt.Errorf("expected %d ClusterRoleBindings, got %d", + expectedCRBCount, len(filteredCRBs)) + } + + if expectedCRBCount > 0 { + expected := expectedRoleNames(clusterID, roleTemplateBindingName, roleTemplateName, expectedCRBCount) + expectedSet := make(map[string]struct{}, len(expected)) + for _, name := range expected { + expectedSet[name] = struct{}{} + } + + for _, crb := range filteredCRBs { + if _, ok := expectedSet[crb.RoleRef.Name]; !ok { + return fmt.Errorf("unexpected ClusterRoleBinding RoleRef.Name %s, expected %v", + crb.RoleRef.Name, expected) + } + } + } + + return nil +} + +func expectedRoleNames(clusterID, bindingName, rtName string, count int) []string { + if clusterID != clusterapi.LocalCluster { + return []string{rtName + ResourceAggregator} + } + + if strings.Contains(bindingName, "prtb") { + return []string{rtName + ProjectMgmtResourceAggregator} + } + + roles := []string{rtName + ClusterMgmtResourceAggregator} + if count > 1 { + roles = append(roles, rtName+ProjectMgmtResourceAggregator) + } + return roles +} + +func filterRoleBindings(roleBindings *rbacv1.RoleBindingList, userName, roleTemplateName string) []rbacv1.RoleBinding { + var filteredRBs []rbacv1.RoleBinding + re := regexp.MustCompile("^" + regexp.QuoteMeta(roleTemplateName)) + + for _, rb := range roleBindings.Items { + for _, subject := range rb.Subjects { + if subject.Kind == rbacv1.UserKind && subject.Name == userName && re.MatchString(rb.RoleRef.Name) { + filteredRBs = append(filteredRBs, rb) + } + } + } + return filteredRBs +} + +func filterClusterRoleBindings(clusterRoleBindings *rbacv1.ClusterRoleBindingList, userName, roleTemplateName string) []rbacv1.ClusterRoleBinding { + var filteredCRBs []rbacv1.ClusterRoleBinding + re := regexp.MustCompile("^" + regexp.QuoteMeta(roleTemplateName)) + + for _, rb := range clusterRoleBindings.Items { + for _, subject := range rb.Subjects { + if subject.Kind == rbacv1.UserKind && subject.Name == userName && re.MatchString(rb.RoleRef.Name) { + filteredCRBs = append(filteredCRBs, rb) + } + } + } + return filteredCRBs +} diff --git a/actions/rbac/rbac.go b/actions/rbac/rbac.go index 3789cfa29..98793f06f 100644 --- a/actions/rbac/rbac.go +++ b/actions/rbac/rbac.go @@ -1,84 +1,61 @@ package rbac import ( - "context" "fmt" - "strings" - "github.com/rancher/norman/types" v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3" "github.com/rancher/shepherd/clients/rancher" management "github.com/rancher/shepherd/clients/rancher/generated/management/v3" - "github.com/rancher/shepherd/extensions/defaults" - extauthz "github.com/rancher/shepherd/extensions/kubeapi/authorization" "github.com/rancher/shepherd/extensions/users" - namegen "github.com/rancher/shepherd/pkg/namegenerator" - "github.com/rancher/shepherd/pkg/wrangler" rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" - "github.com/sirupsen/logrus" - rbacv1 "k8s.io/api/rbac/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/selection" - kwait "k8s.io/apimachinery/pkg/util/wait" ) type Role string const ( - Admin Role = "admin" - BaseUser Role = "user-base" - StandardUser Role = "user" - ClusterOwner Role = "cluster-owner" - ClusterMember Role = "cluster-member" - ProjectOwner Role = "project-owner" - ProjectMember Role = "project-member" - CreateNS Role = "create-ns" - ReadOnly Role = "read-only" - CustomManageProjectMember Role = "projectroletemplatebindings-manage" - CrtbView Role = "clusterroletemplatebindings-view" - PrtbView Role = "projectroletemplatebindings-view" - ProjectsCreate Role = "projects-create" - ProjectsView Role = "projects-view" - ManageWorkloads Role = "workloads-manage" - ManageUsers Role = "users-manage" - ActiveStatus = "active" - ForbiddenError = "403 Forbidden" - RancherDeploymentNamespace = "cattle-system" - DefaultNamespace = "fleet-default" - RancherDeploymentName = "rancher" - CattleResyncEnvVarName = "CATTLE_RESYNC_DEFAULT" - LocalCluster = "local" - UserKind = "User" - ImageName = "nginx" - ManageUsersVerb = "manage-users" - UpdatePsaVerb = "updatepsa" - ManagementAPIGroup = "management.cattle.io" - UsersResource = "users" - UserAttributeResource = "userattribute" - GroupsResource = "groups" - GroupMembersResource = "groupmembers" - ProjectResource = "projects" - PrtbResource = "projectroletemplatebindings" - SecretsResource = "secrets" - ClusterContext = "cluster" - ProjectContext = "project" - GrbOwnerLabel = "authz.management.cattle.io/grb-owner" - GlobalDataNS = "cattle-global-data" - MembershipBindingOwnerLabel = "membership-binding-owner" - PSALabelKey = "pod-security.kubernetes.io/" - PSAEnforceLabelKey = "pod-security.kubernetes.io/enforce" - PSAWarnLabelKey = "pod-security.kubernetes.io/warn" - PSAAuditLabelKey = "pod-security.kubernetes.io/audit" - PSAPrivilegedPolicy = "privileged" - PSABaselinePolicy = "baseline" - PSARestrictedPolicy = "restricted" - PSAEnforceVersionLabelKey = "pod-security.kubernetes.io/enforce-version" - PSAWarnVersionLabelKey = "pod-security.kubernetes.io/warn-version" - PSAAuditVersionLabelKey = "pod-security.kubernetes.io/audit-version" - PSALatestValue = "latest" - CompletedSummary = "Completed" + Admin Role = "admin" + BaseUser Role = "user-base" + StandardUser Role = "user" + ClusterOwner Role = "cluster-owner" + ClusterMember Role = "cluster-member" + ProjectOwner Role = "project-owner" + ProjectMember Role = "project-member" + CreateNS Role = "create-ns" + ReadOnly Role = "read-only" + CustomManageProjectMember Role = "projectroletemplatebindings-manage" + CrtbView Role = "clusterroletemplatebindings-view" + PrtbView Role = "projectroletemplatebindings-view" + ProjectsCreate Role = "projects-create" + ProjectsView Role = "projects-view" + ManageWorkloads Role = "workloads-manage" + ManageUsers Role = "users-manage" + ManageNodes Role = "nodes-manage" + ManageConfigMaps Role = "configmaps-manage" + SecretsView Role = "secrets-view" + UserKind = "User" + ActiveStatus = "active" + ForbiddenError = "403 Forbidden" + RancherDeploymentNamespace = "cattle-system" + DefaultNamespace = "fleet-default" + RancherDeploymentName = "rancher" + CattleResyncEnvVarName = "CATTLE_RESYNC_DEFAULT" + ImageName = "nginx" + GrbOwnerLabel = "authz.management.cattle.io/grb-owner" + GlobalDataNS = "cattle-global-data" + PSALabelKey = "pod-security.kubernetes.io/" + PSAEnforceLabelKey = "pod-security.kubernetes.io/enforce" + PSAWarnLabelKey = "pod-security.kubernetes.io/warn" + PSAAuditLabelKey = "pod-security.kubernetes.io/audit" + PSAPrivilegedPolicy = "privileged" + PSABaselinePolicy = "baseline" + PSARestrictedPolicy = "restricted" + PSAEnforceVersionLabelKey = "pod-security.kubernetes.io/enforce-version" + PSAWarnVersionLabelKey = "pod-security.kubernetes.io/warn-version" + PSAAuditVersionLabelKey = "pod-security.kubernetes.io/audit-version" + PSALatestValue = "latest" + CrtbOwnerLabel = "authz.cluster.cattle.io/crtb-owner" + PrtbOwnerLabel = "authz.cluster.cattle.io/prtb-owner" + ClusterNameAnnotationKey = "cluster.cattle.io/name" ) func (r Role) String() string { @@ -92,25 +69,25 @@ func AddUserWithRoleToCluster(client *rancher.Client, globalRole, role string, c return nil, nil, err } - roleContext, err := GetRoleTemplateContext(client, role) + roleContext, err := rbacapi.GetRoleTemplateContext(client, role) if err != nil { return nil, nil, fmt.Errorf("failed to get context for role %s: %w", role, err) } switch roleContext { - case ProjectContext: + case rbacapi.ProjectContext: if project == nil { return nil, nil, fmt.Errorf("project is required for project-scoped role: %s", role) } - _, err = CreateProjectRoleTemplateBinding(client, standardUser, project, role) + _, err = rbacapi.CreateProjectRoleTemplateBinding(client, standardUser, project, role) if err != nil { return nil, nil, err } - case ClusterContext: + case rbacapi.ClusterContext: if cluster == nil { return nil, nil, fmt.Errorf("cluster is required for cluster-scoped role: %s", role) } - _, err = CreateClusterRoleTemplateBinding(client, cluster.ID, standardUser, role) + _, err = rbacapi.CreateClusterRoleTemplateBinding(client, cluster.ID, standardUser, role) if err != nil { return nil, nil, err } @@ -138,738 +115,3 @@ func SetupUser(client *rancher.Client, globalRoles ...string) (user *management. } return } - -// VerifyRoleRules checks if the expected role rules match the actual rules. -func VerifyRoleRules(expected, actual map[string][]string) error { - for resource, expectedVerbs := range expected { - actualVerbs, exists := actual[resource] - if !exists { - return fmt.Errorf("resource %s not found in role rules", resource) - } - - expectedSet := make(map[string]struct{}) - for _, verb := range expectedVerbs { - expectedSet[verb] = struct{}{} - } - - for _, verb := range actualVerbs { - if _, found := expectedSet[verb]; !found { - return fmt.Errorf("verbs for resource %s do not match: expected %v, got %v", resource, expectedVerbs, actualVerbs) - } - } - } - return nil -} - -// GetRoleBindings is a helper function to fetch rolebindings for a user -func GetRoleBindings(rancherClient *rancher.Client, clusterID string, userID string) ([]rbacv1.RoleBinding, error) { - logrus.Infof("Getting role bindings for user %s in cluster %s", userID, clusterID) - listOpt := metav1.ListOptions{} - roleBindings, err := rbacapi.ListRoleBindings(rancherClient, clusterID, "", listOpt) - if err != nil { - return nil, fmt.Errorf("failed to fetch RoleBindings: %w", err) - } - - var userRoleBindings []rbacv1.RoleBinding - for _, rb := range roleBindings.Items { - for _, subject := range rb.Subjects { - if subject.Name == userID { - userRoleBindings = append(userRoleBindings, rb) - break - } - } - } - logrus.Infof("Found %d role bindings for user %s", len(userRoleBindings), userID) - return userRoleBindings, nil -} - -// GetBindings is a helper function to fetch bindings for a user -func GetBindings(rancherClient *rancher.Client, userID string) (map[string]interface{}, error) { - logrus.Infof("Getting all bindings for user %s", userID) - bindings := make(map[string]interface{}) - - roleBindings, err := GetRoleBindings(rancherClient, rbacapi.LocalCluster, userID) - if err != nil { - return nil, fmt.Errorf("failed to get role bindings: %w", err) - } - bindings["RoleBindings"] = roleBindings - - logrus.Info("Getting cluster role bindings") - clusterRoleBindings, err := rbacapi.ListClusterRoleBindings(rancherClient, rbacapi.LocalCluster, metav1.ListOptions{}) - if err != nil { - return nil, fmt.Errorf("failed to list cluster role bindings: %w", err) - } - bindings["ClusterRoleBindings"] = clusterRoleBindings.Items - - logrus.Info("Getting global role bindings") - globalRoleBindings, err := rancherClient.Management.GlobalRoleBinding.ListAll(&types.ListOpts{}) - if err != nil { - return nil, fmt.Errorf("failed to list global role bindings: %w", err) - } - bindings["GlobalRoleBindings"] = globalRoleBindings.Data - - logrus.Info("Getting cluster role template bindings") - clusterRoleTemplateBindings, err := rancherClient.Management.ClusterRoleTemplateBinding.List(&types.ListOpts{}) - if err != nil { - return nil, fmt.Errorf("failed to list cluster role template bindings: %w", err) - } - bindings["ClusterRoleTemplateBindings"] = clusterRoleTemplateBindings.Data - - logrus.Info("All bindings retrieved successfully") - return bindings, nil -} - -// GetGlobalRoleBindingByUserAndRole is a helper function to fetch global role binding for a user associated with a specific global role -func GetGlobalRoleBindingByUserAndRole(client *rancher.Client, userID, globalRoleName string) (*v3.GlobalRoleBinding, error) { - var matchingGlobalRoleBinding *v3.GlobalRoleBinding - - err := kwait.PollUntilContextTimeout(context.TODO(), defaults.TenSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, pollErr error) { - grblist, err := client.WranglerContext.Mgmt.GlobalRoleBinding().List(metav1.ListOptions{}) - if err != nil { - return false, err - } - - for _, grb := range grblist.Items { - if grb.GlobalRoleName == globalRoleName && grb.UserName == userID { - matchingGlobalRoleBinding = &grb - return true, nil - } - } - - return false, nil - }) - - if err != nil { - return nil, fmt.Errorf("error while polling for global role binding: %w", err) - } - - return matchingGlobalRoleBinding, nil -} - -// GetGlobalRoleByName is a helper function to fetch global role by name -func GetGlobalRoleByName(client *rancher.Client, globalRoleName string) (*v3.GlobalRole, error) { - var matchingGlobalRole *v3.GlobalRole - - err := kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, pollErr error) { - grlist, err := client.WranglerContext.Mgmt.GlobalRole().List(metav1.ListOptions{}) - if err != nil { - return false, err - } - - for _, gr := range grlist.Items { - if gr.Name == globalRoleName { - matchingGlobalRole = &gr - return true, nil - } - } - - return false, nil - }) - - if err != nil { - return nil, fmt.Errorf("error while polling for global role: %w", err) - } - - return matchingGlobalRole, nil -} - -// GetGlobalRoleBindingByName is a helper function to fetch global role binding by name -func GetGlobalRoleBindingByName(client *rancher.Client, globalRoleBindingName string) (*v3.GlobalRoleBinding, error) { - var matchingGlobalRoleBinding *v3.GlobalRoleBinding - - err := kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, pollErr error) { - grblist, err := client.WranglerContext.Mgmt.GlobalRoleBinding().List(metav1.ListOptions{}) - if err != nil { - return false, err - } - - for _, grb := range grblist.Items { - if grb.Name == globalRoleBindingName { - matchingGlobalRoleBinding = &grb - return true, nil - } - } - - return false, nil - }) - - if err != nil { - return nil, fmt.Errorf("error while polling for global role binding: %w", err) - } - - return matchingGlobalRoleBinding, nil -} - -// GetRoleTemplateByName is a helper function to fetch role template by name using wrangler context -func GetRoleTemplateByName(client *rancher.Client, roleTemplateName string) (*v3.RoleTemplate, error) { - var roleTemplate *v3.RoleTemplate - - err := kwait.PollUntilContextTimeout(context.Background(), defaults.FiveHundredMillisecondTimeout, defaults.TenSecondTimeout, false, func(ctx context.Context) (done bool, pollErr error) { - rt, err := client.WranglerContext.Mgmt.RoleTemplate().Get(roleTemplateName, metav1.GetOptions{}) - if err != nil { - if apierrors.IsNotFound(err) { - return false, nil - } - return false, err - } - - roleTemplate = rt - return true, nil - }) - - if err != nil { - return nil, fmt.Errorf("error while polling for role template: %w", err) - } - - return roleTemplate, nil -} - -// GetClusterRoleRules is a helper function to fetch rules for a cluster role -func GetClusterRoleRules(client *rancher.Client, clusterID string, clusterRoleName string) ([]rbacv1.PolicyRule, error) { - var ctx *wrangler.Context - var err error - - if clusterID != rbacapi.LocalCluster { - ctx, err = client.WranglerContext.DownStreamClusterWranglerContext(clusterID) - if err != nil { - return nil, fmt.Errorf("failed to get downstream context: %w", err) - } - } else { - ctx = client.WranglerContext - } - - clusterRole, err := ctx.RBAC.ClusterRole().Get(clusterRoleName, metav1.GetOptions{}) - if err != nil { - if apierrors.IsNotFound(err) { - return nil, fmt.Errorf("ClusterRole %s not found", clusterRoleName) - } - return nil, fmt.Errorf("failed to get ClusterRole %s: %w", clusterRoleName, err) - } - - return clusterRole.Rules, nil -} - -// CreateRoleTemplate creates a cluster or project role template with the provided rules using wrangler context -func CreateRoleTemplate(client *rancher.Client, context string, rules []rbacv1.PolicyRule, inheritedRoles []*v3.RoleTemplate, external bool, externalRules []rbacv1.PolicyRule) (*v3.RoleTemplate, error) { - var roleTemplateNames []string - for _, inheritedRole := range inheritedRoles { - if inheritedRole != nil { - roleTemplateNames = append(roleTemplateNames, inheritedRole.Name) - } - } - - displayName := namegen.AppendRandomString("role-template") - - roleTemplate := &v3.RoleTemplate{ - ObjectMeta: metav1.ObjectMeta{ - Name: displayName, - }, - Context: context, - Rules: rules, - DisplayName: displayName, - RoleTemplateNames: roleTemplateNames, - External: external, - ExternalRules: externalRules, - } - - createdRoleTemplate, err := client.WranglerContext.Mgmt.RoleTemplate().Create(roleTemplate) - if err != nil { - return nil, fmt.Errorf("failed to create RoleTemplate: %w", err) - } - - return GetRoleTemplateByName(client, createdRoleTemplate.Name) -} - -// CreateClusterRoleTemplateBinding creates a cluster role template binding for the user with the provided role template using wrangler context -func CreateClusterRoleTemplateBinding(client *rancher.Client, clusterID string, user *management.User, roleTemplateID string) (*v3.ClusterRoleTemplateBinding, error) { - crtbObj := &v3.ClusterRoleTemplateBinding{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: clusterID, - GenerateName: "crtb-", - }, - ClusterName: clusterID, - UserName: user.ID, - RoleTemplateName: roleTemplateID, - } - - crtb, err := client.WranglerContext.Mgmt.ClusterRoleTemplateBinding().Create(crtbObj) - if err != nil { - return nil, err - } - - err = WaitForCrtbStatus(client, crtb.Namespace, crtb.Name) - if err != nil { - return nil, err - } - - userClient, err := client.AsUser(user) - if err != nil { - return nil, fmt.Errorf("client as user %s: %w", user.Name, err) - } - - err = extauthz.WaitForAllowed(userClient, clusterID, nil) - if err != nil { - return nil, err - } - - return crtb, nil -} - -// GetClusterRoleTemplateBindingsForUser fetches clusterroletemplatebindings for a specific user -func GetClusterRoleTemplateBindingsForUser(rancherClient *rancher.Client, userID string) (*v3.ClusterRoleTemplateBinding, error) { - var matchingCRTB *v3.ClusterRoleTemplateBinding - err := kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, pollErr error) { - crtbList, err := rbacapi.ListClusterRoleTemplateBindings(rancherClient, metav1.ListOptions{}) - if err != nil { - return false, err - } - - for _, crtb := range crtbList.Items { - if crtb.UserName == userID { - matchingCRTB = &crtb - return true, nil - } - } - - return false, nil - }) - - if err != nil { - return nil, fmt.Errorf("error while polling for crtb: %w", err) - } - - return matchingCRTB, nil -} - -// WaitForCrtbStatus waits for the CRTB to reach the Completed status or checks for its existence if status field is not supported (older Rancher versions) -func WaitForCrtbStatus(client *rancher.Client, crtbNamespace, crtbName string) error { - ctx, cancel := context.WithTimeout(context.Background(), defaults.OneMinuteTimeout) - defer cancel() - - err := kwait.PollUntilContextTimeout(ctx, defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, err error) { - crtb, err := client.WranglerContext.Mgmt.ClusterRoleTemplateBinding().Get(crtbNamespace, crtbName, metav1.GetOptions{}) - if err != nil { - return false, nil - } - - if crtb.Status.Summary == CompletedSummary { - return true, nil - } - - if crtb != nil && crtb.Name == crtbName && crtb.Namespace == crtbNamespace { - return true, nil - } - - return false, nil - }) - - if err != nil { - return fmt.Errorf("timed out waiting for CRTB %s/%s to complete or exist: %w", crtbNamespace, crtbName, err) - } - - return nil -} - -// CreateProjectRoleTemplateBinding creates a project role template binding for the user with the provided role template using wrangler context -func CreateProjectRoleTemplateBinding(client *rancher.Client, user *management.User, project *v3.Project, roleTemplateID string) (*v3.ProjectRoleTemplateBinding, error) { - projectName := fmt.Sprintf("%s:%s", project.Namespace, project.Name) - - prtbNamespace := project.Name - if project.Status.BackingNamespace != "" { - prtbNamespace = fmt.Sprintf("%s-%s", project.Spec.ClusterName, project.Name) - } - - prtbObj := &v3.ProjectRoleTemplateBinding{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: prtbNamespace, - GenerateName: "prtb-", - }, - ProjectName: projectName, - UserName: user.ID, - RoleTemplateName: roleTemplateID, - } - - prtbObj, err := client.WranglerContext.Mgmt.ProjectRoleTemplateBinding().Create(prtbObj) - if err != nil { - return nil, err - } - - prtb, err := WaitForPrtbExistence(client, project, prtbObj, user) - - if err != nil { - return nil, err - } - - userClient, err := client.AsUser(user) - if err != nil { - return nil, fmt.Errorf("client as user %s: %w", user.Name, err) - } - - err = extauthz.WaitForAllowed(userClient, project.Namespace, nil) - if err != nil { - return nil, err - } - - return prtb, nil -} - -// WaitForPrtbExistence waits for the PRTB to exist with the correct user and project -func WaitForPrtbExistence(client *rancher.Client, project *v3.Project, prtbObj *v3.ProjectRoleTemplateBinding, user *management.User) (*v3.ProjectRoleTemplateBinding, error) { - projectName := fmt.Sprintf("%s:%s", project.Namespace, project.Name) - - var prtb *v3.ProjectRoleTemplateBinding - err := kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.TwoMinuteTimeout, false, func(ctx context.Context) (bool, error) { - var err error - prtb, err = client.WranglerContext.Mgmt.ProjectRoleTemplateBinding().Get(prtbObj.Namespace, prtbObj.Name, metav1.GetOptions{}) - if err != nil { - return false, nil - } - if prtb != nil && prtb.UserName == user.ID && prtb.ProjectName == projectName { - return true, nil - } - - return false, nil - }) - if err != nil { - return nil, err - } - return prtb, nil -} - -// GetRoleTemplateContext is a helper function to fetch the context of a role template -func GetRoleTemplateContext(client *rancher.Client, roleTemplateName string) (string, error) { - roleTemplate, err := GetRoleTemplateByName(client, roleTemplateName) - if err != nil { - return "", fmt.Errorf("failed to get RoleTemplate %s: %w", roleTemplateName, err) - } - - if roleTemplate == nil { - return "", fmt.Errorf("RoleTemplate %s not found", roleTemplateName) - } - - return roleTemplate.Context, nil -} - -// ListCRTBsByLabel lists ClusterRoleTemplateBindings by label selector -func ListCRTBsByLabel(client *rancher.Client, labelKey, labelValue string, expectedCount int) (*v3.ClusterRoleTemplateBindingList, error) { - req, err := labels.NewRequirement(labelKey, selection.In, []string{labelValue}) - if err != nil { - return nil, err - } - - selector := labels.NewSelector().Add(*req) - var crtbs *v3.ClusterRoleTemplateBindingList - - ctx, cancel := context.WithTimeout(context.Background(), defaults.TwoMinuteTimeout) - defer cancel() - - err = kwait.PollUntilContextTimeout(ctx, defaults.FiveSecondTimeout, defaults.TwoMinuteTimeout, false, func(ctx context.Context) (done bool, pollErr error) { - crtbs, pollErr = rbacapi.ListClusterRoleTemplateBindings(client, metav1.ListOptions{ - LabelSelector: selector.String(), - }) - if pollErr != nil { - return false, pollErr - } - - if expectedCount == 0 { - return true, nil - } - - if len(crtbs.Items) == expectedCount { - return true, nil - } - - logrus.Infof("Waiting for ClusterRoleTemplateBindings count to match, current: %d, expected: %d", - len(crtbs.Items), expectedCount) - return false, nil - }) - - if err != nil { - if crtbs != nil { - return crtbs, fmt.Errorf("timed out waiting for ClusterRoleTemplateBindings count to match expected: %d, actual: %d, error: %w", - expectedCount, len(crtbs.Items), err) - } - return nil, err - } - - return crtbs, nil -} - -// GetRoleBindingsForCRTBs gets RoleBindings based on ClusterRoleTemplateBindings -func GetRoleBindingsForCRTBs(client *rancher.Client, crtbs *v3.ClusterRoleTemplateBindingList) (*rbacv1.RoleBindingList, error) { - var downstreamRBs rbacv1.RoleBindingList - - for _, crtb := range crtbs.Items { - roleTemplateName := crtb.RoleTemplateName - if strings.Contains(roleTemplateName, "rt") { - listOpt := metav1.ListOptions{ - FieldSelector: "metadata.name=" + roleTemplateName, - } - roleTemplateList, err := rbacapi.ListRoleTemplates(client, listOpt) - if err != nil { - return nil, err - } - if len(roleTemplateList.Items) > 0 { - roleTemplateName = roleTemplateList.Items[0].RoleTemplateNames[0] - } - } - - nameSelector := fmt.Sprintf("metadata.name=%s-%s", crtb.Name, roleTemplateName) - namespaceSelector := fmt.Sprintf("metadata.namespace=%s", crtb.ClusterName) - combinedSelector := fmt.Sprintf("%s,%s", nameSelector, namespaceSelector) - downstreamRBsForCRTB, err := rbacapi.ListRoleBindings(client, rbacapi.LocalCluster, "", metav1.ListOptions{ - FieldSelector: combinedSelector, - }) - if err != nil { - return nil, err - } - - downstreamRBs.Items = append(downstreamRBs.Items, downstreamRBsForCRTB.Items...) - } - - return &downstreamRBs, nil -} - -// GetClusterRoleBindingsForCRTBs gets ClusterRoleBindings based on ClusterRoleTemplateBindings using labels -func GetClusterRoleBindingsForCRTBs(client *rancher.Client, crtbs *v3.ClusterRoleTemplateBindingList) (*rbacv1.ClusterRoleBindingList, error) { - var downstreamCRBs rbacv1.ClusterRoleBindingList - - for _, crtb := range crtbs.Items { - labelKey := fmt.Sprintf("%s_%s", crtb.ClusterName, crtb.Name) - req, err := labels.NewRequirement(labelKey, selection.In, []string{MembershipBindingOwnerLabel}) - if err != nil { - return nil, err - } - - selector := labels.NewSelector().Add(*req) - downstreamCRBsForCRTB, err := rbacapi.ListClusterRoleBindings(client, rbacapi.LocalCluster, metav1.ListOptions{ - LabelSelector: selector.String(), - }) - if err != nil { - return nil, err - } - - downstreamCRBs.Items = append(downstreamCRBs.Items, downstreamCRBsForCRTB.Items...) - } - - return &downstreamCRBs, nil -} - -// GetClusterRoleBindingsForUsers gets ClusterRoleBindings where users from CRTBs are subjects -func GetClusterRoleBindingsForUsers(client *rancher.Client, crtbs *v3.ClusterRoleTemplateBindingList) ([]rbacv1.ClusterRoleBinding, error) { - var userCRBs []rbacv1.ClusterRoleBinding - - for _, crtb := range crtbs.Items { - crbs, err := rbacapi.ListClusterRoleBindings(client, rbacapi.LocalCluster, metav1.ListOptions{}) - if err != nil { - return nil, err - } - - for _, crb := range crbs.Items { - for _, subject := range crb.Subjects { - if subject.Kind == "User" && subject.Name == crtb.UserName { - userCRBs = append(userCRBs, crb) - } - } - } - } - - return userCRBs, nil -} - -// GetRoleBindingsForUsers gets RoleBindings where users are subjects in specific namespaces -func GetRoleBindingsForUsers(client *rancher.Client, userName string, namespaces []string) ([]rbacv1.RoleBinding, error) { - var userRBs []rbacv1.RoleBinding - - for _, namespace := range namespaces { - rbs, err := rbacapi.ListRoleBindings(client, rbacapi.LocalCluster, namespace, metav1.ListOptions{}) - if err != nil { - return nil, fmt.Errorf("failed to list RoleBindings in namespace %s: %w", namespace, err) - } - - for _, rb := range rbs.Items { - for _, subject := range rb.Subjects { - if subject.Kind == "User" && subject.Name == userName { - userRBs = append(userRBs, rb) - } - } - } - } - - return userRBs, nil -} - -// CreateGlobalRoleWithInheritedClusterRolesWrangler creates a global role with inherited cluster roles -func CreateGlobalRoleWithInheritedClusterRolesWrangler(client *rancher.Client, inheritedRoles []string) (*v3.GlobalRole, error) { - globalRole := v3.GlobalRole{ - ObjectMeta: metav1.ObjectMeta{ - Name: namegen.AppendRandomString("testgr"), - }, - InheritedClusterRoles: inheritedRoles, - } - - createdGlobalRole, err := client.WranglerContext.Mgmt.GlobalRole().Create(&globalRole) - if err != nil { - return nil, fmt.Errorf("failed to create global role with inherited cluster roles: %w", err) - } - - return createdGlobalRole, nil -} - -// CreateGroupClusterRoleTemplateBinding creates Cluster Role Template bindings -func CreateGroupClusterRoleTemplateBinding(client *rancher.Client, clusterID string, groupPrincipalID string, roleTemplateID string) (*v3.ClusterRoleTemplateBinding, error) { - crtbObj := &v3.ClusterRoleTemplateBinding{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: clusterID, - GenerateName: "crtb-", - Annotations: map[string]string{ - "field.cattle.io/creatorId": client.UserID, - }, - }, - ClusterName: clusterID, - GroupPrincipalName: groupPrincipalID, - RoleTemplateName: roleTemplateID, - } - - crtb, err := client.WranglerContext.Mgmt.ClusterRoleTemplateBinding().Create(crtbObj) - if err != nil { - return nil, err - } - - err = WaitForCrtbStatus(client, crtb.Namespace, crtb.Name) - if err != nil { - return nil, err - } - - return crtb, nil -} - -// CreateGroupProjectRoleTemplateBinding creates Project Role Template bindings for groups -func CreateGroupProjectRoleTemplateBinding(client *rancher.Client, projectID string, projectNamespace string, groupPrincipalID string, roleTemplateID string) (*v3.ProjectRoleTemplateBinding, error) { - prtbObj := &v3.ProjectRoleTemplateBinding{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: projectNamespace, - GenerateName: "prtb-", - }, - ProjectName: projectID, - GroupPrincipalName: groupPrincipalID, - RoleTemplateName: roleTemplateID, - } - - prtb, err := client.WranglerContext.Mgmt.ProjectRoleTemplateBinding().Create(prtbObj) - if err != nil { - return nil, err - } - - return prtb, nil -} - -// GetClusterRoleTemplateBindingsForGroup polls until a CRTB for the given group principal and cluster is found. -func GetClusterRoleTemplateBindingsForGroup(rancherClient *rancher.Client, groupPrincipalName, clusterID string) (*v3.ClusterRoleTemplateBinding, error) { - var matchingCRTB *v3.ClusterRoleTemplateBinding - err := kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, pollErr error) { - crtbList, err := rbacapi.ListClusterRoleTemplateBindings(rancherClient, metav1.ListOptions{}) - if err != nil { - return false, err - } - for _, crtb := range crtbList.Items { - if crtb.GroupPrincipalName == groupPrincipalName && crtb.ClusterName == clusterID { - matchingCRTB = &crtb - return true, nil - } - } - return false, nil - }) - if err != nil { - return nil, fmt.Errorf("error while polling for group crtb: %w", err) - } - return matchingCRTB, nil -} - -// CreateGlobalRoleWithRules creates a global role with given name and rules using wrangler context -func CreateGlobalRoleWithRules(client *rancher.Client, name string, rules []rbacv1.PolicyRule) (*v3.GlobalRole, error) { - role := &v3.GlobalRole{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - Rules: rules, - } - - createdRole, err := client.WranglerContext.Mgmt.GlobalRole().Create(role) - if err != nil { - return nil, fmt.Errorf("failed to create global role %s: %w", name, err) - } - - return createdRole, nil -} - -// CreateGlobalRoleBinding creates a global role binding for the user with the provided global role using wrangler context -func CreateGlobalRoleBinding(client *rancher.Client, user *v3.User, globalRoleName string) (*v3.GlobalRoleBinding, error) { - grbObj := &v3.GlobalRoleBinding{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "grb-", - }, - UserName: user.Username, - GlobalRoleName: globalRoleName, - } - - grb, err := client.WranglerContext.Mgmt.GlobalRoleBinding().Create(grbObj) - if err != nil { - return nil, fmt.Errorf("failed to create global role binding for user %s and global role %s: %w", user.Name, globalRoleName, err) - } - - err = WaitForGrbExistence(client, user.Username, globalRoleName) - if err != nil { - return nil, err - } - - return grb, nil -} - -// WaitForGrbExistence waits until the GlobalRoleBinding for the given user and role exists -func WaitForGrbExistence(client *rancher.Client, username, roleName string) error { - err := kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, err error) { - grb, err := GetGlobalRoleBindingByUserAndRole(client, username, roleName) - if err != nil { - return false, nil - } - - return grb != nil, nil - }) - - if err != nil { - return fmt.Errorf("timed out waiting for GRB for user %s and role %s to exist: %w", username, roleName, err) - } - - return nil -} - -// DeleteGlobalRoleBinding deletes a global role binding by name using wrangler context -func DeleteGlobalRoleBinding(client *rancher.Client, grbName string) error { - err := client.WranglerContext.Mgmt.GlobalRoleBinding().Delete(grbName, nil) - if err != nil { - return fmt.Errorf("failed to delete global role binding %s: %w", grbName, err) - } - - err = WaitForGlobalRoleBindingDeletion(client, grbName) - if err != nil { - return fmt.Errorf("global role binding %s not deleted in time: %w", grbName, err) - } - - return nil -} - -// WaitForGlobalRoleBindingDeletion waits until the GlobalRoleBinding is deleted -func WaitForGlobalRoleBindingDeletion(client *rancher.Client, grbName string) error { - return kwait.PollUntilContextTimeout(context.TODO(), defaults.FiveSecondTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (done bool, err error) { - _, err = client.WranglerContext.Mgmt.GlobalRoleBinding().Get(grbName, metav1.GetOptions{}) - if apierrors.IsNotFound(err) { - return true, nil - } - if err != nil { - return false, nil - } - return false, nil - }, - ) -} diff --git a/actions/rbac/verify.go b/actions/rbac/verify.go index a15ef9166..dbf13875c 100644 --- a/actions/rbac/verify.go +++ b/actions/rbac/verify.go @@ -13,6 +13,7 @@ import ( v1 "github.com/rancher/shepherd/clients/rancher/v1" "github.com/rancher/shepherd/extensions/clusters" "github.com/rancher/shepherd/extensions/users" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" namespaceapi "github.com/rancher/tests/actions/kubeapi/namespaces" projectapi "github.com/rancher/tests/actions/kubeapi/projects" rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" @@ -35,7 +36,7 @@ func VerifyGlobalRoleBindingsForUser(t *testing.T, user *management.User, adminC // VerifyRoleBindingsForUser validates that the corresponding role bindings are created for the user func VerifyRoleBindingsForUser(t *testing.T, user *management.User, adminClient *rancher.Client, clusterID string, role Role, expectedCount int) { - rblist, err := rbacapi.ListRoleBindings(adminClient, LocalCluster, clusterID, metav1.ListOptions{}) + rblist, err := rbacapi.ListRoleBindings(adminClient, clusterapi.LocalCluster, clusterID, metav1.ListOptions{}) require.NoError(t, err) userID := user.Resource.ID userRoleBindings := []string{} @@ -194,7 +195,7 @@ func VerifyUserCanAddClusterRoles(t *testing.T, client, memberClient *rancher.Cl additionalClusterUser, err := users.CreateUserWithRole(client, users.UserConfig(), StandardUser.String()) require.NoError(t, err) - _, errUserRole := CreateClusterRoleTemplateBinding(memberClient, cluster.ID, additionalClusterUser, ClusterOwner.String()) + _, errUserRole := rbacapi.CreateClusterRoleTemplateBinding(memberClient, cluster.ID, additionalClusterUser, ClusterOwner.String()) switch role { case ProjectOwner, ProjectMember: require.Error(t, errUserRole) @@ -205,7 +206,7 @@ func VerifyUserCanAddClusterRoles(t *testing.T, client, memberClient *rancher.Cl // VerifyUserCanAddProjectRoles validates a user with the required cluster permissions are able/not able to add other users in a project on the downstream cluster func VerifyUserCanAddProjectRoles(t *testing.T, client *rancher.Client, project *v3.Project, additionalUser *management.User, projectRole, clusterID string, role Role) { - _, errUserRole := CreateProjectRoleTemplateBinding(client, additionalUser, project, projectRole) + _, errUserRole := rbacapi.CreateProjectRoleTemplateBinding(client, additionalUser, project, projectRole) switch role { case ProjectOwner: require.NoError(t, errUserRole) @@ -233,51 +234,3 @@ func VerifyUserCanRemoveClusterRoles(t *testing.T, client *rancher.Client, user err := users.RemoveClusterRoleFromUser(client, user) require.NoError(t, err) } - -// VerifyClusterRoleTemplateBindingForUser is a helper function to verify the number of cluster role template bindings for a user -func VerifyClusterRoleTemplateBindingForUser(client *rancher.Client, username string, expectedCount int) ([]v3.ClusterRoleTemplateBinding, error) { - crtbList, err := rbacapi.ListClusterRoleTemplateBindings(client, metav1.ListOptions{}) - if err != nil { - return nil, fmt.Errorf("failed to list ClusterRoleTemplateBindings: %w", err) - } - - userCrtbs := []v3.ClusterRoleTemplateBinding{} - actualCount := 0 - for _, crtb := range crtbList.Items { - if crtb.UserName == username { - userCrtbs = append(userCrtbs, crtb) - actualCount++ - } - } - - if actualCount != expectedCount { - return nil, fmt.Errorf("expected %d ClusterRoleTemplateBindings for user %s, but found %d", - expectedCount, username, actualCount) - } - - return userCrtbs, nil -} - -// VerifyProjectRoleTemplateBindingForUser is a helper function to verify the number of project role template bindings for a user -func VerifyProjectRoleTemplateBindingForUser(client *rancher.Client, username string, expectedCount int) ([]v3.ProjectRoleTemplateBinding, error) { - prtbList, err := rbacapi.ListProjectRoleTemplateBindings(client, metav1.ListOptions{}) - if err != nil { - return nil, fmt.Errorf("failed to list ProjectRoleTemplateBindings: %w", err) - } - - userPrtbs := []v3.ProjectRoleTemplateBinding{} - actualCount := 0 - for _, prtb := range prtbList.Items { - if prtb.UserName == username { - userPrtbs = append(userPrtbs, prtb) - actualCount++ - } - } - - if actualCount != expectedCount { - return nil, fmt.Errorf("expected %d ProjectRoleTemplateBindings for user %s, but found %d", - expectedCount, username, actualCount) - } - - return userPrtbs, nil -} diff --git a/actions/secrets/secrets.go b/actions/secrets/secrets.go index ec173453b..c8d64b896 100644 --- a/actions/secrets/secrets.go +++ b/actions/secrets/secrets.go @@ -12,7 +12,6 @@ import ( namegen "github.com/rancher/shepherd/pkg/namegenerator" clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" secretsapi "github.com/rancher/tests/actions/kubeapi/secrets" - "github.com/rancher/tests/actions/rbac" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -102,7 +101,7 @@ func CreateProjectScopedSecret(client *rancher.Client, clusterID, projectID stri ProjectScopedSecretLabel: projectID, } - createdProjectScopedSecret, err := CreateSecret(client, rbac.LocalCluster, backingNamespace, data, secretType, labels, nil) + createdProjectScopedSecret, err := CreateSecret(client, clusterapi.LocalCluster, backingNamespace, data, secretType, labels, nil) if err != nil { return nil, fmt.Errorf("failed to create project scoped secret: %w", err) } @@ -169,7 +168,7 @@ func UpdateSecretData(client *rancher.Client, clusterID, namespace, secretName s func UpdateProjectScopedSecret(client *rancher.Client, clusterID, projectID, secretName string, newData map[string][]byte) (*corev1.Secret, error) { backingNamespace := fmt.Sprintf("%s-%s", clusterID, projectID) - updatedProjectScopedSecret, err := UpdateSecretData(client, rbac.LocalCluster, backingNamespace, secretName, newData) + updatedProjectScopedSecret, err := UpdateSecretData(client, clusterapi.LocalCluster, backingNamespace, secretName, newData) if err != nil { return nil, fmt.Errorf("failed to update secret %s: %w", secretName, err) } diff --git a/actions/settings/settings.go b/actions/settings/settings.go index d02726add..415a832f2 100644 --- a/actions/settings/settings.go +++ b/actions/settings/settings.go @@ -6,7 +6,7 @@ import ( "github.com/rancher/shepherd/clients/rancher" "github.com/rancher/shepherd/extensions/settings" "github.com/rancher/shepherd/pkg/wrangler" - rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -25,7 +25,7 @@ func GetGlobalSettingNames(client *rancher.Client, clusterID string) ([]string, var ctx *wrangler.Context var err error - if clusterID != rbacapi.LocalCluster { + if clusterID != clusterapi.LocalCluster { ctx, err = client.WranglerContext.DownStreamClusterWranglerContext(clusterID) if err != nil { return nil, fmt.Errorf("failed to get downstream context: %w", err) diff --git a/actions/users/users.go b/actions/users/users.go index 0307efd48..322d64f76 100644 --- a/actions/users/users.go +++ b/actions/users/users.go @@ -13,7 +13,7 @@ import ( management "github.com/rancher/shepherd/clients/rancher/generated/management/v3" "github.com/rancher/shepherd/extensions/defaults" namegen "github.com/rancher/shepherd/pkg/namegenerator" - "github.com/rancher/tests/actions/rbac" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -124,7 +124,7 @@ func CreateUserWithRoles(client *rancher.Client, globalRoles ...string) (*v3.Use } for _, globalRole := range globalRoles { - _, err := rbac.CreateGlobalRoleBinding(client, createdUser, globalRole) + _, err := rbacapi.CreateGlobalRoleBinding(client, globalRole, createdUser.Username, "", "") if err != nil { return nil, "", fmt.Errorf("failed to assign global role %s to user %s: %w", globalRole, createdUser.Username, err) } diff --git a/actions/workloads/deployment/deployment.go b/actions/workloads/deployment/deployment.go index 7eea0ed46..325e08a5c 100644 --- a/actions/workloads/deployment/deployment.go +++ b/actions/workloads/deployment/deployment.go @@ -20,7 +20,7 @@ import ( namegen "github.com/rancher/shepherd/pkg/namegenerator" "github.com/rancher/shepherd/pkg/wrangler" "github.com/rancher/tests/actions/kubeapi/workloads/deployments" - "github.com/rancher/tests/actions/rbac" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" "github.com/rancher/tests/actions/workloads/pods" "github.com/sirupsen/logrus" appv1 "k8s.io/api/apps/v1" @@ -247,7 +247,7 @@ func UpdateOrRemoveEnvVarForDeployment(client *rancher.Client, namespaceName, de } } - _, err = UpdateDeployment(client, rbac.LocalCluster, namespaceName, modifiedDeployment, true) + _, err = UpdateDeployment(client, clusterapi.LocalCluster, namespaceName, modifiedDeployment, true) if err != nil { return fmt.Errorf("error updating deployment %s in namespace %s: %w", deploymentName, namespaceName, err) } diff --git a/validation/auth/provider/activedirectory/activedirectory_test.go b/validation/auth/provider/activedirectory/activedirectory_test.go index 7d02aea30..23d4d3cb9 100644 --- a/validation/auth/provider/activedirectory/activedirectory_test.go +++ b/validation/auth/provider/activedirectory/activedirectory_test.go @@ -16,7 +16,7 @@ import ( "github.com/rancher/shepherd/pkg/session" authactions "github.com/rancher/tests/actions/auth" projectsapi "github.com/rancher/tests/actions/kubeapi/projects" - krbac "github.com/rancher/tests/actions/kubeapi/rbac" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/projects" "github.com/rancher/tests/actions/rbac" "github.com/sirupsen/logrus" @@ -156,7 +156,7 @@ func (a *ActiveDirectoryAuthProviderSuite) TestActiveDirectoryGroupMembershipRef GroupPrincipalName: adminGroupPrincipalID, } - _, err = krbac.CreateGlobalRoleBinding(authAdmin, adminGlobalRole) + _, err = authAdmin.WranglerContext.Mgmt.GlobalRoleBinding().Create(adminGlobalRole) require.NoError(a.T(), err, "Failed to create admin global role binding") err = users.RefreshGroupMembership(authAdmin) @@ -171,7 +171,7 @@ func (a *ActiveDirectoryAuthProviderSuite) TestActiveDirectoryGroupMembershipRef GroupPrincipalName: standardGroupPrincipalID, } - _, err = krbac.CreateGlobalRoleBinding(authAdmin, standardGlobalRole) + _, err = authAdmin.WranglerContext.Mgmt.GlobalRoleBinding().Create(standardGlobalRole) require.NoError(a.T(), err, "Failed to create standard global role binding") err = users.RefreshGroupMembership(authAdmin) @@ -189,7 +189,7 @@ func (a *ActiveDirectoryAuthProviderSuite) TestActiveDirectoryNestedGroupCluster a.client.Auth.ActiveDirectory.Config.Users.SearchBase, a.client.Auth.ActiveDirectory.Config.Groups.SearchBase, ) - _, err = rbac.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, doubleNestedGroupPrincipalID, rbac.ClusterOwner.String()) + _, err = rbacapi.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, doubleNestedGroupPrincipalID, rbac.ClusterOwner.String()) require.NoError(a.T(), err, "Failed to create cluster role binding") for _, userInfo := range a.authConfig.DoubleNestedUsers { @@ -203,7 +203,7 @@ func (a *ActiveDirectoryAuthProviderSuite) TestActiveDirectoryNestedGroupCluster rbac.VerifyUserCanListCluster(a.T(), a.client, userClient, a.cluster.ID, rbac.ClusterOwner) } - foundCRTB, err := rbac.GetClusterRoleTemplateBindingsForGroup(a.client, doubleNestedGroupPrincipalID, a.cluster.ID) + foundCRTB, err := rbacapi.GetClusterRoleTemplateBindingsForGroup(a.client, doubleNestedGroupPrincipalID, a.cluster.ID) require.NoError(a.T(), err, "Failed to get group CRTB") require.NotNil(a.T(), foundCRTB, "Cluster role binding should exist for group") } @@ -214,7 +214,7 @@ func (a *ActiveDirectoryAuthProviderSuite) TestActiveDirectoryNonMemberClusterAc defer subSession.Cleanup() doubleNestedGroupPrincipalID := authactions.GetGroupPrincipalID(authactions.ActiveDirectory, a.authConfig.DoubleNestedGroup, a.client.Auth.ActiveDirectory.Config.Users.SearchBase, a.client.Auth.ActiveDirectory.Config.Groups.SearchBase) - _, err = rbac.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, doubleNestedGroupPrincipalID, rbac.ClusterOwner.String()) + _, err = rbacapi.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, doubleNestedGroupPrincipalID, rbac.ClusterOwner.String()) require.NoError(a.T(), err, "Failed to create cluster role binding") for _, userInfo := range a.authConfig.Users { @@ -248,7 +248,7 @@ func (a *ActiveDirectoryAuthProviderSuite) TestActiveDirectoryNestedGroupProject projectName := fmt.Sprintf("%s:%s", projectResp.Namespace, projectResp.Name) - groupPRTBResp, err := rbac.CreateGroupProjectRoleTemplateBinding(authAdmin, projectName, prtbNamespace, nestedGroupPrincipalID, rbac.ProjectOwner.String()) + groupPRTBResp, err := rbacapi.CreateGroupProjectRoleTemplateBinding(authAdmin, projectName, prtbNamespace, nestedGroupPrincipalID, rbac.ProjectOwner.String()) require.NoError(a.T(), err, "Failed to create PRTB") require.NotNil(a.T(), groupPRTBResp, "PRTB should be created") @@ -274,7 +274,7 @@ func (a *ActiveDirectoryAuthProviderSuite) TestActiveDirectoryRestrictedModeBind defer subSession.Cleanup() groupPrincipalID := authactions.GetGroupPrincipalID(authactions.ActiveDirectory, a.authConfig.Group, a.client.Auth.ActiveDirectory.Config.Users.SearchBase, a.client.Auth.ActiveDirectory.Config.Groups.SearchBase) - _, err = rbac.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, groupPrincipalID, rbac.ClusterMember.String()) + _, err = rbacapi.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, groupPrincipalID, rbac.ClusterMember.String()) require.NoError(a.T(), err, "Failed to create cluster role binding") projectResp, _, err := projects.CreateProjectAndNamespaceUsingWrangler(authAdmin, a.cluster.ID) @@ -303,7 +303,7 @@ func (a *ActiveDirectoryAuthProviderSuite) TestActiveDirectoryRestrictedModeBind RoleTemplateName: rbac.ProjectOwner.String(), } - userPRTBResp, err := krbac.CreateProjectRoleTemplateBinding(authAdmin, userPRTB) + userPRTBResp, err := authAdmin.WranglerContext.Mgmt.ProjectRoleTemplateBinding().Create(userPRTB) require.NoError(a.T(), err, "Failed to create PRTB for user [%v]", userInfo.Username) require.NotNil(a.T(), userPRTBResp, "PRTB should be created for user [%v]", userInfo.Username) } @@ -315,7 +315,7 @@ func (a *ActiveDirectoryAuthProviderSuite) TestActiveDirectoryAllowClusterAndPro defer subSession.Cleanup() doubleNestedGroupPrincipalID := authactions.GetGroupPrincipalID(authactions.ActiveDirectory, a.authConfig.DoubleNestedGroup, a.client.Auth.ActiveDirectory.Config.Users.SearchBase, a.client.Auth.ActiveDirectory.Config.Groups.SearchBase) - _, err = rbac.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, doubleNestedGroupPrincipalID, rbac.ClusterMember.String()) + _, err = rbacapi.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, doubleNestedGroupPrincipalID, rbac.ClusterMember.String()) require.NoError(a.T(), err, "Failed to create cluster role binding") projectResp, _, err := projects.CreateProjectAndNamespaceUsingWrangler(authAdmin, a.cluster.ID) @@ -329,7 +329,7 @@ func (a *ActiveDirectoryAuthProviderSuite) TestActiveDirectoryAllowClusterAndPro nestedGroupPrincipalID := authactions.GetGroupPrincipalID(authactions.ActiveDirectory, a.authConfig.NestedGroup, a.client.Auth.ActiveDirectory.Config.Users.SearchBase, a.client.Auth.ActiveDirectory.Config.Groups.SearchBase) - groupPRTBResp, err := rbac.CreateGroupProjectRoleTemplateBinding(authAdmin, projectName, prtbNamespace, nestedGroupPrincipalID, rbac.ProjectOwner.String()) + groupPRTBResp, err := rbacapi.CreateGroupProjectRoleTemplateBinding(authAdmin, projectName, prtbNamespace, nestedGroupPrincipalID, rbac.ProjectOwner.String()) require.NoError(a.T(), err, "Failed to create PRTB") require.NotNil(a.T(), groupPRTBResp, "PRTB should be created") diff --git a/validation/auth/provider/openldap/openldap_test.go b/validation/auth/provider/openldap/openldap_test.go index 6b55b6f7c..58a13f894 100644 --- a/validation/auth/provider/openldap/openldap_test.go +++ b/validation/auth/provider/openldap/openldap_test.go @@ -16,7 +16,7 @@ import ( "github.com/rancher/shepherd/pkg/session" authactions "github.com/rancher/tests/actions/auth" projectsapi "github.com/rancher/tests/actions/kubeapi/projects" - krbac "github.com/rancher/tests/actions/kubeapi/rbac" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/projects" "github.com/rancher/tests/actions/rbac" "github.com/sirupsen/logrus" @@ -156,7 +156,7 @@ func (a *OpenLDAPAuthProviderSuite) TestOpenLDAPGroupMembershipRefresh() { GroupPrincipalName: adminGroupPrincipalID, } - _, err = krbac.CreateGlobalRoleBinding(authAdmin, adminGlobalRole) + _, err = authAdmin.WranglerContext.Mgmt.GlobalRoleBinding().Create(adminGlobalRole) require.NoError(a.T(), err, "Failed to create admin global role binding") err = users.RefreshGroupMembership(authAdmin) @@ -171,7 +171,7 @@ func (a *OpenLDAPAuthProviderSuite) TestOpenLDAPGroupMembershipRefresh() { GroupPrincipalName: standardGroupPrincipalID, } - _, err = krbac.CreateGlobalRoleBinding(authAdmin, standardGlobalRole) + _, err = authAdmin.WranglerContext.Mgmt.GlobalRoleBinding().Create(standardGlobalRole) require.NoError(a.T(), err, "Failed to create standard global role binding") err = users.RefreshGroupMembership(authAdmin) @@ -189,7 +189,7 @@ func (a *OpenLDAPAuthProviderSuite) TestOpenLDAPNestedGroupClusterAccess() { a.client.Auth.OLDAP.Config.Users.SearchBase, a.client.Auth.OLDAP.Config.Groups.SearchBase, ) - _, err = rbac.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, doubleNestedGroupPrincipalID, rbac.ClusterOwner.String()) + _, err = rbacapi.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, doubleNestedGroupPrincipalID, rbac.ClusterOwner.String()) require.NoError(a.T(), err, "Failed to create cluster role binding") for _, userInfo := range a.authConfig.DoubleNestedUsers { @@ -203,7 +203,7 @@ func (a *OpenLDAPAuthProviderSuite) TestOpenLDAPNestedGroupClusterAccess() { rbac.VerifyUserCanListCluster(a.T(), a.client, userClient, a.cluster.ID, rbac.ClusterOwner) } - foundCRTB, err := rbac.GetClusterRoleTemplateBindingsForGroup(a.client, doubleNestedGroupPrincipalID, a.cluster.ID) + foundCRTB, err := rbacapi.GetClusterRoleTemplateBindingsForGroup(a.client, doubleNestedGroupPrincipalID, a.cluster.ID) require.NoError(a.T(), err, "Failed to get group CRTB") require.NotNil(a.T(), foundCRTB, "Cluster role binding should exist for group") } @@ -214,7 +214,7 @@ func (a *OpenLDAPAuthProviderSuite) TestOpenLDAPNonMemberClusterAccessDenied() { defer subSession.Cleanup() doubleNestedGroupPrincipalID := authactions.GetGroupPrincipalID(authactions.OpenLdap, a.authConfig.DoubleNestedGroup, a.client.Auth.OLDAP.Config.Users.SearchBase, a.client.Auth.OLDAP.Config.Groups.SearchBase) - _, err = rbac.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, doubleNestedGroupPrincipalID, rbac.ClusterOwner.String()) + _, err = rbacapi.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, doubleNestedGroupPrincipalID, rbac.ClusterOwner.String()) require.NoError(a.T(), err, "Failed to create cluster role binding") for _, userInfo := range a.authConfig.Users { @@ -248,7 +248,7 @@ func (a *OpenLDAPAuthProviderSuite) TestOpenLDAPNestedGroupProjectAccess() { projectName := fmt.Sprintf("%s:%s", projectResp.Namespace, projectResp.Name) - groupPRTBResp, err := rbac.CreateGroupProjectRoleTemplateBinding(authAdmin, projectName, prtbNamespace, nestedGroupPrincipalID, rbac.ProjectOwner.String()) + groupPRTBResp, err := rbacapi.CreateGroupProjectRoleTemplateBinding(authAdmin, projectName, prtbNamespace, nestedGroupPrincipalID, rbac.ProjectOwner.String()) require.NoError(a.T(), err, "Failed to create PRTB") require.NotNil(a.T(), groupPRTBResp, "PRTB should be created") @@ -274,7 +274,7 @@ func (a *OpenLDAPAuthProviderSuite) TestOpenLDAPRestrictedModeBindings() { defer subSession.Cleanup() groupPrincipalID := authactions.GetGroupPrincipalID(authactions.OpenLdap, a.authConfig.Group, a.client.Auth.OLDAP.Config.Users.SearchBase, a.client.Auth.OLDAP.Config.Groups.SearchBase) - _, err = rbac.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, groupPrincipalID, rbac.ClusterMember.String()) + _, err = rbacapi.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, groupPrincipalID, rbac.ClusterMember.String()) require.NoError(a.T(), err, "Failed to create cluster role binding") projectResp, _, err := projects.CreateProjectAndNamespaceUsingWrangler(authAdmin, a.cluster.ID) @@ -302,7 +302,7 @@ func (a *OpenLDAPAuthProviderSuite) TestOpenLDAPRestrictedModeBindings() { RoleTemplateName: rbac.ProjectOwner.String(), } - userPRTBResp, err := krbac.CreateProjectRoleTemplateBinding(authAdmin, userPRTB) + userPRTBResp, err := authAdmin.WranglerContext.Mgmt.ProjectRoleTemplateBinding().Create(userPRTB) require.NoError(a.T(), err, "Failed to create PRTB for user [%v]", userInfo.Username) require.NotNil(a.T(), userPRTBResp, "PRTB should be created for user [%v]", userInfo.Username) } @@ -314,7 +314,7 @@ func (a *OpenLDAPAuthProviderSuite) TestOpenLDAPAllowClusterAndProjectMembersAcc defer subSession.Cleanup() doubleNestedGroupPrincipalID := authactions.GetGroupPrincipalID(authactions.OpenLdap, a.authConfig.DoubleNestedGroup, a.client.Auth.OLDAP.Config.Users.SearchBase, a.client.Auth.OLDAP.Config.Groups.SearchBase) - _, err = rbac.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, doubleNestedGroupPrincipalID, rbac.ClusterMember.String()) + _, err = rbacapi.CreateGroupClusterRoleTemplateBinding(authAdmin, a.cluster.ID, doubleNestedGroupPrincipalID, rbac.ClusterMember.String()) require.NoError(a.T(), err, "Failed to create cluster role binding") projectResp, _, err := projects.CreateProjectAndNamespaceUsingWrangler(authAdmin, a.cluster.ID) @@ -328,7 +328,7 @@ func (a *OpenLDAPAuthProviderSuite) TestOpenLDAPAllowClusterAndProjectMembersAcc nestedGroupPrincipalID := authactions.GetGroupPrincipalID(authactions.OpenLdap, a.authConfig.NestedGroup, a.client.Auth.OLDAP.Config.Users.SearchBase, a.client.Auth.OLDAP.Config.Groups.SearchBase) - groupPRTBResp, err := rbac.CreateGroupProjectRoleTemplateBinding(authAdmin, projectName, prtbNamespace, nestedGroupPrincipalID, rbac.ProjectOwner.String()) + groupPRTBResp, err := rbacapi.CreateGroupProjectRoleTemplateBinding(authAdmin, projectName, prtbNamespace, nestedGroupPrincipalID, rbac.ProjectOwner.String()) require.NoError(a.T(), err, "Failed to create PRTB") require.NotNil(a.T(), groupPRTBResp, "PRTB should be created") diff --git a/validation/auth/userretention/userretention_delete_user_test.go b/validation/auth/userretention/userretention_delete_user_test.go index 76981b61f..96f9d7fa1 100644 --- a/validation/auth/userretention/userretention_delete_user_test.go +++ b/validation/auth/userretention/userretention_delete_user_test.go @@ -11,7 +11,7 @@ import ( "github.com/rancher/shepherd/extensions/users" "github.com/rancher/shepherd/pkg/session" "github.com/rancher/tests/actions/auth" - "github.com/rancher/tests/actions/rbac" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -108,7 +108,7 @@ func (ur *URDeleteTestSuite) TestAdminUserGetDeleted() { require.ErrorContains(ur.T(), err, unauthorizedError) logrus.Info("Checking bindings after user deletion") - bindingsAfter, err := rbac.GetBindings(ur.client, newAdminUser.ID) + bindingsAfter, err := rbacapi.GetBindings(ur.client, newAdminUser.ID) require.NoError(ur.T(), err) require.Empty(ur.T(), bindingsAfter["RoleBindings"], "Expected no RoleBindings after user deletion") @@ -156,7 +156,7 @@ func (ur *URDeleteTestSuite) TestStandardUserGetDeleted() { require.ErrorContains(ur.T(), err, unauthorizedError) logrus.Info("Checking bindings after user deletion") - bindingsAfter, err := rbac.GetBindings(ur.client, newStdUser.ID) + bindingsAfter, err := rbacapi.GetBindings(ur.client, newStdUser.ID) require.NoError(ur.T(), err) require.Empty(ur.T(), bindingsAfter["RoleBindings"], "Expected no RoleBindings after user deletion") @@ -232,7 +232,7 @@ func (ur *URDeleteTestSuite) TestUserIsNotGetDeletedWithDryRun() { require.NoError(ur.T(), err) logrus.Info("Getting initial bindings") - bindingsBefore, _ := rbac.GetBindings(ur.client, newUser.ID) + bindingsBefore, _ := rbacapi.GetBindings(ur.client, newUser.ID) logrus.Info("Waiting for default duration") time.Sleep(2 * defaultWaitDuration) @@ -243,7 +243,7 @@ func (ur *URDeleteTestSuite) TestUserIsNotGetDeletedWithDryRun() { require.Equal(ur.T(), isActive, *(userReLogin).Enabled) logrus.Info("Checking bindings after wait period") - bindingsAfter, _ := rbac.GetBindings(ur.client, newUser.ID) + bindingsAfter, _ := rbacapi.GetBindings(ur.client, newUser.ID) require.Equal(ur.T(), bindingsBefore, bindingsAfter, "RoleBindings") require.Equal(ur.T(), bindingsBefore, bindingsAfter, "ClusterRoleBindings") require.Equal(ur.T(), bindingsBefore, bindingsAfter, "GlobalRoleBindings") diff --git a/validation/auth/userretention/userretention_disable_user_test.go b/validation/auth/userretention/userretention_disable_user_test.go index 62ef16723..554a20fcf 100644 --- a/validation/auth/userretention/userretention_disable_user_test.go +++ b/validation/auth/userretention/userretention_disable_user_test.go @@ -11,7 +11,7 @@ import ( "github.com/rancher/shepherd/extensions/users" "github.com/rancher/shepherd/pkg/session" "github.com/rancher/tests/actions/auth" - "github.com/rancher/tests/actions/rbac" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -100,7 +100,7 @@ func (ur *URDisableTestSuite) TestAdminUserGetDisabled() { require.NoError(ur.T(), err) require.Equal(ur.T(), isActive, *(userReLogin).Enabled) - bindingsBefore, err := rbac.GetBindings(ur.client, newAdminUser.ID) + bindingsBefore, err := rbacapi.GetBindings(ur.client, newAdminUser.ID) require.NoError(ur.T(), err, "Failed to get initial bindings") logrus.Info("Polling user status") @@ -114,7 +114,7 @@ func (ur *URDisableTestSuite) TestAdminUserGetDisabled() { logrus.Info("Attempting login with disabled user") _, err = auth.GetUserAfterLogin(ur.client, *newAdminUser) require.ErrorContains(ur.T(), err, forbiddenError) - bindingsAfter, err := rbac.GetBindings(ur.client, newAdminUser.ID) + bindingsAfter, err := rbacapi.GetBindings(ur.client, newAdminUser.ID) require.NoError(ur.T(), err, "Failed to get final bindings") ur.assertBindingsEqual(bindingsBefore, bindingsAfter) @@ -135,7 +135,7 @@ func (ur *URDisableTestSuite) TestStandardUserGetDisabled() { require.Equal(ur.T(), isActive, *(userReLogin).Enabled) logrus.Info("Getting initial bindings") - bindingsBefore, err := rbac.GetBindings(ur.client, newStdUser.ID) + bindingsBefore, err := rbacapi.GetBindings(ur.client, newStdUser.ID) require.NoError(ur.T(), err, "Failed to get initial bindings") logrus.Info("Polling user status") @@ -151,7 +151,7 @@ func (ur *URDisableTestSuite) TestStandardUserGetDisabled() { require.ErrorContains(ur.T(), err, forbiddenError) logrus.Info("Getting final bindings") - bindingsAfter, err := rbac.GetBindings(ur.client, newStdUser.ID) + bindingsAfter, err := rbacapi.GetBindings(ur.client, newStdUser.ID) require.NoError(ur.T(), err, "Failed to get final bindings") ur.assertBindingsEqual(bindingsBefore, bindingsAfter) } @@ -171,7 +171,7 @@ func (ur *URDisableTestSuite) TestDisabledUserGetEnabled() { require.Equal(ur.T(), isActive, *(userReLogin).Enabled) logrus.Info("Getting initial bindings") - bindingsBefore, err := rbac.GetBindings(ur.client, newStdUser.ID) + bindingsBefore, err := rbacapi.GetBindings(ur.client, newStdUser.ID) require.NoError(ur.T(), err, "Failed to get initial bindings") logrus.Info("Polling user status to disable") @@ -199,7 +199,7 @@ func (ur *URDisableTestSuite) TestDisabledUserGetEnabled() { require.Equal(ur.T(), isActive, *(activeUserReLogin).Enabled) logrus.Info("Getting final bindings") - bindingsAfterEnabled, err := rbac.GetBindings(ur.client, newStdUser.ID) + bindingsAfterEnabled, err := rbacapi.GetBindings(ur.client, newStdUser.ID) require.NoError(ur.T(), err, "Failed to get final bindings") ur.assertBindingsEqual(bindingsBefore, bindingsAfterEnabled) } @@ -241,7 +241,7 @@ func (ur *URDisableTestSuite) TestUserDisableByUpdatingUserattributes() { require.NoError(ur.T(), err) logrus.Info("Getting initial bindings") - bindingsBefore, err := rbac.GetBindings(ur.client, newStdUser.ID) + bindingsBefore, err := rbacapi.GetBindings(ur.client, newStdUser.ID) require.NoError(ur.T(), err, "Failed to get initial bindings") logrus.Info("Updating user attributes") @@ -269,7 +269,7 @@ func (ur *URDisableTestSuite) TestUserDisableByUpdatingUserattributes() { require.ErrorContains(ur.T(), err, forbiddenError) logrus.Info("Getting final bindings") - bindingsAfter, err := rbac.GetBindings(ur.client, newStdUser.ID) + bindingsAfter, err := rbacapi.GetBindings(ur.client, newStdUser.ID) require.NoError(ur.T(), err, "Failed to get final bindings") ur.assertBindingsEqual(bindingsBefore, bindingsAfter) } @@ -288,7 +288,7 @@ func (ur *URDisableTestSuite) TestUserIsNotDisabledWithDryRun() { require.NoError(ur.T(), err) logrus.Info("Getting initial bindings") - bindingsBefore, err := rbac.GetBindings(ur.client, newStdUser.ID) + bindingsBefore, err := rbacapi.GetBindings(ur.client, newStdUser.ID) require.NoError(ur.T(), err, "Failed to get initial bindings") logrus.Info("Updating user attributes") @@ -312,7 +312,7 @@ func (ur *URDisableTestSuite) TestUserIsNotDisabledWithDryRun() { require.Equal(ur.T(), isActive, *(userReLogin).Enabled) logrus.Info("Getting final bindings") - bindingsAfter, err := rbac.GetBindings(ur.client, newStdUser.ID) + bindingsAfter, err := rbacapi.GetBindings(ur.client, newStdUser.ID) require.NoError(ur.T(), err, "Failed to get final bindings") ur.assertBindingsEqual(bindingsBefore, bindingsAfter) diff --git a/validation/hostedtenant/rbac/hosted_tenant_rbac_test.go b/validation/hostedtenant/rbac/hosted_tenant_rbac_test.go index c20e398f1..2f1529bc3 100644 --- a/validation/hostedtenant/rbac/hosted_tenant_rbac_test.go +++ b/validation/hostedtenant/rbac/hosted_tenant_rbac_test.go @@ -11,6 +11,7 @@ import ( "github.com/rancher/shepherd/pkg/config" "github.com/rancher/shepherd/pkg/session" "github.com/rancher/tests/actions/hostedtenant" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/rbac" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" @@ -59,7 +60,7 @@ func (h *HostedRancherTestSuite) TestGlobalRoleInheritedClusterRoles() { log.Info("Create global role with inheritedClusterRoles") inheritedClusterRoles := []string{rbac.ClusterOwner.String()} - createdGlobalRole, err := rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(h.hostClient, inheritedClusterRoles) + createdGlobalRole, err := rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(h.hostClient, inheritedClusterRoles) require.NoError(h.T(), err) log.Info("Verify the global role is created on the hosted Rancher") @@ -75,32 +76,32 @@ func (h *HostedRancherTestSuite) TestGlobalRoleInheritedClusterRoles() { require.NoError(h.T(), err) log.Info("Verify global role bindings on host") - hostGrb, err := rbac.GetGlobalRoleBindingByUserAndRole(h.hostClient, createdUser.ID, createdGlobalRole.Name) + hostGrb, err := rbacapi.GetGlobalRoleBindingByUserAndRole(h.hostClient, createdUser.ID, createdGlobalRole.Name) require.NoError(h.T(), err) require.Equal(h.T(), hostGrb.GlobalRoleName, createdGlobalRole.Name) log.Info("Verify no global role bindings on tenant") - _, err = rbac.GetGlobalRoleBindingByUserAndRole(h.tenantClient, createdUser.ID, createdGlobalRole.Name) + _, err = rbacapi.GetGlobalRoleBindingByUserAndRole(h.tenantClient, createdUser.ID, createdGlobalRole.Name) require.Error(h.T(), err, "Expected error because global role binding should not exist on tenant") require.Contains(h.T(), err.Error(), "context deadline exceeded", "Expected timeout error when GRB is not found") grbName := hostGrb.Name log.Info("Verify CRTB on host") - crtbs, err := rbac.ListCRTBsByLabel(h.hostClient, rbac.GrbOwnerLabel, grbName, len(inheritedClusterRoles)) + crtbs, err := rbacapi.ListCRTBsByLabel(h.hostClient, rbac.GrbOwnerLabel, grbName, len(inheritedClusterRoles)) require.NoError(h.T(), err) require.GreaterOrEqual(h.T(), len(crtbs.Items), len(inheritedClusterRoles), "Should have CRTBs on host") log.Info("Verify role bindings on host") for _, crtb := range crtbs.Items { namespaces := []string{rbac.GlobalDataNS, crtb.ClusterName} - userRBs, err := rbac.GetRoleBindingsForUsers(h.hostClient, crtb.UserName, namespaces) + userRBs, err := rbacapi.GetRoleBindingsForUsers(h.hostClient, crtb.UserName, namespaces) require.NoError(h.T(), err) require.Greater(h.T(), len(userRBs), 0, "Should have role bindings on host for user %s", crtb.UserName) } log.Info("Verify cluster role bindings on host") - userCRBs, err := rbac.GetClusterRoleBindingsForUsers(h.hostClient, crtbs) + userCRBs, err := rbacapi.GetClusterRoleBindingsForUsers(h.hostClient, crtbs) require.NoError(h.T(), err) require.Greater(h.T(), len(userCRBs), 0, "Should have cluster role bindings on host") diff --git a/validation/projects/project_scoped_secrets_test.go b/validation/projects/project_scoped_secrets_test.go index 5682d9060..8e7952c4b 100644 --- a/validation/projects/project_scoped_secrets_test.go +++ b/validation/projects/project_scoped_secrets_test.go @@ -87,7 +87,7 @@ func (pss *ProjectScopedSecretTestSuite) TestCreateProjectScopedSecretLocalClust subSession := pss.session.NewSession() defer subSession.Cleanup() - pss.testProjectScopedSecret(rbac.LocalCluster, corev1.SecretTypeOpaque, opaqueSecretData) + pss.testProjectScopedSecret(clusterapi.LocalCluster, corev1.SecretTypeOpaque, opaqueSecretData) } func (pss *ProjectScopedSecretTestSuite) TestCreateProjectScopedOpaqueSecret() { @@ -176,11 +176,11 @@ func (pss *ProjectScopedSecretTestSuite) TestDeleteProjectScopedSecret() { log.Info("Delete the Project scoped secret.") backingNamespace := fmt.Sprintf("%s-%s", pss.cluster.ID, createdProject.Name) - err := secrets.DeleteSecret(pss.client, rbac.LocalCluster, backingNamespace, createdProjectScopedSecret.Name) + err := secrets.DeleteSecret(pss.client, clusterapi.LocalCluster, backingNamespace, createdProjectScopedSecret.Name) require.NoError(pss.T(), err) log.Info("Verify that the project scoped secret is deleted.") - _, err = secretsapi.GetSecretByName(pss.client, rbac.LocalCluster, backingNamespace, createdProjectScopedSecret.Name, metav1.GetOptions{}) + _, err = secretsapi.GetSecretByName(pss.client, clusterapi.LocalCluster, backingNamespace, createdProjectScopedSecret.Name, metav1.GetOptions{}) require.Error(pss.T(), err) require.True(pss.T(), apierrors.IsNotFound(err), "Expected NotFound error, got: %v", err) @@ -208,7 +208,7 @@ func (pss *ProjectScopedSecretTestSuite) TestProjectScopedSecretCleanupOnProject log.Info("Verify that the project scoped secret is deleted.") backingNamespace := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("%s-%s", pss.cluster.ID, createdProject.Name)}} - err = secrets.WaitForSecretInNamespaces(pss.client, rbac.LocalCluster, createdProjectScopedSecret.Name, []*corev1.Namespace{backingNamespace}, false) + err = secrets.WaitForSecretInNamespaces(pss.client, clusterapi.LocalCluster, createdProjectScopedSecret.Name, []*corev1.Namespace{backingNamespace}, false) require.NoError(pss.T(), err, "Expected secret to be deleted but it still exists or an unexpected error occurred") log.Info("Verify that the secret is removed from all the namespaces in the project.") @@ -306,11 +306,11 @@ func (pss *ProjectScopedSecretTestSuite) TestProjectScopedSecretByRole() { log.Infof("As a %v, delete the project scoped secret %s in project %s", tt.role.String(), createdProjectScopedSecret.Name, createdProject.Name) backingNamespace := fmt.Sprintf("%s-%s", pss.cluster.ID, createdProject.Name) - err = secrets.DeleteSecret(standardUserClient, rbac.LocalCluster, backingNamespace, createdProjectScopedSecret.Name) + err = secrets.DeleteSecret(standardUserClient, clusterapi.LocalCluster, backingNamespace, createdProjectScopedSecret.Name) assert.NoError(pss.T(), err, "Failed to delete project scoped secret") log.Info("Verify that the project scoped secret is deleted.") - _, err = secretsapi.GetSecretByName(standardUserClient, rbac.LocalCluster, backingNamespace, createdProjectScopedSecret.Name, metav1.GetOptions{}) + _, err = secretsapi.GetSecretByName(standardUserClient, clusterapi.LocalCluster, backingNamespace, createdProjectScopedSecret.Name, metav1.GetOptions{}) assert.Error(pss.T(), err) assert.True(pss.T(), apierrors.IsNotFound(err), "Expected NotFound error, got: %v", err) @@ -359,11 +359,11 @@ func (pss *ProjectScopedSecretTestSuite) TestProjectScopedSecretAsClusterMember( log.Infof("As a %v, delete the project scoped secret %s in project %s", role, createdProjectScopedSecret.Name, createdProject.Name) backingNamespace := fmt.Sprintf("%s-%s", pss.cluster.ID, createdProject.Name) - err = secrets.DeleteSecret(standardUserClient, rbac.LocalCluster, backingNamespace, createdProjectScopedSecret.Name) + err = secrets.DeleteSecret(standardUserClient, clusterapi.LocalCluster, backingNamespace, createdProjectScopedSecret.Name) require.NoError(pss.T(), err, "Failed to delete project scoped secret as cluster member") log.Info("Verify that the project scoped secret is deleted.") - _, err = secretsapi.GetSecretByName(standardUserClient, rbac.LocalCluster, backingNamespace, createdProjectScopedSecret.Name, metav1.GetOptions{}) + _, err = secretsapi.GetSecretByName(standardUserClient, clusterapi.LocalCluster, backingNamespace, createdProjectScopedSecret.Name, metav1.GetOptions{}) require.Error(pss.T(), err) require.True(pss.T(), apierrors.IsNotFound(err), "Expected NotFound error, got: %v", err) @@ -389,7 +389,7 @@ func (pss *ProjectScopedSecretTestSuite) TestProjectMemberCannotAccessOtherProje log.Infof("As a %v, try to delete the project scoped secret %s in project %s (unauthorized access).", role, createdProjectSecret.Name, createdProject1.Name) backingNamespace := fmt.Sprintf("%s-%s", pss.cluster.ID, createdProject1.Name) - err = secrets.DeleteSecret(standardUserClient, rbac.LocalCluster, backingNamespace, createdProjectSecret.Name) + err = secrets.DeleteSecret(standardUserClient, clusterapi.LocalCluster, backingNamespace, createdProjectSecret.Name) require.Error(pss.T(), err) require.True(pss.T(), apierrors.IsForbidden(err), "Expected Forbidden error, got: %v", err) @@ -412,7 +412,7 @@ func (pss *ProjectScopedSecretTestSuite) TestUserWithProjectsViewAllCannotAccess log.Infof("As user with role %v, try to get the project scoped secret %s", projectViewerRole, createdProjectSecret.Name) backingNamespace := fmt.Sprintf("%s-%s", pss.cluster.ID, createdProject.Name) - _, err = secretsapi.GetSecretByName(standardUserClient, rbac.LocalCluster, backingNamespace, createdProjectSecret.Name, metav1.GetOptions{}) + _, err = secretsapi.GetSecretByName(standardUserClient, clusterapi.LocalCluster, backingNamespace, createdProjectSecret.Name, metav1.GetOptions{}) require.Error(pss.T(), err) require.True(pss.T(), apierrors.IsForbidden(err), "Expected Forbidden error when getting project scoped secret, got: %v", err) @@ -429,12 +429,12 @@ func (pss *ProjectScopedSecretTestSuite) TestVerifyProjectScopedSecretRancherRes createdProject, namespaceList, createdProjectScopedSecret := pss.testProjectScopedSecret(pss.cluster.ID, corev1.SecretTypeOpaque, opaqueSecretData) log.Info("Restart Rancher") - err := deployment.RestartDeployment(pss.client, rbac.LocalCluster, rbac.RancherDeploymentNamespace, rbac.RancherDeploymentName) + err := deployment.RestartDeployment(pss.client, clusterapi.LocalCluster, rbac.RancherDeploymentNamespace, rbac.RancherDeploymentName) require.NoError(pss.T(), err, "Failed to restart Rancher deployment") log.Info("Verify that the project scoped secret still exists after Rancher restart.") backingNamespace := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("%s-%s", pss.cluster.ID, createdProject.Name)}} - err = secrets.WaitForSecretInNamespaces(pss.client, rbac.LocalCluster, createdProjectScopedSecret.Name, []*corev1.Namespace{backingNamespace}, true) + err = secrets.WaitForSecretInNamespaces(pss.client, clusterapi.LocalCluster, createdProjectScopedSecret.Name, []*corev1.Namespace{backingNamespace}, true) require.NoErrorf(pss.T(), err, "Project scoped secret %q not found in backing namespace %q after Rancher restart: %v", createdProjectScopedSecret.Name, backingNamespace, err) log.Info("Verify that the secret propagated to all the namespaces in the project still exists.") @@ -450,7 +450,7 @@ func (pss *ProjectScopedSecretTestSuite) TestProjectScopedSecretWithSameNameInSa log.Infof("Attempt to create another project scoped secret with the same name '%s' in project '%s'", createdProjectScopedSecret.Name, createdProject.Name) backingNamespace := fmt.Sprintf("%s-%s", pss.cluster.ID, createdProject.Name) - ctx, err := clusterapi.GetClusterWranglerContext(pss.client, rbac.LocalCluster) + ctx, err := clusterapi.GetClusterWranglerContext(pss.client, clusterapi.LocalCluster) require.NoError(pss.T(), err) secretName := createdProjectScopedSecret.Name @@ -476,7 +476,7 @@ func (pss *ProjectScopedSecretTestSuite) TestProjectScopedSecretWithSameNameInDi log.Infof("Create a project scoped secret with the same name '%s' in project '%s'", createdProjectScopedSecret.Name, createdProject2.Name) backingNamespace := fmt.Sprintf("%s-%s", pss.cluster.ID, createdProject2.Name) - ctx, err := clusterapi.GetClusterWranglerContext(pss.client, rbac.LocalCluster) + ctx, err := clusterapi.GetClusterWranglerContext(pss.client, clusterapi.LocalCluster) require.NoError(pss.T(), err) secretName := createdProjectScopedSecret.Name @@ -514,7 +514,7 @@ func (pss *ProjectScopedSecretTestSuite) TestProjectScopedSecrettPropagatedToNam log.Infof("Create project scoped secret with the same name as the namespace in project '%s'", createdProject.Name) backingNamespace := fmt.Sprintf("%s-%s", pss.cluster.ID, createdProject.Name) - ctx, err := clusterapi.GetClusterWranglerContext(pss.client, rbac.LocalCluster) + ctx, err := clusterapi.GetClusterWranglerContext(pss.client, clusterapi.LocalCluster) require.NoError(pss.T(), err) labels := map[string]string{ diff --git a/validation/projects/projects_rbac_test.go b/validation/projects/projects_rbac_test.go index f622879a5..1d909ce0c 100644 --- a/validation/projects/projects_rbac_test.go +++ b/validation/projects/projects_rbac_test.go @@ -12,8 +12,8 @@ import ( "github.com/rancher/shepherd/extensions/defaults" namegen "github.com/rancher/shepherd/pkg/namegenerator" "github.com/rancher/shepherd/pkg/session" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" projectapi "github.com/rancher/tests/actions/kubeapi/projects" - rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/rbac" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" @@ -225,7 +225,7 @@ func (rbp *RbacProjectTestSuite) TestCrossClusterResourceIsolation() { defer subSession.Cleanup() log.Info("Creating a project and associated namespace in the local cluster") - firstProject, firstNamespace, err := projectapi.CreateProjectAndNamespace(rbp.client, rbac.LocalCluster) + firstProject, firstNamespace, err := projectapi.CreateProjectAndNamespace(rbp.client, clusterapi.LocalCluster) require.NoError(rbp.T(), err) log.Info("Creating a standard user and assigning the cluster-member role in the downstream cluster") @@ -242,7 +242,7 @@ func (rbp *RbacProjectTestSuite) TestCrossClusterResourceIsolation() { require.NoError(rbp.T(), err, "Failed to create project in downstream cluster") log.Infof("As %s, attempting to create a PRTB referencing the project in the local cluster", rbac.ClusterMember.String()) - prtb.ProjectName = fmt.Sprintf("%s:%s", rbac.LocalCluster, firstProject.Name) + prtb.ProjectName = fmt.Sprintf("%s:%s", clusterapi.LocalCluster, firstProject.Name) prtb.Name = namegen.AppendRandomString("prtb-") prtb.RoleTemplateName = rbac.ProjectOwner.String() prtb.UserPrincipalName = "local://" + standardUser.ID @@ -250,7 +250,7 @@ func (rbp *RbacProjectTestSuite) TestCrossClusterResourceIsolation() { if firstProject.Status.BackingNamespace != "" { prtb.Namespace = firstProject.Status.BackingNamespace } - _, err = rbacapi.CreateProjectRoleTemplateBinding(standardUserClient, &prtb) + _, err = standardUserClient.WranglerContext.Mgmt.ProjectRoleTemplateBinding().Create(&prtb) require.Error(rbp.T(), err, "Expected failure: user should not be able to create PRTB referencing the project in the local cluster") log.Infof("As %s, verifying that the user cannot access the namespace in the local cluster", rbac.ClusterMember.String()) diff --git a/validation/projects/projects_test.go b/validation/projects/projects_test.go index 541cbfbf0..db365c9a6 100644 --- a/validation/projects/projects_test.go +++ b/validation/projects/projects_test.go @@ -13,7 +13,6 @@ import ( clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" namespaceapi "github.com/rancher/tests/actions/kubeapi/namespaces" projectapi "github.com/rancher/tests/actions/kubeapi/projects" - rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/projects" "github.com/rancher/tests/actions/rbac" "github.com/rancher/tests/actions/workloads/deployment" @@ -56,7 +55,7 @@ func (pr *ProjectsTestSuite) TestProjectsCrudLocalCluster() { defer subSession.Cleanup() log.Info("Create a project in the local cluster and verify that the project can be listed.") - createdProject, err := projectapi.CreateProject(pr.client, rbacapi.LocalCluster) + createdProject, err := projectapi.CreateProject(pr.client, clusterapi.LocalCluster) require.NoError(pr.T(), err) projectList, err := projectapi.ListProjects(pr.client, createdProject.Namespace, metav1.ListOptions{ @@ -138,14 +137,14 @@ func (pr *ProjectsTestSuite) TestDeleteSystemProject() { defer subSession.Cleanup() log.Info("Delete the System Project in the local cluster.") - projectList, err := projectapi.ListProjects(pr.client, rbacapi.LocalCluster, metav1.ListOptions{ + projectList, err := projectapi.ListProjects(pr.client, clusterapi.LocalCluster, metav1.ListOptions{ LabelSelector: fmt.Sprintf("%s=%s", projectapi.SystemProjectLabel, "true"), }) require.NoError(pr.T(), err) require.Equal(pr.T(), 1, len(projectList.Items), "Expected one project in the list") systemProjectName := projectList.Items[0].ObjectMeta.Name - err = projectapi.DeleteProject(pr.client, rbacapi.LocalCluster, systemProjectName) + err = projectapi.DeleteProject(pr.client, clusterapi.LocalCluster, systemProjectName) require.Error(pr.T(), err, "Failed to delete project") expectedErrorMessage := "admission webhook \"rancher.cattle.io.projects.management.cattle.io\" denied the request: System Project cannot be deleted" require.Equal(pr.T(), expectedErrorMessage, err.Error()) diff --git a/validation/projects/rbac_terminating_project_test.go b/validation/projects/rbac_terminating_project_test.go index f69f870a1..ac6a80cb3 100644 --- a/validation/projects/rbac_terminating_project_test.go +++ b/validation/projects/rbac_terminating_project_test.go @@ -11,6 +11,7 @@ import ( "github.com/rancher/shepherd/extensions/clusters" "github.com/rancher/shepherd/extensions/users" "github.com/rancher/shepherd/pkg/session" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" projectapi "github.com/rancher/tests/actions/kubeapi/projects" rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/projects" @@ -81,7 +82,7 @@ func (rtp *RbacTerminatingProjectTestSuite) TestUserAdditionToClusterWithTermina logCaptureStartTime = time.Now() log.Info("Verify that there are no errors in the Rancher logs related to role binding.") errorRegex := `\[ERROR\] error syncing '(.*?)': handler mgmt-auth-crtb-controller: .*? (?:not found|is forbidden), requeuing` - err = pod.CheckPodLogsForErrors(rtp.client, rbacapi.LocalCluster, leaderPodName, rbac.RancherDeploymentNamespace, errorRegex, logCaptureStartTime) + err = pod.CheckPodLogsForErrors(rtp.client, clusterapi.LocalCluster, leaderPodName, rbac.RancherDeploymentNamespace, errorRegex, logCaptureStartTime) require.NoError(rtp.T(), err) logCaptureStartTime = time.Now() @@ -91,7 +92,7 @@ func (rtp *RbacTerminatingProjectTestSuite) TestUserAdditionToClusterWithTermina require.NoError(rtp.T(), err, "Failed to remove the finalizer.") log.Info("Verify that there are no errors in the Rancher logs related to role binding.") - err = pod.CheckPodLogsForErrors(rtp.client, rbacapi.LocalCluster, leaderPodName, rbac.RancherDeploymentNamespace, errorRegex, logCaptureStartTime) + err = pod.CheckPodLogsForErrors(rtp.client, clusterapi.LocalCluster, leaderPodName, rbac.RancherDeploymentNamespace, errorRegex, logCaptureStartTime) require.NoError(rtp.T(), err) } @@ -122,7 +123,7 @@ func (rtp *RbacTerminatingProjectTestSuite) TestUserAdditionToProjectWithTermina require.NoError(rtp.T(), err) log.Info("Add the standard user to the project as project owner.") - _, err = rbac.CreateProjectRoleTemplateBinding(rtp.client, createdUser, createdProject, rbac.ProjectOwner.String()) + _, err = rbacapi.CreateProjectRoleTemplateBinding(rtp.client, createdUser, createdProject, rbac.ProjectOwner.String()) require.Error(rtp.T(), err) log.Info("Remove the finalizer that was previously added to the project.") diff --git a/validation/rbac/aggregatedclusterroles/README.md b/validation/rbac/aggregatedclusterroles/README.md new file mode 100644 index 000000000..aa10a6342 --- /dev/null +++ b/validation/rbac/aggregatedclusterroles/README.md @@ -0,0 +1,24 @@ +# Aggregated Cluster Roles + +## Pre-requisites + +- Ensure you have an existing cluster that the user has access to. If you do not have a downstream cluster in Rancher, create one first before running this test. + +## Test Setup + +Your GO suite should be set to `-run ^Test$` + +- To run the CRTB tests in aggregated_cluster_roles_crtb_test.go, set the GO suite to `-run ^TestAggregatedClusterRolesCrtbTestSuite$` +- To run the PRTB tests in aggregated_cluster_roles_prtb_test.go, set the GO suite to `-run ^TestAggregatedClusterRolesPrtbTestSuite$` +- To run the CRTB tests in aggregated_cluster_roles_cleanup_test.go, set the GO suite to `-run ^TestAggregatedClusterRolesCleanupTestSuite$` + +In your config file, set the following: + +```yaml +rancher: + host: "rancher_server_address" + adminToken: "rancher_admin_token" + insecure: True #optional + cleanup: True #optional + clusterName: "cluster_name" +``` diff --git a/validation/rbac/aggregatedclusterroles/aggregated_cluster_roles_cleanup_test.go b/validation/rbac/aggregatedclusterroles/aggregated_cluster_roles_cleanup_test.go new file mode 100644 index 000000000..f01be4430 --- /dev/null +++ b/validation/rbac/aggregatedclusterroles/aggregated_cluster_roles_cleanup_test.go @@ -0,0 +1,592 @@ +//go:build (validation || infra.any || cluster.any || extended) && !sanity && !stress && !2.9 && !2.10 && !2.11 && !2.12 && !2.13 + +package aggregatedclusterroles + +import ( + "testing" + + v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3" + "github.com/rancher/shepherd/clients/rancher" + management "github.com/rancher/shepherd/clients/rancher/generated/management/v3" + "github.com/rancher/shepherd/extensions/clusters" + "github.com/rancher/shepherd/extensions/users" + "github.com/rancher/shepherd/pkg/session" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" + namespaceapi "github.com/rancher/tests/actions/kubeapi/namespaces" + projectapi "github.com/rancher/tests/actions/kubeapi/projects" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" + "github.com/rancher/tests/actions/rbac" + "github.com/rancher/tests/actions/secrets" + "github.com/rancher/tests/actions/workloads/deployment" + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type AggregatedClusterRolesCleanupTestSuite struct { + suite.Suite + client *rancher.Client + session *session.Session + cluster *management.Cluster +} + +func (acrd *AggregatedClusterRolesCleanupTestSuite) TearDownSuite() { + acrd.session.Cleanup() + + log.Infof("Disabling the feature flag %s", rbacapi.AggregatedRoleTemplatesFeatureFlag) + err := rbacapi.SetAggregatedClusterRoleFeatureFlag(acrd.client, false) + if err != nil { + log.Warnf("Failed to disable the feature flag during teardown: %v", err) + } +} + +func (acrd *AggregatedClusterRolesCleanupTestSuite) SetupSuite() { + acrd.session = session.NewSession() + + client, err := rancher.NewClient("", acrd.session) + require.NoError(acrd.T(), err) + acrd.client = client + + log.Info("Getting cluster name from the config file and append cluster details to the test suite struct.") + clusterName := client.RancherConfig.ClusterName + require.NotEmptyf(acrd.T(), clusterName, "Cluster name should be set in the config file") + clusterID, err := clusters.GetClusterIDByName(acrd.client, clusterName) + require.NoError(acrd.T(), err, "Error getting cluster ID") + acrd.cluster, err = acrd.client.Management.Cluster.ByID(clusterID) + require.NoError(acrd.T(), err) + + log.Infof("Enabling the feature flag %s", rbacapi.AggregatedRoleTemplatesFeatureFlag) + featureEnabled, err := rbacapi.IsFeatureEnabled(acrd.client, rbacapi.AggregatedRoleTemplatesFeatureFlag) + require.NoError(acrd.T(), err, "Failed to check if feature flag is enabled") + if !featureEnabled { + err := rbacapi.SetAggregatedClusterRoleFeatureFlag(acrd.client, true) + require.NoError(acrd.T(), err, "Failed to enable the feature flag") + } else { + log.Infof("Feature flag %s is already enabled.", rbacapi.AggregatedRoleTemplatesFeatureFlag) + } +} + +func (acrd *AggregatedClusterRolesCleanupTestSuite) acrCreateTestResourcesForCleanup(client *rancher.Client, cluster *management.Cluster) (*v3.Project, []*corev1.Namespace, *management.User, []*appsv1.Deployment, []string, []*corev1.Secret, error) { + log.Info("Creating the required resources for the test.") + createdProject, err := projectapi.CreateProject(client, cluster.ID) + require.NoError(acrd.T(), err, "Failed to create project") + + downstreamContext, err := clusterapi.GetClusterWranglerContext(client, cluster.ID) + require.NoError(acrd.T(), err, "Failed to get downstream cluster context") + + var createdNamespaces []*corev1.Namespace + var createdDeployments []*appsv1.Deployment + var createdSecrets []*corev1.Secret + var podNames []string + + numNamespaces := 2 + for i := 0; i < numNamespaces; i++ { + namespace, err := namespaceapi.CreateNamespaceUsingWrangler(client, cluster.ID, createdProject.Name, nil) + require.NoError(acrd.T(), err, "Failed to create namespace") + createdNamespaces = append(createdNamespaces, namespace) + + createdDeployment, err := deployment.CreateDeployment(client, cluster.ID, namespace.Name, 2, "", "", false, false, false, true) + require.NoError(acrd.T(), err, "Failed to create deployment in namespace %s", namespace.Name) + createdDeployments = append(createdDeployments, createdDeployment) + + podList, err := downstreamContext.Core.Pod().List(namespace.Name, metav1.ListOptions{}) + require.NoError(acrd.T(), err, "Failed to list pods in namespace %s", namespace.Name) + require.Greater(acrd.T(), len(podList.Items), 0, "No pods found in namespace %s", namespace.Name) + podNames = append(podNames, podList.Items[0].Name) + + secretData := map[string][]byte{ + "hello": []byte("world"), + } + createdSecret, err := secrets.CreateSecret(client, cluster.ID, namespace.Name, secretData, corev1.SecretTypeOpaque, nil, nil) + require.NoError(acrd.T(), err, "Failed to create secret in namespace %s", namespace.Name) + createdSecrets = append(createdSecrets, createdSecret) + } + + createdUser, err := users.CreateUserWithRole(client, users.UserConfig(), rbac.StandardUser.String()) + require.NoError(acrd.T(), err, "Failed to create user") + + return createdProject, createdNamespaces, createdUser, createdDeployments, podNames, createdSecrets, nil +} + +func (acrd *AggregatedClusterRolesCleanupTestSuite) TestDeleteRoleTemplateRemovesClusterRoles() { + subSession := acrd.session.NewSession() + defer subSession.Cleanup() + + log.Info("Creating a cluster role template with no inheritance.") + mainRules := rbacapi.PolicyRules["readProjects"] + createdMainRT, err := rbacapi.CreateRoleTemplate(acrd.client, rbacapi.ClusterContext, mainRules, nil, false, false, nil) + require.NoError(acrd.T(), err, "Failed to create main role template") + + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrd.client, clusterapi.LocalCluster, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 4, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrd.client, acrd.cluster.ID, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 2, len(downstreamCRs.Items)) + + log.Infof("Deleting the role template %s.", mainRTName) + err = rbacapi.DeleteRoleTemplate(acrd.client, mainRTName) + require.NoError(acrd.T(), err, "Failed to delete role template") + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrd.client, clusterapi.LocalCluster, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 0, len(localCRs.Items)) + downstreamCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrd.client, acrd.cluster.ID, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 0, len(downstreamCRs.Items)) +} + +func (acrd *AggregatedClusterRolesCleanupTestSuite) TestCrtbDeleteRoleTemplateWithInheritance() { + subSession := acrd.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, _, err := acrd.acrCreateTestResourcesForCleanup(acrd.client, acrd.cluster) + require.NoError(acrd.T(), err) + + log.Info("Creating cluster role templates with cluster management and regular resources.") + childRules := rbacapi.PolicyRules["readProjects"] + mainRules := rbacapi.PolicyRules["readPods"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrd.client, rbacapi.ClusterContext, childRules, nil, false, false, nil) + require.NoError(acrd.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrd.client, rbacapi.ClusterContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrd.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrd.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 7, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrd.client, acrd.cluster.ID, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 4, len(downstreamCRs.Items)) + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrd.client, acrd.cluster.ID, createdUser, mainRTName) + require.NoError(acrd.T(), err, "Failed to assign role to user") + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrd.client, createdUser.ID, 1) + require.NoError(acrd.T(), err, "CRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrd.client, clusterapi.LocalCluster, &crtbs[0], 1, 0) + require.NoError(acrd.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrd.client, acrd.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrd.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "projects", "", "", true, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + + log.Infof("Deleting the role template %s.", mainRTName) + err = rbacapi.DeleteRoleTemplate(acrd.client, mainRTName) + require.NoError(acrd.T(), err, "Failed to delete role template") + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrd.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 4, len(localCRs.Items)) + downstreamCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrd.client, acrd.cluster.ID, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 2, len(downstreamCRs.Items)) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, false, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "projects", "", "", false, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "pods", namespaceName, "", false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + + log.Infof("Deleting the role template %s.", childRTName) + err = rbacapi.DeleteRoleTemplate(acrd.client, childRTName) + require.NoError(acrd.T(), err, "Failed to delete role template") + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrd.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 0, len(localCRs.Items)) + downstreamCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrd.client, acrd.cluster.ID, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 0, len(downstreamCRs.Items)) +} + +func (acrd *AggregatedClusterRolesCleanupTestSuite) TestPrtbDeleteRoleTemplateWithInheritance() { + subSession := acrd.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, _, err := acrd.acrCreateTestResourcesForCleanup(acrd.client, acrd.cluster) + require.NoError(acrd.T(), err) + + log.Info("Creating project role templates with project management and regular resources.") + childRules := rbacapi.PolicyRules["readPrtbs"] + mainRules := rbacapi.PolicyRules["readPods"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrd.client, rbacapi.ProjectContext, childRules, nil, false, false, nil) + require.NoError(acrd.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrd.client, rbacapi.ProjectContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrd.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrd.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 7, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrd.client, acrd.cluster.ID, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 4, len(downstreamCRs.Items)) + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName) + createdPrtb, err := rbacapi.CreateProjectRoleTemplateBinding(acrd.client, createdUser, createdProject, mainRTName) + require.NoError(acrd.T(), err, "Failed to assign role to user") + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrd.client, createdUser.ID, 1) + require.NoError(acrd.T(), err, "PRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtbNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrd.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrd.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrd.client, acrd.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrd.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", true, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + + log.Infof("Deleting the role template %s.", mainRTName) + err = rbacapi.DeleteRoleTemplate(acrd.client, mainRTName) + require.NoError(acrd.T(), err, "Failed to delete role template") + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrd.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 4, len(localCRs.Items)) + downstreamCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrd.client, acrd.cluster.ID, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 2, len(downstreamCRs.Items)) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", false, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "pods", namespaceName, "", false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + + log.Infof("Deleting the role template %s.", childRTName) + err = rbacapi.DeleteRoleTemplate(acrd.client, childRTName) + require.NoError(acrd.T(), err, "Failed to delete role template") + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrd.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 0, len(localCRs.Items)) + downstreamCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrd.client, acrd.cluster.ID, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 0, len(downstreamCRs.Items)) +} + +func (acrd *AggregatedClusterRolesCleanupTestSuite) TestCrtbRemoveUserFromCluster() { + subSession := acrd.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, _, err := acrd.acrCreateTestResourcesForCleanup(acrd.client, acrd.cluster) + require.NoError(acrd.T(), err) + + log.Info("Creating cluster role templates with cluster management and regular resources.") + childRules := rbacapi.PolicyRules["readProjects"] + mainRules := rbacapi.PolicyRules["readPods"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrd.client, rbacapi.ClusterContext, childRules, nil, false, false, nil) + require.NoError(acrd.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrd.client, rbacapi.ClusterContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrd.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrd.client, acrd.cluster.ID, createdUser, mainRTName) + require.NoError(acrd.T(), err, "Failed to assign role to user") + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrd.client, createdUser.ID, 1) + require.NoError(acrd.T(), err, "CRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrd.client, clusterapi.LocalCluster, &crtbs[0], 1, 0) + require.NoError(acrd.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrd.client, acrd.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrd.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "projects", "", "", true, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + + log.Infof("Removing user %s from the downstream cluster.", createdUser.ID) + err = rbacapi.DeleteClusterRoleTemplateBinding(acrd.client, acrd.cluster.ID, crtbs[0].Name) + require.NoError(acrd.T(), err, "Failed to delete role template") + _, err = rbacapi.VerifyClusterRoleTemplateBindingForUser(acrd.client, createdUser.ID, 0) + require.NoError(acrd.T(), err, "CRTB still exists for the user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrd.client, clusterapi.LocalCluster, &crtbs[0], 0, 0) + require.NoError(acrd.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrd.client, acrd.cluster.ID, &crtbs[0], 0, 0) + require.NoError(acrd.T(), err) + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrd.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 7, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrd.client, acrd.cluster.ID, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 4, len(downstreamCRs.Items)) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, false, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "projects", "", "", false, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "pods", namespaceName, "", false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, false, false)) +} + +func (acrd *AggregatedClusterRolesCleanupTestSuite) TestPrtbRemoveUserFromProject() { + subSession := acrd.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, _, err := acrd.acrCreateTestResourcesForCleanup(acrd.client, acrd.cluster) + require.NoError(acrd.T(), err) + + log.Info("Creating project role templates with project management and regular resources.") + childRules := rbacapi.PolicyRules["readPrtbs"] + mainRules := rbacapi.PolicyRules["readPods"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrd.client, rbacapi.ProjectContext, childRules, nil, false, false, nil) + require.NoError(acrd.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrd.client, rbacapi.ProjectContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrd.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName) + createdPrtb, err := rbacapi.CreateProjectRoleTemplateBinding(acrd.client, createdUser, createdProject, mainRTName) + require.NoError(acrd.T(), err, "Failed to assign role to user") + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrd.client, createdUser.ID, 1) + require.NoError(acrd.T(), err, "PRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtbNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrd.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrd.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrd.client, acrd.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrd.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", true, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + + log.Infof("Removing user %s from the project %s in the downstream cluster.", createdUser.ID, createdProject.Name) + err = rbacapi.DeleteProjectRoleTemplateBinding(acrd.client, createdPrtb.Namespace, createdPrtb.Name) + require.NoError(acrd.T(), err, "Failed to delete project role template binding") + _, err = rbacapi.VerifyProjectRoleTemplateBindingForUser(acrd.client, createdUser.ID, 0) + require.NoError(acrd.T(), err, "PRTB still exists for the user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForPrtb(acrd.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 0, 0) + require.NoError(acrd.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrd.client, acrd.cluster.ID, &prtbs[0], createdNamespaces, 0, 0) + require.NoError(acrd.T(), err) + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrd.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 7, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrd.client, acrd.cluster.ID, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 4, len(downstreamCRs.Items)) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", false, true)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "list", "pods", namespaceName, "", false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrd.T(), rbacapi.VerifyUserPermission(acrd.client, acrd.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, false, false)) +} + +func (acrd *AggregatedClusterRolesCleanupTestSuite) TestCrtbUserDeletionCleansUpAllBindings() { + subSession := acrd.session.NewSession() + defer subSession.Cleanup() + + _, _, createdUser, _, _, _, err := acrd.acrCreateTestResourcesForCleanup(acrd.client, acrd.cluster) + require.NoError(acrd.T(), err) + + log.Info("Creating cluster role templates with cluster management and regular resources.") + childRules := rbacapi.PolicyRules["readProjects"] + mainRules := rbacapi.PolicyRules["readPods"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrd.client, rbacapi.ClusterContext, childRules, nil, false, false, nil) + require.NoError(acrd.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrd.client, rbacapi.ClusterContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrd.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrd.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 7, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrd.client, acrd.cluster.ID, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 4, len(downstreamCRs.Items)) + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrd.client, acrd.cluster.ID, createdUser, mainRTName) + require.NoError(acrd.T(), err, "Failed to assign role to user") + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrd.client, createdUser.ID, 1) + require.NoError(acrd.T(), err, "CRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrd.client, clusterapi.LocalCluster, &crtbs[0], 1, 0) + require.NoError(acrd.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrd.client, acrd.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrd.T(), err) + + log.Infof("Deleting user %s", createdUser.ID) + err = acrd.client.WranglerContext.Mgmt.User().Delete(createdUser.ID, &metav1.DeleteOptions{}) + require.NoError(acrd.T(), err, "Failed to delete user") + + log.Infof("Verifying that the cluster role template binding for user %s is automatically deleted.", createdUser.Username) + _, err = rbacapi.VerifyClusterRoleTemplateBindingForUser(acrd.client, createdUser.ID, 0) + require.NoError(acrd.T(), err, "CRTB still exists for the deleted user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + require.NoError(acrd.T(), rbacapi.VerifyBindingsForCrtb(acrd.client, clusterapi.LocalCluster, &crtbs[0], 0, 0)) + require.NoError(acrd.T(), rbacapi.VerifyBindingsForCrtb(acrd.client, acrd.cluster.ID, &crtbs[0], 0, 0)) + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrd.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 7, len(localCRs.Items)) + downstreamCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrd.client, acrd.cluster.ID, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 4, len(downstreamCRs.Items)) +} + +func (acrd *AggregatedClusterRolesCleanupTestSuite) TestPrtbUserDeletionCleansUpAllBindings() { + subSession := acrd.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, _, _, _, err := acrd.acrCreateTestResourcesForCleanup(acrd.client, acrd.cluster) + require.NoError(acrd.T(), err) + + log.Info("Creating project role templates with project management and regular resources.") + childRules := rbacapi.PolicyRules["readPrtbs"] + mainRules := rbacapi.PolicyRules["readPods"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrd.client, rbacapi.ProjectContext, childRules, nil, false, false, nil) + require.NoError(acrd.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrd.client, rbacapi.ProjectContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrd.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrd.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 7, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrd.client, acrd.cluster.ID, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 4, len(downstreamCRs.Items)) + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName) + _, err = rbacapi.CreateProjectRoleTemplateBinding(acrd.client, createdUser, createdProject, mainRTName) + require.NoError(acrd.T(), err, "Failed to assign role to user") + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrd.client, createdUser.ID, 1) + require.NoError(acrd.T(), err, "PRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtbNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrd.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrd.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrd.client, acrd.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrd.T(), err) + + log.Infof("Deleting user %s", createdUser.ID) + err = acrd.client.WranglerContext.Mgmt.User().Delete(createdUser.ID, &metav1.DeleteOptions{}) + require.NoError(acrd.T(), err, "Failed to delete user") + + log.Infof("Verifying that the project role template binding for user %s is automatically deleted.", createdUser.Username) + _, err = rbacapi.VerifyProjectRoleTemplateBindingForUser(acrd.client, createdUser.ID, 0) + require.NoError(acrd.T(), err, "PRTB still exists for the deleted user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForPrtb(acrd.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 0, 0) + require.NoError(acrd.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrd.client, acrd.cluster.ID, &prtbs[0], createdNamespaces, 0, 0) + require.NoError(acrd.T(), err) + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrd.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 7, len(localCRs.Items)) + downstreamCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrd.client, acrd.cluster.ID, childRTName, mainRTName) + require.NoError(acrd.T(), err) + require.Equal(acrd.T(), 4, len(downstreamCRs.Items)) +} + +func TestAggregatedClusterRolesCleanupTestSuite(t *testing.T) { + suite.Run(t, new(AggregatedClusterRolesCleanupTestSuite)) +} diff --git a/validation/rbac/aggregatedclusterroles/aggregated_cluster_roles_crtb_test.go b/validation/rbac/aggregatedclusterroles/aggregated_cluster_roles_crtb_test.go new file mode 100644 index 000000000..62feba188 --- /dev/null +++ b/validation/rbac/aggregatedclusterroles/aggregated_cluster_roles_crtb_test.go @@ -0,0 +1,988 @@ +//go:build (validation || infra.any || cluster.any || extended) && !sanity && !stress && !2.9 && !2.10 && !2.11 && !2.12 && !2.13 + +package aggregatedclusterroles + +import ( + "testing" + + v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3" + "github.com/rancher/shepherd/clients/rancher" + management "github.com/rancher/shepherd/clients/rancher/generated/management/v3" + "github.com/rancher/shepherd/extensions/clusters" + "github.com/rancher/shepherd/extensions/users" + "github.com/rancher/shepherd/pkg/session" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" + namespaceapi "github.com/rancher/tests/actions/kubeapi/namespaces" + projectapi "github.com/rancher/tests/actions/kubeapi/projects" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" + "github.com/rancher/tests/actions/rbac" + "github.com/rancher/tests/actions/secrets" + "github.com/rancher/tests/actions/workloads/deployment" + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type AggregatedClusterRolesCrtbTestSuite struct { + suite.Suite + client *rancher.Client + session *session.Session + cluster *management.Cluster +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) TearDownSuite() { + acrc.session.Cleanup() + + log.Infof("Disabling the feature flag %s", rbacapi.AggregatedRoleTemplatesFeatureFlag) + err := rbacapi.SetAggregatedClusterRoleFeatureFlag(acrc.client, false) + if err != nil { + log.Warnf("Failed to disable the feature flag during teardown: %v", err) + } +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) SetupSuite() { + acrc.session = session.NewSession() + + client, err := rancher.NewClient("", acrc.session) + require.NoError(acrc.T(), err) + acrc.client = client + + log.Info("Getting cluster name from the config file and append cluster details to the test suite struct") + clusterName := client.RancherConfig.ClusterName + require.NotEmptyf(acrc.T(), clusterName, "Cluster name should be set in the config file") + clusterID, err := clusters.GetClusterIDByName(acrc.client, clusterName) + require.NoError(acrc.T(), err, "Error getting cluster ID") + acrc.cluster, err = acrc.client.Management.Cluster.ByID(clusterID) + require.NoError(acrc.T(), err) + + log.Infof("Enabling the feature flag %s", rbacapi.AggregatedRoleTemplatesFeatureFlag) + featureEnabled, err := rbacapi.IsFeatureEnabled(acrc.client, rbacapi.AggregatedRoleTemplatesFeatureFlag) + require.NoError(acrc.T(), err, "Failed to check if feature flag is enabled") + if !featureEnabled { + err := rbacapi.SetAggregatedClusterRoleFeatureFlag(acrc.client, true) + require.NoError(acrc.T(), err, "Failed to enable the feature flag") + } else { + log.Infof("Feature flag %s is already enabled.", rbacapi.AggregatedRoleTemplatesFeatureFlag) + } +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) acrCreateTestResourcesForCrtb(client *rancher.Client, cluster *management.Cluster) (*v3.Project, []*corev1.Namespace, *management.User, []*appsv1.Deployment, []string, []*corev1.Secret, error) { + log.Info("Creating the required resources for the test.") + createdProject, err := projectapi.CreateProject(client, cluster.ID) + require.NoError(acrc.T(), err, "Failed to create project") + + downstreamContext, err := clusterapi.GetClusterWranglerContext(client, cluster.ID) + require.NoError(acrc.T(), err, "Failed to get downstream cluster context") + + var createdNamespaces []*corev1.Namespace + var createdDeployments []*appsv1.Deployment + var createdSecrets []*corev1.Secret + var podNames []string + + numNamespaces := 2 + for i := 0; i < numNamespaces; i++ { + namespace, err := namespaceapi.CreateNamespaceUsingWrangler(client, cluster.ID, createdProject.Name, nil) + require.NoError(acrc.T(), err, "Failed to create namespace") + createdNamespaces = append(createdNamespaces, namespace) + + createdDeployment, err := deployment.CreateDeployment(client, cluster.ID, namespace.Name, 2, "", "", false, false, false, true) + require.NoError(acrc.T(), err, "Failed to create deployment in namespace %s", namespace.Name) + createdDeployments = append(createdDeployments, createdDeployment) + + podList, err := downstreamContext.Core.Pod().List(namespace.Name, metav1.ListOptions{}) + require.NoError(acrc.T(), err, "Failed to list pods in namespace %s", namespace.Name) + require.Greater(acrc.T(), len(podList.Items), 0, "No pods found in namespace %s", namespace.Name) + podNames = append(podNames, podList.Items[0].Name) + + secretData := map[string][]byte{ + "hello": []byte("world"), + } + createdSecret, err := secrets.CreateSecret(client, cluster.ID, namespace.Name, secretData, corev1.SecretTypeOpaque, nil, nil) + require.NoError(acrc.T(), err, "Failed to create secret in namespace %s", namespace.Name) + createdSecrets = append(createdSecrets, createdSecret) + } + + createdUser, err := users.CreateUserWithRole(client, users.UserConfig(), rbac.StandardUser.String()) + require.NoError(acrc.T(), err, "Failed to create user") + + return createdProject, createdNamespaces, createdUser, createdDeployments, podNames, createdSecrets, nil +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) TestCrtbInheritanceWithClusterMgmtResources() { + subSession := acrc.session.NewSession() + defer subSession.Cleanup() + + createdProject, _, createdUser, _, _, _, err := acrc.acrCreateTestResourcesForCrtb(acrc.client, acrc.cluster) + require.NoError(acrc.T(), err) + + log.Info("Creating cluster role templates with cluster management plane resources.") + childRules := rbacapi.PolicyRules["readProjects"] + mainRules := rbacapi.PolicyRules["createProjects"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 8, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, acrc.cluster.ID, childRTName, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 4, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyClusterMgmtACR(acrc.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for cluster-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, mainRTName, []string{childRTName}) + require.NoError(acrc.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrc.client, acrc.cluster.ID, createdUser, mainRTName) + require.NoError(acrc.T(), err, "Failed to assign role to user") + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrc.client, createdUser.ID, 1) + require.NoError(acrc.T(), err, "CRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[0], 1, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrc.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "create", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "update", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "patch", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) TestCrtbInheritanceWithRegularResources() { + subSession := acrc.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, _, err := acrc.acrCreateTestResourcesForCrtb(acrc.client, acrc.cluster) + require.NoError(acrc.T(), err) + + log.Info("Creating cluster role templates with regular resources.") + childRules := rbacapi.PolicyRules["readDeployments"] + mainRules := rbacapi.PolicyRules["readPods"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 4, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, acrc.cluster.ID, childRTName, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 4, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, mainRTName, []string{childRTName}) + require.NoError(acrc.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrc.client, acrc.cluster.ID, createdUser, mainRTName) + require.NoError(acrc.T(), err, "Failed to assign role to user") + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrc.client, createdUser.ID, 1) + require.NoError(acrc.T(), err, "CRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[0], 0, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrc.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "deployments", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, false, true)) +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) TestCrtbInheritanceWithMgmtAndRegularResources() { + subSession := acrc.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, _, err := acrc.acrCreateTestResourcesForCrtb(acrc.client, acrc.cluster) + require.NoError(acrc.T(), err) + + log.Info("Creating cluster role templates with cluster management and regular resources.") + childRules := rbacapi.PolicyRules["readProjects"] + mainRules := rbacapi.PolicyRules["readPods"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 7, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, acrc.cluster.ID, childRTName, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 4, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyClusterMgmtACR(acrc.client, clusterapi.LocalCluster, childRTName, nil) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for cluster-mgmt resources") + err = rbacapi.VerifyClusterMgmtACR(acrc.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for cluster-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, mainRTName, []string{childRTName}) + require.NoError(acrc.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrc.client, acrc.cluster.ID, createdUser, mainRTName) + require.NoError(acrc.T(), err, "Failed to assign role to user") + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrc.client, createdUser.ID, 1) + require.NoError(acrc.T(), err, "CRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[0], 1, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrc.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, false, false)) +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) TestCrtbInheritanceWithMultipleRules() { + subSession := acrc.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, createdSecret, err := acrc.acrCreateTestResourcesForCrtb(acrc.client, acrc.cluster) + require.NoError(acrc.T(), err) + + log.Info("Creating cluster role templates with multiple rules.") + chidRules := []rbacv1.PolicyRule{ + { + Verbs: []string{"get", "list"}, + Resources: []string{rbacapi.DeploymentsResource}, + APIGroups: []string{rbacapi.AppsAPIGroup}, + }, + { + Verbs: []string{"get", "list"}, + Resources: []string{rbacapi.SecretsResource}, + APIGroups: []string{""}, + }, + } + mainRules := []rbacv1.PolicyRule{ + { + Verbs: []string{"get", "list"}, + Resources: []string{rbacapi.PodsResource}, + APIGroups: []string{""}, + }, + { + Verbs: []string{"create", "get", "update"}, + Resources: []string{rbacapi.ProjectResource}, + APIGroups: []string{rbacapi.ManagementAPIGroup}, + }, + } + createdChildRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, chidRules, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template") + + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 9, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, acrc.cluster.ID, childRTName, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 4, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyClusterMgmtACR(acrc.client, clusterapi.LocalCluster, mainRTName, nil) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for cluster-mgmt resources") + err = rbacapi.VerifyProjectMgmtACR(acrc.client, clusterapi.LocalCluster, childRTName, nil) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, mainRTName, []string{childRTName}) + require.NoError(acrc.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrc.client, acrc.cluster.ID, createdUser, mainRTName) + require.NoError(acrc.T(), err, "Failed to assign role to user") + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrc.client, createdUser.ID, 1) + require.NoError(acrc.T(), err, "CRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[0], 2, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrc.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "deployments", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "secrets", namespaceName, createdSecret[0].Name, true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "secrets", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "create", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "update", "projects", "", createdProject.Name, true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "patch", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "projects", "", "", false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "secrets", namespaceName, createdSecret[0].Name, false, false)) +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) TestCrtbWithNoInheritance() { + subSession := acrc.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, _, _, _, err := acrc.acrCreateTestResourcesForCrtb(acrc.client, acrc.cluster) + require.NoError(acrc.T(), err) + + log.Info("Creating a cluster role template with no inheritance.") + mainRules := rbacapi.PolicyRules["readProjects"] + createdMainRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, mainRules, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create main role template") + + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, clusterapi.LocalCluster, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 4, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, acrc.cluster.ID, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 2, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, mainRTName, nil) + require.NoError(acrc.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyClusterMgmtACR(acrc.client, clusterapi.LocalCluster, mainRTName, nil) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for cluster-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, mainRTName, nil) + require.NoError(acrc.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrc.client, acrc.cluster.ID, createdUser, mainRTName) + require.NoError(acrc.T(), err, "Failed to assign role to user") + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrc.client, createdUser.ID, 1) + require.NoError(acrc.T(), err, "CRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[0], 1, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrc.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "create", "projects", "", "", false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "update", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "patch", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "pods", createdNamespaces[0].Name, "", false, false)) +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) TestCrtbInheritedRulesOnly() { + subSession := acrc.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, _, _, _, err := acrc.acrCreateTestResourcesForCrtb(acrc.client, acrc.cluster) + require.NoError(acrc.T(), err) + + log.Info("Creating cluster role templates.") + childRules := rbacapi.PolicyRules["readProjects"] + mainRules := []rbacv1.PolicyRule{} + createdChildRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 7, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, acrc.cluster.ID, childRTName, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 4, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyClusterMgmtACR(acrc.client, clusterapi.LocalCluster, childRTName, nil) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for cluster-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, mainRTName, []string{childRTName}) + require.NoError(acrc.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrc.client, acrc.cluster.ID, createdUser, mainRTName) + require.NoError(acrc.T(), err, "Failed to assign role to user") + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrc.client, createdUser.ID, 1) + require.NoError(acrc.T(), err, "CRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[0], 1, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrc.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "create", "projects", "", "", false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "update", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "patch", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "pods", createdNamespaces[0].Name, "", false, false)) +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) TestCrtbInheritanceWithTwoCrtbs() { + subSession := acrc.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, _, err := acrc.acrCreateTestResourcesForCrtb(acrc.client, acrc.cluster) + require.NoError(acrc.T(), err) + + log.Info("Creating cluster role templates.") + childRules1 := rbacapi.PolicyRules["readDeployments"] + childRules2 := rbacapi.PolicyRules["readPods"] + mainRules1 := rbacapi.PolicyRules["createProjects"] + mainRules2 := rbacapi.PolicyRules["readProjects"] + + createdChildRT1, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules1, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template") + createdChildRT2, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules2, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template") + + inheritedChildRoleTemplate1 := []*v3.RoleTemplate{createdChildRT1} + inheritedChildRoleTemplate2 := []*v3.RoleTemplate{createdChildRT2} + + createdMainRT1, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, mainRules1, inheritedChildRoleTemplate1, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create main role template") + createdMainRT2, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, mainRules2, inheritedChildRoleTemplate2, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create main role template") + + childRTName1 := createdChildRT1.Name + mainRTName1 := createdMainRT1.Name + childRTName2 := createdChildRT2.Name + mainRTName2 := createdMainRT2.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, clusterapi.LocalCluster, childRTName1, mainRTName1, childRTName2, mainRTName2) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 12, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, acrc.cluster.ID, childRTName1, mainRTName1, childRTName2, mainRTName2) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 8, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, mainRTName1, []string{childRTName1}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, mainRTName2, []string{childRTName2}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyClusterMgmtACR(acrc.client, clusterapi.LocalCluster, mainRTName1, nil) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for cluster-mgmt resources") + err = rbacapi.VerifyClusterMgmtACR(acrc.client, clusterapi.LocalCluster, mainRTName2, nil) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for cluster-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, mainRTName1, []string{childRTName1}) + require.NoError(acrc.T(), err, "Failed to fetch downstream ACR") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, mainRTName2, []string{childRTName2}) + require.NoError(acrc.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName1) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrc.client, acrc.cluster.ID, createdUser, mainRTName1) + require.NoError(acrc.T(), err, "Failed to assign role to user") + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName2) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrc.client, acrc.cluster.ID, createdUser, mainRTName2) + require.NoError(acrc.T(), err, "Failed to assign role to user") + + log.Infof("Verifying cluster role template bindings created for user %s", createdUser.Username) + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrc.client, createdUser.ID, 2) + require.NoError(acrc.T(), err, "CRTBs not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[0], 1, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[1], 1, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[1], 0, 1) + require.NoError(acrc.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "create", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "update", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "patch", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "deployments", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "deployments", namespaceName, createdDeployment[0].Name, false, false)) +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) TestCrtbNestedInheritance() { + subSession := acrc.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, _, podNames, createdSecret, err := acrc.acrCreateTestResourcesForCrtb(acrc.client, acrc.cluster) + require.NoError(acrc.T(), err) + + log.Info("Creating nested cluster role templates.") + childRules1 := rbacapi.PolicyRules["createProjects"] + childRules2 := rbacapi.PolicyRules["readSecrets"] + childRules3 := rbacapi.PolicyRules["readProjects"] + mainRules1 := rbacapi.PolicyRules["readPods"] + + createdChildRT1, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules1, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template") + + inheritedChildRoleTemplate1 := []*v3.RoleTemplate{createdChildRT1} + createdChildRT2, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules2, inheritedChildRoleTemplate1, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template") + + inheritedChildRoleTemplate2 := []*v3.RoleTemplate{createdChildRT2} + createdChildRT3, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules3, inheritedChildRoleTemplate2, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template") + + inheritedChildRoleTemplate3 := []*v3.RoleTemplate{createdChildRT3} + createdMainRT1, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, mainRules1, inheritedChildRoleTemplate3, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create main role template") + + childRTName1 := createdChildRT1.Name + childRTName2 := createdChildRT2.Name + childRTName3 := createdChildRT3.Name + mainRTName1 := createdMainRT1.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, clusterapi.LocalCluster, childRTName1, childRTName2, childRTName3, mainRTName1) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 18, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, acrc.cluster.ID, childRTName1, childRTName2, childRTName3, mainRTName1) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 8, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyClusterMgmtACR(acrc.client, clusterapi.LocalCluster, mainRTName1, []string{childRTName1, childRTName3}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for cluster-mgmt resources") + err = rbacapi.VerifyProjectMgmtACR(acrc.client, clusterapi.LocalCluster, mainRTName1, []string{childRTName2}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, mainRTName1, []string{childRTName1, childRTName2, childRTName3}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for main role") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, childRTName3, []string{childRTName1, childRTName2}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for child role 3") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, childRTName2, []string{childRTName1}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for child role 2") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, mainRTName1, []string{childRTName1, childRTName2, childRTName3}) + require.NoError(acrc.T(), err, "Failed to fetch downstream ACR for main role") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, childRTName3, []string{childRTName1, childRTName2}) + require.NoError(acrc.T(), err, "Failed to fetch downstream ACR for child role 3") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, childRTName2, []string{childRTName1}) + require.NoError(acrc.T(), err, "Failed to fetch downstream ACR for child role 2") + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName1) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrc.client, acrc.cluster.ID, createdUser, mainRTName1) + require.NoError(acrc.T(), err, "Failed to assign role to user") + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrc.client, createdUser.ID, 1) + require.NoError(acrc.T(), err, "CRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[0], 2, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrc.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "secrets", namespaceName, createdSecret[0].Name, true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "secrets", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "create", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "update", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "patch", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) TestCrtbMultipleLevelsOfInheritance() { + subSession := acrc.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, createdSecret, err := acrc.acrCreateTestResourcesForCrtb(acrc.client, acrc.cluster) + require.NoError(acrc.T(), err) + + log.Info("Creating multiple levels of nested cluster role templates.") + childRules11 := rbacapi.PolicyRules["readDeployments"] + childRules12 := rbacapi.PolicyRules["readProjects"] + parentRules1 := rbacapi.PolicyRules["readNamespaces"] + childRules21 := rbacapi.PolicyRules["readPods"] + parentRules2 := rbacapi.PolicyRules["readSecrets"] + mainRules1 := rbacapi.PolicyRules["createProjects"] + + createdChildRT11, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules11, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template 11") + + createdChildRT12, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules12, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template 12") + + inheritedParentRoleTemplate1 := []*v3.RoleTemplate{createdChildRT11, createdChildRT12} + createdParentRT1, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, parentRules1, inheritedParentRoleTemplate1, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create parent role template 1") + + createdChildRT21, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules21, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template 21") + + inheritedParentRoleTemplate2 := []*v3.RoleTemplate{createdChildRT21} + createdParentRT2, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, parentRules2, inheritedParentRoleTemplate2, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create parent role template 2") + + inheritedMainRoleTemplate1 := []*v3.RoleTemplate{createdParentRT1, createdParentRT2} + createdMainRT1, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, mainRules1, inheritedMainRoleTemplate1, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create main role template 1") + + childRTName11 := createdChildRT11.Name + childRTName12 := createdChildRT12.Name + parentRTName1 := createdParentRT1.Name + childRTName21 := createdChildRT21.Name + parentRTName2 := createdParentRT2.Name + mainRTName1 := createdMainRT1.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, clusterapi.LocalCluster, childRTName11, childRTName12, parentRTName1, childRTName21, parentRTName2, mainRTName1) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 20, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, acrc.cluster.ID, childRTName11, childRTName12, parentRTName1, childRTName21, parentRTName2, mainRTName1) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 12, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyClusterMgmtACR(acrc.client, clusterapi.LocalCluster, mainRTName1, []string{childRTName12}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for cluster-mgmt resources") + err = rbacapi.VerifyProjectMgmtACR(acrc.client, clusterapi.LocalCluster, parentRTName2, nil) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, mainRTName1, []string{childRTName11, childRTName12, parentRTName1, childRTName21, parentRTName2}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for main role") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, mainRTName1, []string{childRTName11, childRTName12, parentRTName1, childRTName21, parentRTName2}) + require.NoError(acrc.T(), err, "Failed to fetch downstream ACR for main role") + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName1) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrc.client, acrc.cluster.ID, createdUser, mainRTName1) + require.NoError(acrc.T(), err, "Failed to assign role to user") + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrc.client, createdUser.ID, 1) + require.NoError(acrc.T(), err, "CRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[0], 2, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrc.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "deployments", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "namespaces", "", namespaceName, true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "namespaces", "", "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "secrets", namespaceName, createdSecret[0].Name, true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "secrets", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "create", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "update", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "patch", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) TestCrtbUpdateRoleTemplateToAddInheritance() { + subSession := acrc.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, _, podNames, _, err := acrc.acrCreateTestResourcesForCrtb(acrc.client, acrc.cluster) + require.NoError(acrc.T(), err) + + log.Info("Creating a cluster role template with no inheritance.") + mainRules := rbacapi.PolicyRules["readProjects"] + createdMainRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, mainRules, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create main role template") + + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, clusterapi.LocalCluster, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 4, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, acrc.cluster.ID, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 2, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, mainRTName, nil) + require.NoError(acrc.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyClusterMgmtACR(acrc.client, clusterapi.LocalCluster, mainRTName, nil) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for cluster-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, mainRTName, nil) + require.NoError(acrc.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrc.client, acrc.cluster.ID, createdUser, mainRTName) + require.NoError(acrc.T(), err, "Failed to assign role to user") + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrc.client, createdUser.ID, 1) + require.NoError(acrc.T(), err, "CRTB not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[0], 1, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrc.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "create", "projects", "", "", false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "update", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "patch", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "pods", namespaceName, "", false, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], false, false)) + + log.Info("Creating a new cluster role template.") + childRules := rbacapi.PolicyRules["readPods"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template") + + childRTName := createdChildRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrc.client, clusterapi.LocalCluster, childRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 2, len(localCRs.Items)) + downstreamCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrc.client, acrc.cluster.ID, childRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 2, len(downstreamCRs.Items)) + + log.Info("Updating the main role template to add inheritance.") + updatedMainRT, err := rbacapi.UpdateRoleTemplateInheritance(acrc.client, mainRTName, []*v3.RoleTemplate{createdChildRT}) + require.NoError(acrc.T(), err, "Failed to update role template inheritance") + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyClusterMgmtACR(acrc.client, clusterapi.LocalCluster, updatedMainRT.Name, []string{}) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, updatedMainRT.Name, []string{childRTName}) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, updatedMainRT.Name, []string{childRTName}) + require.NoError(acrc.T(), err) + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[0], 1, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrc.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "create", "projects", "", "", false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "update", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "patch", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) TestCrtbUpdateRoleTemplateToRemoveInheritance() { + subSession := acrc.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, _, err := acrc.acrCreateTestResourcesForCrtb(acrc.client, acrc.cluster) + require.NoError(acrc.T(), err) + + log.Info("Creating cluster role templates with cluster management and regular resources.") + childRules := rbacapi.PolicyRules["readPods"] + mainRules := rbacapi.PolicyRules["readProjects"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 6, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrc.client, acrc.cluster.ID, childRTName, mainRTName) + require.NoError(acrc.T(), err) + require.Equal(acrc.T(), 4, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrc.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyClusterMgmtACR(acrc.client, clusterapi.LocalCluster, mainRTName, nil) + require.NoError(acrc.T(), err, "Failed to fetch local ACR for cluster-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, mainRTName, []string{childRTName}) + require.NoError(acrc.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to the downstream cluster with role %s", createdUser.Username, mainRTName) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrc.client, acrc.cluster.ID, createdUser, mainRTName) + require.NoError(acrc.T(), err, "Failed to assign role to user") + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrc.client, createdUser.ID, 1) + require.NoError(acrc.T(), err, "CRTB not found for user") + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[0], 1, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrc.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + + log.Info("Removing inheritance from the main role template.") + updatedMainRT, err := rbacapi.UpdateRoleTemplateInheritance(acrc.client, mainRTName, []*v3.RoleTemplate{}) + require.NoError(acrc.T(), err, "Failed to update role template inheritance") + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyClusterMgmtACR(acrc.client, clusterapi.LocalCluster, updatedMainRT.Name, []string{}) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, clusterapi.LocalCluster, updatedMainRT.Name, []string{}) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyMainACRContainsAllRules(acrc.client, acrc.cluster.ID, updatedMainRT.Name, []string{}) + require.NoError(acrc.T(), err) + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[0], 1, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrc.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "create", "projects", "", "", false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "update", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "patch", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "pods", namespaceName, "", false, false)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], false, false)) +} + +func (acrc *AggregatedClusterRolesCrtbTestSuite) TestCrtbVerifyCrossClusterAccessRestriction() { + subSession := acrc.session.NewSession() + defer subSession.Cleanup() + + createdProject, _, createdUser, _, _, _, err := acrc.acrCreateTestResourcesForCrtb(acrc.client, acrc.cluster) + require.NoError(acrc.T(), err) + createdProject2, err := projectapi.CreateProject(acrc.client, clusterapi.LocalCluster) + require.NoError(acrc.T(), err, "Failed to create project") + + log.Info("Creating cluster role templates with cluster management plane resources.") + childRules := rbacapi.PolicyRules["readProjects"] + mainRules := rbacapi.PolicyRules["createProjects"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, childRules, nil, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrc.client, rbacapi.ClusterContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrc.T(), err, "Failed to create main role template") + + mainRTName := createdMainRT.Name + log.Infof("Adding user %s to the downstream cluster %s with role %s", createdUser.Username, acrc.cluster.ID, mainRTName) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrc.client, acrc.cluster.ID, createdUser, mainRTName) + require.NoError(acrc.T(), err, "Failed to assign role to user") + crtbs, err := rbacapi.VerifyClusterRoleTemplateBindingForUser(acrc.client, createdUser.ID, 1) + require.NoError(acrc.T(), err, "CRTB not found for user") + + log.Infof("Adding user %s to the local cluster with role %s", createdUser.Username, rbac.ManageNodes.String()) + _, err = rbacapi.CreateClusterRoleTemplateBinding(acrc.client, clusterapi.LocalCluster, createdUser, rbac.ManageNodes.String()) + require.NoError(acrc.T(), err, "Failed to assign role to user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, clusterapi.LocalCluster, &crtbs[0], 1, 0) + require.NoError(acrc.T(), err) + err = rbacapi.VerifyBindingsForCrtb(acrc.client, acrc.cluster.ID, &crtbs[0], 0, 1) + require.NoError(acrc.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "list", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "create", "projects", "", "", true, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "update", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "patch", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, acrc.cluster.ID, createdUser, "delete", "projects", "", createdProject.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, clusterapi.LocalCluster, createdUser, "get", "projects", "", createdProject2.Name, false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, clusterapi.LocalCluster, createdUser, "list", "projects", "", "", false, true)) + require.NoError(acrc.T(), rbacapi.VerifyUserPermission(acrc.client, clusterapi.LocalCluster, createdUser, "create", "projects", "", "", false, true)) +} + +func TestAggregatedClusterRolesCrtbTestSuite(t *testing.T) { + suite.Run(t, new(AggregatedClusterRolesCrtbTestSuite)) +} diff --git a/validation/rbac/aggregatedclusterroles/aggregated_cluster_roles_prtb_test.go b/validation/rbac/aggregatedclusterroles/aggregated_cluster_roles_prtb_test.go new file mode 100644 index 000000000..0c56c2690 --- /dev/null +++ b/validation/rbac/aggregatedclusterroles/aggregated_cluster_roles_prtb_test.go @@ -0,0 +1,1059 @@ +//go:build (validation || infra.any || cluster.any || extended) && !sanity && !stress && !2.9 && !2.10 && !2.11 && !2.12 && !2.13 + +package aggregatedclusterroles + +import ( + "testing" + + v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3" + "github.com/rancher/shepherd/clients/rancher" + management "github.com/rancher/shepherd/clients/rancher/generated/management/v3" + "github.com/rancher/shepherd/extensions/clusters" + "github.com/rancher/shepherd/extensions/users" + "github.com/rancher/shepherd/pkg/session" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" + namespaceapi "github.com/rancher/tests/actions/kubeapi/namespaces" + projectapi "github.com/rancher/tests/actions/kubeapi/projects" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" + "github.com/rancher/tests/actions/rbac" + "github.com/rancher/tests/actions/secrets" + "github.com/rancher/tests/actions/workloads/deployment" + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type AggregatedClusterRolesPrtbTestSuite struct { + suite.Suite + client *rancher.Client + session *session.Session + cluster *management.Cluster +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) TearDownSuite() { + acrp.session.Cleanup() + + log.Infof("Disabling the feature flag %s", rbacapi.AggregatedRoleTemplatesFeatureFlag) + err := rbacapi.SetAggregatedClusterRoleFeatureFlag(acrp.client, false) + if err != nil { + log.Warnf("Failed to disable the feature flag during teardown: %v", err) + } +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) SetupSuite() { + acrp.session = session.NewSession() + + client, err := rancher.NewClient("", acrp.session) + require.NoError(acrp.T(), err) + acrp.client = client + + log.Info("Getting cluster name from the config file and append cluster details to the test suite struct.") + clusterName := client.RancherConfig.ClusterName + require.NotEmptyf(acrp.T(), clusterName, "Cluster name should be set in the config file") + clusterID, err := clusters.GetClusterIDByName(acrp.client, clusterName) + require.NoError(acrp.T(), err, "Error getting cluster ID") + acrp.cluster, err = acrp.client.Management.Cluster.ByID(clusterID) + require.NoError(acrp.T(), err) + + log.Infof("Enabling the feature flag %s", rbacapi.AggregatedRoleTemplatesFeatureFlag) + featureEnabled, err := rbacapi.IsFeatureEnabled(acrp.client, rbacapi.AggregatedRoleTemplatesFeatureFlag) + require.NoError(acrp.T(), err, "Failed to check if feature flag is enabled") + if !featureEnabled { + err := rbacapi.SetAggregatedClusterRoleFeatureFlag(acrp.client, true) + require.NoError(acrp.T(), err, "Failed to enable the feature flag") + } else { + log.Infof("Feature flag %s is already enabled.", rbacapi.AggregatedRoleTemplatesFeatureFlag) + } +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) acrCreateTestResourcesForPrtb(client *rancher.Client, cluster *management.Cluster) (*v3.Project, []*corev1.Namespace, *management.User, []*appsv1.Deployment, []string, []*corev1.Secret, error) { + log.Info("Creating the required resources for the test.") + createdProject, err := projectapi.CreateProject(client, cluster.ID) + require.NoError(acrp.T(), err, "Failed to create project") + + downstreamContext, err := clusterapi.GetClusterWranglerContext(client, cluster.ID) + require.NoError(acrp.T(), err, "Failed to get downstream cluster context") + + var createdNamespaces []*corev1.Namespace + var createdDeployments []*appsv1.Deployment + var createdSecrets []*corev1.Secret + var podNames []string + + numNamespaces := 2 + for i := 0; i < numNamespaces; i++ { + namespace, err := namespaceapi.CreateNamespaceUsingWrangler(client, cluster.ID, createdProject.Name, nil) + require.NoError(acrp.T(), err, "Failed to create namespace") + createdNamespaces = append(createdNamespaces, namespace) + + createdDeployment, err := deployment.CreateDeployment(client, cluster.ID, namespace.Name, 2, "", "", false, false, false, true) + require.NoError(acrp.T(), err, "Failed to create deployment in namespace %s", namespace.Name) + createdDeployments = append(createdDeployments, createdDeployment) + + podList, err := downstreamContext.Core.Pod().List(namespace.Name, metav1.ListOptions{}) + require.NoError(acrp.T(), err, "Failed to list pods in namespace %s", namespace.Name) + require.Greater(acrp.T(), len(podList.Items), 0, "No pods found in namespace %s", namespace.Name) + podNames = append(podNames, podList.Items[0].Name) + + secretData := map[string][]byte{ + "hello": []byte("world"), + } + createdSecret, err := secrets.CreateSecret(client, cluster.ID, namespace.Name, secretData, corev1.SecretTypeOpaque, nil, nil) + require.NoError(acrp.T(), err, "Failed to create secret in namespace %s", namespace.Name) + createdSecrets = append(createdSecrets, createdSecret) + } + + createdUser, err := users.CreateUserWithRole(client, users.UserConfig(), rbac.StandardUser.String()) + require.NoError(acrp.T(), err, "Failed to create user") + + return createdProject, createdNamespaces, createdUser, createdDeployments, podNames, createdSecrets, nil +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) TestPrtbInheritanceWithProjectMgmtResources() { + subSession := acrp.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, _, _, _, err := acrp.acrCreateTestResourcesForPrtb(acrp.client, acrp.cluster) + require.NoError(acrp.T(), err) + + log.Info("Creating project role templates with project management plane resources.") + childRules := rbacapi.PolicyRules["readPrtbs"] + mainRules := rbacapi.PolicyRules["updatePrtbs"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 8, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, acrp.cluster.ID, childRTName, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 4, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyProjectMgmtACR(acrp.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, mainRTName, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName) + createdPrtb, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject, mainRTName) + require.NoError(acrp.T(), err, "Failed to assign role to user") + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrp.client, createdUser.ID, 1) + require.NoError(acrp.T(), err, "prtb not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtbNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "update", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "patch", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) TestPrtbInheritanceWithRegularResources() { + subSession := acrp.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, _, err := acrp.acrCreateTestResourcesForPrtb(acrp.client, acrp.cluster) + require.NoError(acrp.T(), err) + + log.Info("Creating project role templates with regular resources.") + childRules := rbacapi.PolicyRules["readDeployments"] + mainRules := rbacapi.PolicyRules["readPods"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 4, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, acrp.cluster.ID, childRTName, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 4, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, mainRTName, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName) + createdPrtb, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject, mainRTName) + require.NoError(acrp.T(), err, "Failed to assign role to user") + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrp.client, createdUser.ID, 1) + require.NoError(acrp.T(), err, "prtb not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtbNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 0, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "deployments", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projects", "", createdProject.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) TestPrtbInheritanceWithMgmtAndRegularResources() { + subSession := acrp.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, _, err := acrp.acrCreateTestResourcesForPrtb(acrp.client, acrp.cluster) + require.NoError(acrp.T(), err) + + log.Info("Creating project role templates with project management and regular resources.") + childRules := rbacapi.PolicyRules["readPrtbs"] + mainRules := rbacapi.PolicyRules["readPods"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 7, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, acrp.cluster.ID, childRTName, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 4, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyProjectMgmtACR(acrp.client, clusterapi.LocalCluster, childRTName, nil) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, mainRTName, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName) + createdPrtb, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject, mainRTName) + require.NoError(acrp.T(), err, "Failed to assign role to user") + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrp.client, createdUser.ID, 1) + require.NoError(acrp.T(), err, "prtb not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtbNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) TestPrtbInheritanceWithMultipleRules() { + subSession := acrp.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, createdSecret, err := acrp.acrCreateTestResourcesForPrtb(acrp.client, acrp.cluster) + require.NoError(acrp.T(), err) + + log.Info("Creating project role templates with multiple rules.") + chidRules := []rbacv1.PolicyRule{ + { + Verbs: []string{"get", "list"}, + Resources: []string{"deployments"}, + APIGroups: []string{rbacapi.AppsAPIGroup}, + }, + { + Verbs: []string{"get", "list"}, + Resources: []string{"secrets"}, + APIGroups: []string{""}, + }, + } + mainRules := []rbacv1.PolicyRule{ + { + Verbs: []string{"get", "list"}, + Resources: []string{"pods"}, + APIGroups: []string{""}, + }, + { + Verbs: []string{"get", "list", "update"}, + Resources: []string{"projectroletemplatebindings"}, + APIGroups: []string{rbacapi.ManagementAPIGroup}, + }, + } + createdChildRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, chidRules, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template") + + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 8, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, acrp.cluster.ID, childRTName, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 4, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyProjectMgmtACR(acrp.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, mainRTName, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName) + createdPrtb, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject, mainRTName) + require.NoError(acrp.T(), err, "Failed to assign role to user") + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrp.client, createdUser.ID, 1) + require.NoError(acrp.T(), err, "prtb not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtbNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "update", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "patch", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "deployments", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "secrets", namespaceName, createdSecret[0].Name, true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "secrets", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "secrets", namespaceName, createdSecret[0].Name, false, false)) +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) TestPrtbWithNoInheritance() { + subSession := acrp.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, _, _, _, err := acrp.acrCreateTestResourcesForPrtb(acrp.client, acrp.cluster) + require.NoError(acrp.T(), err) + + log.Info("Creating a project role template with no inheritance.") + mainRules := rbacapi.PolicyRules["readPrtbs"] + createdMainRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, mainRules, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create main role template") + + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, clusterapi.LocalCluster, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 4, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, acrp.cluster.ID, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 2, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, mainRTName, nil) + require.NoError(acrp.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyProjectMgmtACR(acrp.client, clusterapi.LocalCluster, mainRTName, nil) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, mainRTName, nil) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName) + createdPrtb, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject, mainRTName) + require.NoError(acrp.T(), err, "Failed to assign role to user") + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrp.client, createdUser.ID, 1) + require.NoError(acrp.T(), err, "prtb not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtbNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "update", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "patch", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "pods", createdNamespaces[0].Name, "", false, false)) +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) TestPrtbInheritedRulesOnly() { + subSession := acrp.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, _, _, _, err := acrp.acrCreateTestResourcesForPrtb(acrp.client, acrp.cluster) + require.NoError(acrp.T(), err) + + log.Info("Creating project role templates.") + childRules := rbacapi.PolicyRules["readPrtbs"] + mainRules := []rbacv1.PolicyRule{} + createdChildRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 7, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, acrp.cluster.ID, childRTName, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 4, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyProjectMgmtACR(acrp.client, clusterapi.LocalCluster, childRTName, nil) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, mainRTName, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName) + createdPrtb, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject, mainRTName) + require.NoError(acrp.T(), err, "Failed to assign role to user") + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrp.client, createdUser.ID, 1) + require.NoError(acrp.T(), err, "prtb not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtbNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "update", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "patch", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "pods", createdNamespaces[0].Name, "", false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) TestPrtbInheritanceWithTwoPrtbs() { + subSession := acrp.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, _, err := acrp.acrCreateTestResourcesForPrtb(acrp.client, acrp.cluster) + require.NoError(acrp.T(), err) + + log.Info("Creating project role templates.") + childRules1 := rbacapi.PolicyRules["readDeployments"] + childRules2 := rbacapi.PolicyRules["readPods"] + mainRules1 := rbacapi.PolicyRules["updatePrtbs"] + mainRules2 := rbacapi.PolicyRules["readPrtbs"] + + createdChildRT1, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules1, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template") + createdChildRT2, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules2, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template") + + inheritedChildRoleTemplate1 := []*v3.RoleTemplate{createdChildRT1} + inheritedChildRoleTemplate2 := []*v3.RoleTemplate{createdChildRT2} + + createdMainRT1, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, mainRules1, inheritedChildRoleTemplate1, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create main role template") + createdMainRT2, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, mainRules2, inheritedChildRoleTemplate2, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create main role template") + + childRTName1 := createdChildRT1.Name + mainRTName1 := createdMainRT1.Name + childRTName2 := createdChildRT2.Name + mainRTName2 := createdMainRT2.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, clusterapi.LocalCluster, childRTName1, mainRTName1, childRTName2, mainRTName2) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 12, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, acrp.cluster.ID, childRTName1, mainRTName1, childRTName2, mainRTName2) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 8, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, mainRTName1, []string{childRTName1}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, mainRTName2, []string{childRTName2}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyProjectMgmtACR(acrp.client, clusterapi.LocalCluster, mainRTName1, nil) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyProjectMgmtACR(acrp.client, clusterapi.LocalCluster, mainRTName2, nil) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, mainRTName1, []string{childRTName1}) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, mainRTName2, []string{childRTName2}) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName1) + createdPrtb1, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject, mainRTName1) + require.NoError(acrp.T(), err, "Failed to assign role to user") + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName2) + createdPrtb2, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject, mainRTName2) + require.NoError(acrp.T(), err, "Failed to assign role to user") + + log.Infof("Verifying project role template bindings are created for user %s", createdUser.Username) + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrp.client, createdUser.ID, 2) + require.NoError(acrp.T(), err, "prtb not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtb1Namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtb1Namespace}, 1, 0) + require.NoError(acrp.T(), err) + + prtb2Namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[1].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[1], []*corev1.Namespace{prtb2Namespace}, 1, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[1], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "deployments", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb1.Namespace, createdPrtb1.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb1.Namespace, "", true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "update", "projectroletemplatebindings", createdPrtb1.Namespace, createdPrtb1.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "patch", "projectroletemplatebindings", createdPrtb1.Namespace, createdPrtb1.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb1.Namespace, createdPrtb1.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb2.Namespace, createdPrtb2.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb2.Namespace, "", true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "update", "projectroletemplatebindings", createdPrtb2.Namespace, createdPrtb2.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "patch", "projectroletemplatebindings", createdPrtb2.Namespace, createdPrtb2.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb2.Namespace, createdPrtb2.Name, false, true)) +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) TestPrtbNestedInheritance() { + subSession := acrp.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, createdSecret, err := acrp.acrCreateTestResourcesForPrtb(acrp.client, acrp.cluster) + require.NoError(acrp.T(), err) + + log.Info("Creating nested project role templates.") + childRules1 := rbacapi.PolicyRules["readDeployments"] + childRules2 := rbacapi.PolicyRules["readSecrets"] + childRules3 := rbacapi.PolicyRules["readPrtbs"] + mainRules1 := rbacapi.PolicyRules["readPods"] + + createdChildRT1, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules1, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template") + + inheritedChildRoleTemplate1 := []*v3.RoleTemplate{createdChildRT1} + createdChildRT2, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules2, inheritedChildRoleTemplate1, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template") + + inheritedChildRoleTemplate2 := []*v3.RoleTemplate{createdChildRT2} + createdChildRT3, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules3, inheritedChildRoleTemplate2, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template") + + inheritedMainRoleTemplate1 := []*v3.RoleTemplate{createdChildRT3} + createdMainRT1, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, mainRules1, inheritedMainRoleTemplate1, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create main role template") + + childRTName1 := createdChildRT1.Name + childRTName2 := createdChildRT2.Name + childRTName3 := createdChildRT3.Name + mainRTName1 := createdMainRT1.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, clusterapi.LocalCluster, childRTName1, childRTName2, childRTName3, mainRTName1) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 13, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, acrp.cluster.ID, childRTName1, childRTName2, childRTName3, mainRTName1) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 8, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster roles in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyProjectMgmtACR(acrp.client, clusterapi.LocalCluster, childRTName3, []string{childRTName2}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, mainRTName1, []string{childRTName1, childRTName2, childRTName3}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for main role") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, childRTName3, []string{childRTName1, childRTName2}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for child role 3") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, childRTName2, []string{childRTName1}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for child role 2") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, mainRTName1, []string{childRTName1, childRTName2, childRTName3}) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR for main role") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, childRTName3, []string{childRTName1, childRTName2}) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR for child role 3") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, childRTName2, []string{childRTName1}) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR for child role 2") + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName1) + createdPrtb, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject, mainRTName1) + require.NoError(acrp.T(), err, "Failed to assign role to user") + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrp.client, createdUser.ID, 1) + require.NoError(acrp.T(), err, "prtb not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtbNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "deployments", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "secrets", namespaceName, createdSecret[0].Name, true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "secrets", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "update", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "patch", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) TestPrtbMultipleLevelsOfInheritance() { + subSession := acrp.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, createdDeployment, podNames, createdSecret, err := acrp.acrCreateTestResourcesForPrtb(acrp.client, acrp.cluster) + require.NoError(acrp.T(), err) + + log.Info("Creating multiple levels of nested project role templates.") + childRules11 := rbacapi.PolicyRules["readDeployments"] + childRules12 := rbacapi.PolicyRules["readSecrets"] + parentRules1 := rbacapi.PolicyRules["readNamespaces"] + childRules21 := rbacapi.PolicyRules["readPods"] + parentRules2 := rbacapi.PolicyRules["readPrtbs"] + mainRules1 := rbacapi.PolicyRules["updatePrtbs"] + + createdChildRT11, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules11, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template 11") + + createdChildRT12, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules12, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template 12") + + inheritedParentRoleTemplate1 := []*v3.RoleTemplate{createdChildRT11, createdChildRT12} + createdParentRT1, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, parentRules1, inheritedParentRoleTemplate1, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create parent role template 1") + + createdChildRT21, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules21, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template 21") + + inheritedParentRoleTemplate2 := []*v3.RoleTemplate{createdChildRT21} + createdParentRT2, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, parentRules2, inheritedParentRoleTemplate2, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create parent role template 2") + + inheritedMainRoleTemplate1 := []*v3.RoleTemplate{createdParentRT1, createdParentRT2} + createdMainRT1, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, mainRules1, inheritedMainRoleTemplate1, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create main role template 1") + + childRTName11 := createdChildRT11.Name + childRTName12 := createdChildRT12.Name + parentRTName1 := createdParentRT1.Name + childRTName21 := createdChildRT21.Name + parentRTName2 := createdParentRT2.Name + mainRTName1 := createdMainRT1.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, clusterapi.LocalCluster, childRTName11, childRTName12, parentRTName1, childRTName21, parentRTName2, mainRTName1) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 19, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, acrp.cluster.ID, childRTName11, childRTName12, parentRTName1, childRTName21, parentRTName2, mainRTName1) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 12, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyProjectMgmtACR(acrp.client, clusterapi.LocalCluster, mainRTName1, []string{parentRTName2, childRTName12}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, mainRTName1, []string{childRTName11, childRTName12, parentRTName1, childRTName21, parentRTName2}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for main role") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, mainRTName1, []string{childRTName11, childRTName12, parentRTName1, childRTName21, parentRTName2}) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR for main role") + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName1) + createdPrtb, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject, mainRTName1) + require.NoError(acrp.T(), err, "Failed to assign role to user") + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrp.client, createdUser.ID, 1) + require.NoError(acrp.T(), err, "prtb not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtbNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "deployments", namespaceName, createdDeployment[0].Name, true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "deployments", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "deployments", namespaceName, createdDeployment[0].Name, false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "namespaces", "", namespaceName, true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "secrets", namespaceName, createdSecret[0].Name, true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "secrets", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "update", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "patch", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) TestPrtbUpdateRoleTemplateToAddInheritance() { + subSession := acrp.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, _, podNames, _, err := acrp.acrCreateTestResourcesForPrtb(acrp.client, acrp.cluster) + require.NoError(acrp.T(), err) + + log.Info("Creating a project role template with no inheritance.") + mainRules := rbacapi.PolicyRules["readPrtbs"] + createdMainRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, mainRules, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create main role template") + + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, clusterapi.LocalCluster, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 4, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, acrp.cluster.ID, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 2, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, mainRTName, nil) + require.NoError(acrp.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyProjectMgmtACR(acrp.client, clusterapi.LocalCluster, mainRTName, nil) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, mainRTName, nil) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName) + createdPrtb, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject, mainRTName) + require.NoError(acrp.T(), err, "Failed to assign role to user") + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrp.client, createdUser.ID, 1) + require.NoError(acrp.T(), err, "prtb not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtbNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "update", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "pods", namespaceName, "", false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], false, false)) + + log.Info("Creating a new project role template.") + childRules := rbacapi.PolicyRules["readPods"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template") + + childRTName := createdChildRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrp.client, clusterapi.LocalCluster, childRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 2, len(localCRs.Items)) + downstreamCRs, err = rbacapi.GetClusterRolesForRoleTemplates(acrp.client, acrp.cluster.ID, childRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 2, len(downstreamCRs.Items)) + + log.Info("Updating the main role template to add inheritance.") + updatedMainRT, err := rbacapi.UpdateRoleTemplateInheritance(acrp.client, mainRTName, []*v3.RoleTemplate{createdChildRT}) + require.NoError(acrp.T(), err, "Failed to update role template inheritance") + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, updatedMainRT.Name, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyProjectMgmtACR(acrp.client, clusterapi.LocalCluster, mainRTName, nil) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, updatedMainRT.Name, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "update", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) TestPrtbUpdateRoleTemplateToRemoveInheritance() { + subSession := acrp.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, _, podNames, _, err := acrp.acrCreateTestResourcesForPrtb(acrp.client, acrp.cluster) + require.NoError(acrp.T(), err) + + log.Info("Creating project role templates with project management and regular resources.") + childRules := rbacapi.PolicyRules["readPods"] + mainRules := rbacapi.PolicyRules["readPrtbs"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create main role template") + + childRTName := createdChildRT.Name + mainRTName := createdMainRT.Name + + log.Info("Verifying the cluster roles in the local and downstream clusters.") + localCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, clusterapi.LocalCluster, childRTName, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 6, len(localCRs.Items)) + downstreamCRs, err := rbacapi.GetClusterRolesForRoleTemplates(acrp.client, acrp.cluster.ID, childRTName, mainRTName) + require.NoError(acrp.T(), err) + require.Equal(acrp.T(), 4, len(downstreamCRs.Items)) + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, mainRTName, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch local ACR") + err = rbacapi.VerifyProjectMgmtACR(acrp.client, clusterapi.LocalCluster, mainRTName, nil) + require.NoError(acrp.T(), err, "Failed to fetch local ACR for project-mgmt resources") + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, mainRTName, []string{childRTName}) + require.NoError(acrp.T(), err, "Failed to fetch downstream ACR") + + log.Infof("Adding user %s to a project %s in the downstream cluster with role %s", createdUser.Username, createdProject.Name, mainRTName) + createdPrtb, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject, mainRTName) + require.NoError(acrp.T(), err, "Failed to assign role to user") + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrp.client, createdUser.ID, 1) + require.NoError(acrp.T(), err, "prtb not found for user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtbNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "pods", namespaceName, "", true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + + log.Info("Removing inheritance from the main role template.") + updatedMainRT, err := rbacapi.UpdateRoleTemplateInheritance(acrp.client, mainRTName, []*v3.RoleTemplate{}) + require.NoError(acrp.T(), err, "Failed to update role template inheritance") + + log.Info("Verifying that the aggregated cluster role in the local and downstream clusters includes the correct rules.") + err = rbacapi.VerifyProjectMgmtACR(acrp.client, clusterapi.LocalCluster, updatedMainRT.Name, []string{}) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, clusterapi.LocalCluster, updatedMainRT.Name, []string{}) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyMainACRContainsAllRules(acrp.client, acrp.cluster.ID, updatedMainRT.Name, []string{}) + require.NoError(acrp.T(), err) + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "pods", namespaceName, "", false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "pods", namespaceName, podNames[0], false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) +} + +func (acrp *AggregatedClusterRolesPrtbTestSuite) TestPrtbVerifyCrossClusterAndProjectAccessRestriction() { + subSession := acrp.session.NewSession() + defer subSession.Cleanup() + + createdProject, createdNamespaces, createdUser, _, _, createdSecret, err := acrp.acrCreateTestResourcesForPrtb(acrp.client, acrp.cluster) + require.NoError(acrp.T(), err) + + createdProject2, err := projectapi.CreateProject(acrp.client, acrp.cluster.ID) + require.NoError(acrp.T(), err, "Failed to create project") + createdNamespace2, err := namespaceapi.CreateNamespaceUsingWrangler(acrp.client, acrp.cluster.ID, createdProject2.Name, nil) + require.NoError(acrp.T(), err, "Failed to create namespace") + secretData := map[string][]byte{ + "hello": []byte("world"), + } + createdSecret2, err := secrets.CreateSecret(acrp.client, acrp.cluster.ID, createdNamespace2.Name, secretData, corev1.SecretTypeOpaque, nil, nil) + require.NoError(acrp.T(), err, "Failed to create secret in namespace %s", createdNamespace2.Name) + + createdProject3, err := projectapi.CreateProject(acrp.client, clusterapi.LocalCluster) + require.NoError(acrp.T(), err, "Failed to create project") + + log.Info("Creating project role templates with project management plane resources.") + childRules := rbacapi.PolicyRules["readPrtbs"] + mainRules := rbacapi.PolicyRules["updatePrtbs"] + createdChildRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, childRules, nil, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create child role template") + inheritedChildRoleTemplate := []*v3.RoleTemplate{createdChildRT} + createdMainRT, err := rbacapi.CreateRoleTemplate(acrp.client, rbacapi.ProjectContext, mainRules, inheritedChildRoleTemplate, false, false, nil) + require.NoError(acrp.T(), err, "Failed to create main role template") + + mainRTName := createdMainRT.Name + log.Infof("Adding user %s to a project %s in the downstream cluster %s with role %s", createdUser.Username, createdProject.Name, acrp.cluster.Name, mainRTName) + createdPrtb, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject, mainRTName) + require.NoError(acrp.T(), err, "Failed to assign role to user") + prtbs, err := rbacapi.VerifyProjectRoleTemplateBindingForUser(acrp.client, createdUser.ID, 1) + require.NoError(acrp.T(), err, "prtb not found for user") + + log.Infof("Adding user %s to a project %s in the downstream cluster %s with role %s", createdUser.Username, createdProject2.Name, acrp.cluster.Name, rbac.SecretsView.String()) + createdPrtb2, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject2, rbac.SecretsView.String()) + require.NoError(acrp.T(), err, "Failed to assign role to user") + + log.Infof("Adding user %s to a project %s in the local cluster with role %s", createdUser.Username, createdProject3.Name, rbac.SecretsView.String()) + createdPrtb3, err := rbacapi.CreateProjectRoleTemplateBinding(acrp.client, createdUser, createdProject3, rbac.SecretsView.String()) + require.NoError(acrp.T(), err, "Failed to assign role to user") + + log.Infof("Verifying role bindings and cluster role bindings for user %s in the local and downstream clusters.", createdUser.Username) + prtbNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: prtbs[0].Namespace, + }, + } + err = rbacapi.VerifyBindingsForPrtb(acrp.client, clusterapi.LocalCluster, &prtbs[0], []*corev1.Namespace{prtbNamespace}, 1, 0) + require.NoError(acrp.T(), err) + err = rbacapi.VerifyBindingsForPrtb(acrp.client, acrp.cluster.ID, &prtbs[0], createdNamespaces, 1, 0) + require.NoError(acrp.T(), err) + + log.Infof("Verifying user permissions for user %s are correct.", createdUser.Username) + namespaceName := createdNamespaces[0].Name + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb.Namespace, "", true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "update", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "patch", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, true, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "delete", "projectroletemplatebindings", createdPrtb.Namespace, createdPrtb.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "secrets", namespaceName, createdSecret[0].Name, false, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "projectroletemplatebindings", createdPrtb2.Namespace, createdPrtb2.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "list", "projectroletemplatebindings", createdPrtb2.Namespace, "", false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "update", "projectroletemplatebindings", createdPrtb2.Namespace, createdPrtb2.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "patch", "projectroletemplatebindings", createdPrtb2.Namespace, createdPrtb2.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, acrp.cluster.ID, createdUser, "get", "secrets", createdNamespace2.Name, createdSecret2.Name, true, false)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, clusterapi.LocalCluster, createdUser, "get", "projectroletemplatebindings", createdPrtb3.Namespace, createdPrtb3.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, clusterapi.LocalCluster, createdUser, "list", "projectroletemplatebindings", createdPrtb3.Namespace, "", false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, clusterapi.LocalCluster, createdUser, "update", "projectroletemplatebindings", createdPrtb3.Namespace, createdPrtb3.Name, false, true)) + require.NoError(acrp.T(), rbacapi.VerifyUserPermission(acrp.client, clusterapi.LocalCluster, createdUser, "patch", "projectroletemplatebindings", createdPrtb3.Namespace, createdPrtb3.Name, false, true)) +} + +func TestAggregatedClusterRolesPrtbTestSuite(t *testing.T) { + suite.Run(t, new(AggregatedClusterRolesPrtbTestSuite)) +} diff --git a/validation/rbac/clusterandprojectroles/cluster_role_test.go b/validation/rbac/clusterandprojectroles/cluster_role_test.go index 8c774a778..bc0da7bb9 100644 --- a/validation/rbac/clusterandprojectroles/cluster_role_test.go +++ b/validation/rbac/clusterandprojectroles/cluster_role_test.go @@ -11,6 +11,7 @@ import ( "github.com/rancher/shepherd/extensions/clusters" "github.com/rancher/shepherd/pkg/session" clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/projects" "github.com/rancher/tests/actions/rbac" "github.com/rancher/tests/actions/secrets" @@ -58,7 +59,7 @@ func (rb *ClusterRoleTestSuite) testSetupUserAndProject(role string) (*managemen require.NoError(rb.T(), err) log.Infof("Adding a standard user to the downstream cluster as %s", role) - _, errUserRole := rbac.CreateClusterRoleTemplateBinding(rb.client, rb.cluster.ID, standardUser, role) + _, errUserRole := rbacapi.CreateClusterRoleTemplateBinding(rb.client, rb.cluster.ID, standardUser, role) require.NoError(rb.T(), errUserRole) standardUserClient, err = standardUserClient.ReLogin() require.NoError(rb.T(), err) @@ -72,7 +73,7 @@ func (rb *ClusterRoleTestSuite) testSetupUserAndProject(role string) (*managemen createdProject, createdNamespace, err := projects.CreateProjectAndNamespaceUsingWrangler(userClient, rb.cluster.ID) require.NoError(rb.T(), err) - _, errProjectOwnerRole := rbac.CreateProjectRoleTemplateBinding(rb.client, standardUser, createdProject, rbac.CustomManageProjectMember.String()) + _, errProjectOwnerRole := rbacapi.CreateProjectRoleTemplateBinding(rb.client, standardUser, createdProject, rbac.CustomManageProjectMember.String()) require.NoError(rb.T(), errProjectOwnerRole) standardUserClient, err = standardUserClient.ReLogin() require.NoError(rb.T(), err) @@ -89,7 +90,7 @@ func (rb *ClusterRoleTestSuite) TestClusterOwnerAddsUserAsProjectOwner() { additionalUser, additionalUserClient, err := rbac.SetupUser(rb.client, rbac.StandardUser.String()) require.NoError(rb.T(), err) - createdPrtb, err := rbac.CreateProjectRoleTemplateBinding(standardUserClient, additionalUser, clusterOwnerProject, rbac.ProjectOwner.String()) + createdPrtb, err := rbacapi.CreateProjectRoleTemplateBinding(standardUserClient, additionalUser, clusterOwnerProject, rbac.ProjectOwner.String()) require.NoError(rb.T(), err) additionalUserClient, err = additionalUserClient.ReLogin() require.NoError(rb.T(), err) @@ -117,7 +118,7 @@ func (rb *ClusterRoleTestSuite) TestClusterOwnerAddsUserAsClusterOwner() { additionalUser, additionalUserClient, err := rbac.SetupUser(rb.client, rbac.StandardUser.String()) require.NoError(rb.T(), err) - crtb, err := rbac.CreateClusterRoleTemplateBinding(standardUserClient, rb.cluster.ID, additionalUser, rbac.ClusterOwner.String()) + crtb, err := rbacapi.CreateClusterRoleTemplateBinding(standardUserClient, rb.cluster.ID, additionalUser, rbac.ClusterOwner.String()) require.NoError(rb.T(), err) additionalUserClient, err = additionalUserClient.ReLogin() require.NoError(rb.T(), err) @@ -145,7 +146,7 @@ func (rb *ClusterRoleTestSuite) TestClusterOwnerAddsClusterMemberAsProjectOwner( additionalUser, additionalUserClient, err := rbac.SetupUser(rb.client, rbac.StandardUser.String()) require.NoError(rb.T(), err) - _, err = rbac.CreateClusterRoleTemplateBinding(standardUserClient, rb.cluster.ID, additionalUser, rbac.ClusterMember.String()) + _, err = rbacapi.CreateClusterRoleTemplateBinding(standardUserClient, rb.cluster.ID, additionalUser, rbac.ClusterMember.String()) require.NoError(rb.T(), err) additionalUserClient, err = additionalUserClient.ReLogin() require.NoError(rb.T(), err) @@ -154,7 +155,7 @@ func (rb *ClusterRoleTestSuite) TestClusterOwnerAddsClusterMemberAsProjectOwner( require.NoError(rb.T(), err) assert.Equal(rb.T(), 1, len(clusterList.Data)) - _, err = rbac.CreateProjectRoleTemplateBinding(standardUserClient, additionalUser, clusterOwnerProject, rbac.ProjectOwner.String()) + _, err = rbacapi.CreateProjectRoleTemplateBinding(standardUserClient, additionalUser, clusterOwnerProject, rbac.ProjectOwner.String()) require.NoError(rb.T(), err) additionalUserClient, err = additionalUserClient.ReLogin() require.NoError(rb.T(), err) @@ -176,23 +177,23 @@ func (rb *ClusterRoleTestSuite) TestClusterMemberWithPrtbAccess() { log.Infof("Creating a cluster role template with verbs *, resources projectroletemplatebindings") rules := []rbacv1.PolicyRule{{ Verbs: []string{"*"}, - APIGroups: []string{rbac.ManagementAPIGroup}, - Resources: []string{rbac.PrtbResource}, + APIGroups: []string{rbacapi.ManagementAPIGroup}, + Resources: []string{rbacapi.PrtbResource}, }} - createdRoleTemplate, err := rbac.CreateRoleTemplate(rb.client, rbac.ClusterContext, rules, nil, false, nil) + createdRoleTemplate, err := rbacapi.CreateRoleTemplate(rb.client, rbacapi.ClusterContext, rules, nil, false, false, nil) require.NoError(rb.T(), err, "Failed to create main role template") log.Info("Adding the user to the downstream cluster with the cluster role template") - _, err = rbac.CreateClusterRoleTemplateBinding(rb.client, rb.cluster.ID, standardUser, createdRoleTemplate.Name) + _, err = rbacapi.CreateClusterRoleTemplateBinding(rb.client, rb.cluster.ID, standardUser, createdRoleTemplate.Name) require.NoError(rb.T(), err) - _, err = rbac.CreateClusterRoleTemplateBinding(rb.client, rb.cluster.ID, standardUser, rbac.ProjectsView.String()) + _, err = rbacapi.CreateClusterRoleTemplateBinding(rb.client, rb.cluster.ID, standardUser, rbac.ProjectsView.String()) require.NoError(rb.T(), err) log.Info("As cluster member with PRTB permissions, verifying CRUD projectroletemplatebindings") - prtb, err := rbac.CreateProjectRoleTemplateBinding(standardUserClient, additionalUser, adminProject, rbac.PrtbView.String()) + prtb, err := rbacapi.CreateProjectRoleTemplateBinding(standardUserClient, additionalUser, adminProject, rbac.PrtbView.String()) require.NoError(rb.T(), err) - userContext, err := clusterapi.GetClusterWranglerContext(standardUserClient, rbac.LocalCluster) + userContext, err := clusterapi.GetClusterWranglerContext(standardUserClient, clusterapi.LocalCluster) require.NoError(rb.T(), err) prtb, err = userContext.Mgmt.ProjectRoleTemplateBinding().Get(prtb.Namespace, prtb.Name, metav1.GetOptions{}) require.NoError(rb.T(), err) @@ -218,15 +219,15 @@ func (rb *ClusterRoleTestSuite) TestClusterMemberWithSecretAccess() { rules := []rbacv1.PolicyRule{{ Verbs: []string{"*"}, APIGroups: []string{""}, - Resources: []string{rbac.SecretsResource}, + Resources: []string{rbacapi.SecretsResource}, }} - createdRoleTemplate, err := rbac.CreateRoleTemplate(rb.client, rbac.ClusterContext, rules, nil, false, nil) + createdRoleTemplate, err := rbacapi.CreateRoleTemplate(rb.client, rbacapi.ClusterContext, rules, nil, false, false, nil) require.NoError(rb.T(), err, "Failed to create main role template") log.Info("Adding the user to the downstream cluster with the cluster role template") - _, err = rbac.CreateClusterRoleTemplateBinding(rb.client, rb.cluster.ID, standardUser, createdRoleTemplate.Name) + _, err = rbacapi.CreateClusterRoleTemplateBinding(rb.client, rb.cluster.ID, standardUser, createdRoleTemplate.Name) require.NoError(rb.T(), err) - _, err = rbac.CreateClusterRoleTemplateBinding(rb.client, rb.cluster.ID, standardUser, rbac.ProjectsView.String()) + _, err = rbacapi.CreateClusterRoleTemplateBinding(rb.client, rb.cluster.ID, standardUser, rbac.ProjectsView.String()) require.NoError(rb.T(), err) log.Info("As cluster member with secrets permissions, verifying CRUD secrets") diff --git a/validation/rbac/clusterandprojectroles/manage_workloads_role_test.go b/validation/rbac/clusterandprojectroles/manage_workloads_role_test.go index 0a710f430..2b539aef7 100644 --- a/validation/rbac/clusterandprojectroles/manage_workloads_role_test.go +++ b/validation/rbac/clusterandprojectroles/manage_workloads_role_test.go @@ -15,8 +15,9 @@ import ( namegen "github.com/rancher/shepherd/pkg/namegenerator" "github.com/rancher/shepherd/pkg/session" clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" - projectsapi "github.com/rancher/tests/actions/projects" - rbac "github.com/rancher/tests/actions/rbac" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" + "github.com/rancher/tests/actions/projects" + "github.com/rancher/tests/actions/rbac" "github.com/rancher/tests/actions/workloads/daemonset" "github.com/rancher/tests/actions/workloads/deployment" "github.com/rancher/tests/actions/workloads/pods" @@ -61,11 +62,11 @@ func (mw *ManageWorkloadsRoleTestSuite) testSetupUserAndProject() (*rancher.Clie require.NoError(mw.T(), err) log.Info("Create a project and a namespace") - createdProject, createdNamespace, err := projectsapi.CreateProjectAndNamespaceUsingWrangler(mw.client, mw.cluster.ID) + createdProject, createdNamespace, err := projects.CreateProjectAndNamespaceUsingWrangler(mw.client, mw.cluster.ID) require.NoError(mw.T(), err) log.Infof("Add the user %s as Project Owner to the project %s", newUser.Name, createdProject.Name) - _, errUserRole := rbac.CreateProjectRoleTemplateBinding(mw.client, newUser, createdProject, rbac.ProjectOwner.String()) + _, errUserRole := rbacapi.CreateProjectRoleTemplateBinding(mw.client, newUser, createdProject, rbac.ProjectOwner.String()) require.NoError(mw.T(), errUserRole) standardUserClient, err = standardUserClient.ReLogin() require.NoError(mw.T(), err) @@ -79,7 +80,7 @@ func (mw *ManageWorkloadsRoleTestSuite) testSetupWorkloadUserAndAddToProject(adm require.NoError(mw.T(), err, "Failed to create a new standard user.") log.Infof("Verify that the project owner is able to add the new user %s to the project %s with 'Manage Workloads' role.", workloadUser.Username, adminProject.Name) - _, errUserRole := rbac.CreateProjectRoleTemplateBinding(mw.client, workloadUser, adminProject, rbac.ManageWorkloads.String()) + _, errUserRole := rbacapi.CreateProjectRoleTemplateBinding(mw.client, workloadUser, adminProject, rbac.ManageWorkloads.String()) require.NoError(mw.T(), errUserRole, "Project owner failed to add the new user to the project with 'Manage Workloads' role.") workloadUserClient, err = workloadUserClient.ReLogin() require.NoError(mw.T(), err) @@ -134,7 +135,7 @@ func (mw *ManageWorkloadsRoleTestSuite) TestManageWorkloadsPermissions() { } } - err = rbac.VerifyRoleRules(expectedRules, actualRules) + err = rbacapi.VerifyRoleRules(expectedRules, actualRules) require.NoError(mw.T(), err, "role rules verification failed") } diff --git a/validation/rbac/clusterandprojectroles/project_role_test.go b/validation/rbac/clusterandprojectroles/project_role_test.go index 72cbc3256..741c9da2a 100644 --- a/validation/rbac/clusterandprojectroles/project_role_test.go +++ b/validation/rbac/clusterandprojectroles/project_role_test.go @@ -10,6 +10,7 @@ import ( management "github.com/rancher/shepherd/clients/rancher/generated/management/v3" "github.com/rancher/shepherd/extensions/clusters" "github.com/rancher/shepherd/pkg/session" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/projects" rbac "github.com/rancher/tests/actions/rbac" log "github.com/sirupsen/logrus" @@ -55,7 +56,7 @@ func (pr *ProjectRolesTestSuite) testSetupUserAndProject() (*rancher.Client, *v3 require.NoError(pr.T(), err) log.Info("Adding a standard user as project owner in the admin project") - _, errUserRole := rbac.CreateProjectRoleTemplateBinding(pr.client, newUser, adminProject, rbac.ProjectOwner.String()) + _, errUserRole := rbacapi.CreateProjectRoleTemplateBinding(pr.client, newUser, adminProject, rbac.ProjectOwner.String()) require.NoError(pr.T(), errUserRole) standardUserClient, err = standardUserClient.ReLogin() require.NoError(pr.T(), err) @@ -72,7 +73,7 @@ func (pr *ProjectRolesTestSuite) TestProjectOwnerAddsAndRemovesOtherProjectOwner additionalUser, additionalUserClient, err := rbac.SetupUser(pr.client, rbac.StandardUser.String()) require.NoError(pr.T(), err) - createdPrtb, errUserRole := rbac.CreateProjectRoleTemplateBinding(standardUserClient, additionalUser, adminProject, rbac.ProjectOwner.String()) + createdPrtb, errUserRole := rbacapi.CreateProjectRoleTemplateBinding(standardUserClient, additionalUser, adminProject, rbac.ProjectOwner.String()) require.NoError(pr.T(), errUserRole) additionalUserClient, err = additionalUserClient.ReLogin() require.NoError(pr.T(), err) @@ -99,7 +100,7 @@ func (pr *ProjectRolesTestSuite) TestManageProjectUserRoleCannotAddProjectOwner( additionalUser, additionalUserClient, err := rbac.SetupUser(pr.client, rbac.StandardUser.String()) require.NoError(pr.T(), err) - _, errUserRole := rbac.CreateProjectRoleTemplateBinding(standardUserClient, additionalUser, adminProject, rbac.CustomManageProjectMember.String()) + _, errUserRole := rbacapi.CreateProjectRoleTemplateBinding(standardUserClient, additionalUser, adminProject, rbac.CustomManageProjectMember.String()) require.NoError(pr.T(), errUserRole) additionalUserClient, err = additionalUserClient.ReLogin() require.NoError(pr.T(), err) @@ -107,7 +108,7 @@ func (pr *ProjectRolesTestSuite) TestManageProjectUserRoleCannotAddProjectOwner( addNewUserAsProjectOwner, addNewUserAsPOClient, err := rbac.SetupUser(pr.client, rbac.StandardUser.String()) require.NoError(pr.T(), err) - _, errUserRole2 := rbac.CreateProjectRoleTemplateBinding(additionalUserClient, addNewUserAsProjectOwner, adminProject, rbac.ProjectOwner.String()) + _, errUserRole2 := rbacapi.CreateProjectRoleTemplateBinding(additionalUserClient, addNewUserAsProjectOwner, adminProject, rbac.ProjectOwner.String()) require.Error(pr.T(), errUserRole2) addNewUserAsPOClient, err = addNewUserAsPOClient.ReLogin() require.NoError(pr.T(), err) diff --git a/validation/rbac/crtb/crtb_status_field_test.go b/validation/rbac/crtb/crtb_status_field_test.go index 06aceac70..7a303a658 100644 --- a/validation/rbac/crtb/crtb_status_field_test.go +++ b/validation/rbac/crtb/crtb_status_field_test.go @@ -13,7 +13,7 @@ import ( "github.com/rancher/shepherd/extensions/clusters" "github.com/rancher/shepherd/extensions/defaults" "github.com/rancher/shepherd/extensions/kubectl" - "github.com/rancher/shepherd/pkg/namegenerator" + namegen "github.com/rancher/shepherd/pkg/namegenerator" "github.com/rancher/shepherd/pkg/session" rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/projects" @@ -67,7 +67,7 @@ func (crtbs *CRTBStatusFieldTestSuite) TestCRTBStatusFieldCreateAndVerify() { require.NoError(crtbs.T(), err) log.Info("Verify that the CRTB status field and the sub-fields are correct") - userCRTBList, err := rbac.GetClusterRoleTemplateBindingsForUser(crtbs.client, user.ID) + userCRTBList, err := rbacapi.GetClusterRoleTemplateBindingsForUser(crtbs.client, user.ID) require.NoError(crtbs.T(), err) userCRTB := userCRTBList err = verifyClusterRoleTemplateBindingStatusField(userCRTB) @@ -85,7 +85,7 @@ func (crtbs *CRTBStatusFieldTestSuite) TestCRTBStatusFieldVerifyReconciliation() log.Infof("Create and add a standard user to downstream cluster with role Cluster Owner") user, _, err := rbac.AddUserWithRoleToCluster(crtbs.client, rbac.StandardUser.String(), rbac.ClusterOwner.String(), crtbs.cluster, adminProject) require.NoError(crtbs.T(), err) - userCRTBList, err := rbac.GetClusterRoleTemplateBindingsForUser(crtbs.client, user.ID) + userCRTBList, err := rbacapi.GetClusterRoleTemplateBindingsForUser(crtbs.client, user.ID) require.NoError(crtbs.T(), err) log.Info("Add environment variable CATTLE_RESYNC_DEFAULT and set it to 1 minute") @@ -150,8 +150,8 @@ func (crtbs *CRTBStatusFieldTestSuite) TestCRTBStatusFieldUpdateAndVerify() { }, }, } - customClusterRole.Name = namegenerator.AppendRandomString("test") - createdCustomClusterRoleTemplate, err := rbacapi.CreateRoleTemplate(crtbs.client, customClusterRole) + customClusterRole.Name = namegen.AppendRandomString("test") + createdCustomClusterRoleTemplate, err := crtbs.client.WranglerContext.Mgmt.RoleTemplate().Create(customClusterRole) require.NoError(crtbs.T(), err) log.Info("Create a project and a namespace in the project") @@ -164,7 +164,7 @@ func (crtbs *CRTBStatusFieldTestSuite) TestCRTBStatusFieldUpdateAndVerify() { userID := user.Resource.ID log.Info("Verify that the CRTB status field and the sub-fields are correct") - userCRTBList, err := rbac.GetClusterRoleTemplateBindingsForUser(crtbs.client, userID) + userCRTBList, err := rbacapi.GetClusterRoleTemplateBindingsForUser(crtbs.client, userID) require.NoError(crtbs.T(), err) userCRTB := userCRTBList err = verifyClusterRoleTemplateBindingStatusField(userCRTB) @@ -179,12 +179,12 @@ func (crtbs *CRTBStatusFieldTestSuite) TestCRTBStatusFieldUpdateAndVerify() { require.NoError(crtbs.T(), err) log.Info("Deleting custom cluster role template") - err = rbacapi.DeleteRoletemplate(crtbs.client, customClusterRole.Name) + err = rbacapi.DeleteRoletemplate(crtbs.client, createdCustomClusterRoleTemplate.Name) require.NoError(crtbs.T(), err) log.Info("Verifying CRTB Status field after deleting custom cluster role template") err = wait.PollUntilContextTimeout(context.TODO(), defaults.OneMinuteTimeout, defaults.OneMinuteTimeout, false, func(ctx context.Context) (bool, error) { - updatedCRTBList, err := rbac.GetClusterRoleTemplateBindingsForUser(crtbs.client, userID) + updatedCRTBList, err := rbacapi.GetClusterRoleTemplateBindingsForUser(crtbs.client, userID) if err != nil { return false, err } @@ -224,7 +224,7 @@ func (crtbs *CRTBStatusFieldTestSuite) TestCRTBStatusFieldKubectlDescribe() { require.NoError(crtbs.T(), err) userID := user.Resource.ID - userCRTBList, err := rbac.GetClusterRoleTemplateBindingsForUser(crtbs.client, userID) + userCRTBList, err := rbacapi.GetClusterRoleTemplateBindingsForUser(crtbs.client, userID) require.NoError(crtbs.T(), err) userCRTB := userCRTBList diff --git a/validation/rbac/deprecated_restrictedadmin.go b/validation/rbac/deprecated_restrictedadmin.go index 7db5a9c24..88e3b6f8f 100644 --- a/validation/rbac/deprecated_restrictedadmin.go +++ b/validation/rbac/deprecated_restrictedadmin.go @@ -13,6 +13,7 @@ import ( "github.com/rancher/shepherd/extensions/clusters" "github.com/rancher/shepherd/extensions/users" namegen "github.com/rancher/shepherd/pkg/namegenerator" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/namespaces" "github.com/rancher/tests/actions/projects" @@ -41,7 +42,7 @@ func verifyRAGlobalRoleBindingsForUser(t *testing.T, user *management.User, admi // verifyRARoleBindingsForUser validates that the corresponding role bindings are created for the user func verifyRARoleBindingsForUser(t *testing.T, user *management.User, adminClient *rancher.Client, clusterID string) { - rblist, err := rbacapi.ListRoleBindings(adminClient, rbacaction.LocalCluster, clusterID, metav1.ListOptions{}) + rblist, err := rbacapi.ListRoleBindings(adminClient, clusterapi.LocalCluster, clusterID, metav1.ListOptions{}) require.NoError(t, err) userID := user.Resource.ID userRoleBindings := []string{} diff --git a/validation/rbac/globalroles/global_roles_test.go b/validation/rbac/globalroles/global_roles_test.go index 7db091cdc..c928dbedb 100644 --- a/validation/rbac/globalroles/global_roles_test.go +++ b/validation/rbac/globalroles/global_roles_test.go @@ -10,6 +10,7 @@ import ( management "github.com/rancher/shepherd/clients/rancher/generated/management/v3" "github.com/rancher/shepherd/extensions/clusters" "github.com/rancher/shepherd/pkg/session" + clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/projects" "github.com/rancher/tests/actions/rbac" @@ -58,14 +59,14 @@ func (gr *GlobalRolesTestSuite) TestGlobalRoleCustom() { require.NoError(gr.T(), err, "Failed to create custom global role and user") log.Info("Verify that the global role binding is created for the user.") - grb, err := rbac.GetGlobalRoleBindingByUserAndRole(gr.client, createdUser.ID, createdGlobalRole.Name) + grb, err := rbacapi.GetGlobalRoleBindingByUserAndRole(gr.client, createdUser.ID, createdGlobalRole.Name) require.NoError(gr.T(), err, "Failed to get global role binding") require.NotEmpty(gr.T(), grb, "Global Role Binding not found for the user") log.Info("As admin, create a deployment.") - _, namespace, err := projects.CreateProjectAndNamespace(gr.client, rbac.LocalCluster) + _, namespace, err := projects.CreateProjectAndNamespace(gr.client, clusterapi.LocalCluster) require.NoError(gr.T(), err, "Failed to create project and namespace") - createdDeployment, err := deployment.CreateDeployment(gr.client, rbac.LocalCluster, namespace.Name, 2, "", "", false, false, false, true) + createdDeployment, err := deployment.CreateDeployment(gr.client, clusterapi.LocalCluster, namespace.Name, 2, "", "", false, false, false, true) require.NoError(gr.T(), err, "Failed to create deployment in the namespace") log.Infof("Verify the user %s can get the deployment.", createdUser.Username) @@ -75,14 +76,14 @@ func (gr *GlobalRolesTestSuite) TestGlobalRoleCustom() { require.NoError(gr.T(), err, "User failed to get the deployment") log.Infof("Verify the user %s cannot create a deployment.", createdUser.Username) - _, err = deployment.CreateDeployment(userClient, rbac.LocalCluster, namespace.Name, 2, "", "", false, false, false, true) + _, err = deployment.CreateDeployment(userClient, clusterapi.LocalCluster, namespace.Name, 2, "", "", false, false, false, true) require.Error(gr.T(), err) require.True(gr.T(), errors.IsForbidden(err)) log.Info("Delete global role.") err = rbacapi.DeleteGlobalRole(gr.client, createdGlobalRole.Name) require.NoError(gr.T(), err, "Failed to delete global role") - _, err = rbac.GetGlobalRoleByName(gr.client, createdGlobalRole.Name) + _, err = rbacapi.GetGlobalRoleByName(gr.client, createdGlobalRole.Name) require.Error(gr.T(), err, "Global role was not deleted") log.Info("Verify the user cannot get the deployment.") @@ -100,27 +101,27 @@ func (gr *GlobalRolesTestSuite) TestBuiltinGlobalRole() { require.NoError(gr.T(), err, "Failed to create user with builtin global role") log.Info("Verify that the global role binding is created for the user.") - grb, err := rbac.GetGlobalRoleBindingByUserAndRole(gr.client, createdUser.ID, rbac.Admin.String()) + grb, err := rbacapi.GetGlobalRoleBindingByUserAndRole(gr.client, createdUser.ID, rbac.Admin.String()) require.NoError(gr.T(), err, "Failed to get global role binding") require.NotEmpty(gr.T(), grb, "Global Role Binding not found for the user") log.Info("Verify the user can create a deployment.") - _, namespace, err := projects.CreateProjectAndNamespace(gr.client, rbac.LocalCluster) + _, namespace, err := projects.CreateProjectAndNamespace(gr.client, clusterapi.LocalCluster) require.NoError(gr.T(), err, "Failed to create project and namespace") userClient, err := gr.client.AsUser(createdUser) require.NoError(gr.T(), err) - _, err = deployment.CreateDeployment(userClient, rbac.LocalCluster, namespace.Name, 2, "", "", false, false, false, true) + _, err = deployment.CreateDeployment(userClient, clusterapi.LocalCluster, namespace.Name, 2, "", "", false, false, false, true) require.NoError(gr.T(), err, "User failed to create deployment in the namespace") log.Info("Delete the global role binding for the user.") err = rbacapi.DeleteGlobalRoleBinding(gr.client, grb.Name) require.NoError(gr.T(), err, "Failed to delete global role binding") - _, err = rbac.GetGlobalRoleBindingByName(gr.client, grb.Name) + _, err = rbacapi.GetGlobalRoleBindingByName(gr.client, grb.Name) require.Error(gr.T(), err, "Global role binding was not deleted") log.Info("Verify the user cannot create a deployment.") - _, err = deployment.CreateDeployment(userClient, rbac.LocalCluster, namespace.Name, 2, "", "", false, false, false, true) + _, err = deployment.CreateDeployment(userClient, clusterapi.LocalCluster, namespace.Name, 2, "", "", false, false, false, true) require.Error(gr.T(), err) require.True(gr.T(), errors.IsForbidden(err)) } @@ -131,7 +132,7 @@ func (gr *GlobalRolesTestSuite) TestUpdateBuiltinGlobalRoleFails() { log.Info("Attempt to update an existing built-in global role and verify it fails.") builtinGlobalRoleName := rbac.StandardUser.String() - builtinGlobalRole, err := rbac.GetGlobalRoleByName(gr.client, builtinGlobalRoleName) + builtinGlobalRole, err := rbacapi.GetGlobalRoleByName(gr.client, builtinGlobalRoleName) require.NoError(gr.T(), err, "Failed to fetch the built-in global role") updatedGlobalRole := builtinGlobalRole.DeepCopy() @@ -158,7 +159,7 @@ func (gr *GlobalRolesTestSuite) TestDeleteBuiltinGlobalRoleFails() { expectedErrMessage := fmt.Sprintf("%s cannot delete builtin GlobalRoles", webhookErrorMessagePrefix) require.Contains(gr.T(), err.Error(), expectedErrMessage) - _, err = rbac.GetGlobalRoleByName(gr.client, builtinGlobalRoleName) + _, err = rbacapi.GetGlobalRoleByName(gr.client, builtinGlobalRoleName) require.NoError(gr.T(), err, "Failed to fetch the built-in global role") } diff --git a/validation/rbac/globalroles/globalroles.go b/validation/rbac/globalroles/globalroles.go index b43a01777..2d2293e03 100644 --- a/validation/rbac/globalroles/globalroles.go +++ b/validation/rbac/globalroles/globalroles.go @@ -8,6 +8,7 @@ import ( management "github.com/rancher/shepherd/clients/rancher/generated/management/v3" "github.com/rancher/shepherd/extensions/users" namegen "github.com/rancher/shepherd/pkg/namegenerator" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -39,7 +40,7 @@ func createCustomGlobalRole(client *rancher.Client, globalRole *v3.GlobalRole) ( return nil, err } - createdGlobalRole, err = rbac.GetGlobalRoleByName(client, createdGlobalRole.Name) + createdGlobalRole, err = rbacapi.GetGlobalRoleByName(client, createdGlobalRole.Name) if err != nil { return nil, err } diff --git a/validation/rbac/globalroles/rbac_global_roles_test.go b/validation/rbac/globalroles/rbac_global_roles_test.go index 3d6156375..62feae79f 100644 --- a/validation/rbac/globalroles/rbac_global_roles_test.go +++ b/validation/rbac/globalroles/rbac_global_roles_test.go @@ -112,7 +112,7 @@ func (rgr *RbacGlobalRolesTestSuite) TestListGlobalRole() { switch tt.role.String() { case rbac.Admin.String(): log.Infof("As a %v, list the global role", tt.role.String()) - grole, err := rbac.GetGlobalRoleByName(rgr.client, createdGlobalRole.Name) + grole, err := rbacapi.GetGlobalRoleByName(rgr.client, createdGlobalRole.Name) assert.NoError(rgr.T(), err) assert.Equal(rgr.T(), grole.Name, createdGlobalRole.Name) case rbac.ClusterOwner.String(), rbac.ClusterMember.String(), rbac.ProjectOwner.String(), rbac.ProjectMember.String(), rbac.ReadOnly.String(): @@ -125,7 +125,7 @@ func (rgr *RbacGlobalRolesTestSuite) TestListGlobalRole() { assert.NoError(rgr.T(), err) log.Infof("As a %v, list the global role", tt.role.String()) - _, err = rbac.GetGlobalRoleByName(userClient, createdGlobalRole.Name) + _, err = rbacapi.GetGlobalRoleByName(userClient, createdGlobalRole.Name) assert.Error(rgr.T(), err) assert.True(rgr.T(), errors.IsForbidden(err)) } @@ -155,7 +155,7 @@ func (rgr *RbacGlobalRolesTestSuite) TestUpdateGlobalRole() { createdGlobalRole, err := createCustomGlobalRole(rgr.client, &customGlobalRole) assert.NoError(rgr.T(), err) - globalRole, err := rbac.GetGlobalRoleByName(rgr.client, createdGlobalRole.Name) + globalRole, err := rbacapi.GetGlobalRoleByName(rgr.client, createdGlobalRole.Name) assert.NoError(rgr.T(), err) if globalRole.Labels == nil { @@ -169,7 +169,7 @@ func (rgr *RbacGlobalRolesTestSuite) TestUpdateGlobalRole() { _, err = rbacapi.UpdateGlobalRole(rgr.client, globalRole) assert.NoError(rgr.T(), err) - updatedGlobalRole, err := rbac.GetGlobalRoleByName(rgr.client, createdGlobalRole.Name) + updatedGlobalRole, err := rbacapi.GetGlobalRoleByName(rgr.client, createdGlobalRole.Name) assert.NoError(rgr.T(), err) assert.Equal(rgr.T(), "true", updatedGlobalRole.Labels["test-label"], "Label not updated as expected") case rbac.ClusterOwner.String(), rbac.ClusterMember.String(), rbac.ProjectOwner.String(), rbac.ProjectMember.String(), rbac.ReadOnly.String(): @@ -218,7 +218,7 @@ func (rgr *RbacGlobalRolesTestSuite) TestDeleteGlobalRole() { err = rbacapi.DeleteGlobalRole(rgr.client, createdGlobalRole.Name) assert.NoError(rgr.T(), err) - _, err = rbac.GetGlobalRoleByName(rgr.client, createdGlobalRole.Name) + _, err = rbacapi.GetGlobalRoleByName(rgr.client, createdGlobalRole.Name) assert.Error(rgr.T(), err) case rbac.ClusterOwner.String(), rbac.ClusterMember.String(), rbac.ProjectOwner.String(), rbac.ProjectMember.String(), rbac.ReadOnly.String(): log.Info("Create a project and a namespace in the project.") diff --git a/validation/rbac/globalroles/restrictedadmin_replacement_template.go b/validation/rbac/globalroles/restrictedadmin_replacement_template.go index 3ea6bdece..6ad4fc174 100644 --- a/validation/rbac/globalroles/restrictedadmin_replacement_template.go +++ b/validation/rbac/globalroles/restrictedadmin_replacement_template.go @@ -2,7 +2,7 @@ package globalroles import ( v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3" - "github.com/rancher/tests/actions/rbac" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -107,8 +107,8 @@ func newRestrictedAdminReplacementTemplate(globalRoleName string) v3.GlobalRole var ( manageUsersVerb = rbacv1.PolicyRule{ - Verbs: []string{rbac.ManageUsersVerb}, - APIGroups: []string{rbac.ManagementAPIGroup}, - Resources: []string{rbac.UsersResource, rbac.UserAttributeResource, rbac.GroupsResource, rbac.GroupMembersResource}, + Verbs: []string{rbacapi.ManageUsersVerb}, + APIGroups: []string{rbacapi.ManagementAPIGroup}, + Resources: []string{rbacapi.UsersResource, rbacapi.UserAttributeResource, rbacapi.GroupsResource, rbacapi.GroupMembersResource}, } ) diff --git a/validation/rbac/globalroles/standarduser_manage_users_template.go b/validation/rbac/globalroles/standarduser_manage_users_template.go index acea4e092..b074ffc3a 100644 --- a/validation/rbac/globalroles/standarduser_manage_users_template.go +++ b/validation/rbac/globalroles/standarduser_manage_users_template.go @@ -3,7 +3,7 @@ package globalroles import ( v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3" namegen "github.com/rancher/shepherd/pkg/namegenerator" - "github.com/rancher/tests/actions/rbac" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -16,8 +16,8 @@ func newCustomGlobalRole(verbs []string) v3.GlobalRole { }, Rules: []rbacv1.PolicyRule{ { - APIGroups: []string{rbac.ManagementAPIGroup}, - Resources: []string{rbac.UsersResource}, + APIGroups: []string{rbacapi.ManagementAPIGroup}, + Resources: []string{rbacapi.UsersResource}, Verbs: verbs, }, }, @@ -27,5 +27,5 @@ func newCustomGlobalRole(verbs []string) v3.GlobalRole { var ( customGlobalRoleDelete = newCustomGlobalRole([]string{"delete", "get", "list"}) customGlobalRoleEdit = newCustomGlobalRole([]string{"patch", "update", "get", "list"}) - customGlobalRoleManageUsers = newCustomGlobalRole([]string{rbac.ManageUsersVerb, "patch", "update", "delete", "get", "list"}) + customGlobalRoleManageUsers = newCustomGlobalRole([]string{rbacapi.ManageUsersVerb, "patch", "update", "delete", "get", "list"}) ) diff --git a/validation/rbac/globalrolesv2/globalroles_v2.go b/validation/rbac/globalrolesv2/globalroles_v2.go index 34d899c58..627a5d038 100644 --- a/validation/rbac/globalrolesv2/globalroles_v2.go +++ b/validation/rbac/globalrolesv2/globalroles_v2.go @@ -121,7 +121,7 @@ func createDownstreamCluster(client *rancher.Client, clusterType string) (*manag } func createGlobalRoleAndUser(client *rancher.Client, inheritedClusterrole []string) (*management.User, *v3.GlobalRole, error) { - gr, err := rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(client, inheritedClusterrole) + gr, err := rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(client, inheritedClusterrole) if err != nil { return nil, nil, err } diff --git a/validation/rbac/globalrolesv2/globalroles_v2_test.go b/validation/rbac/globalrolesv2/globalroles_v2_test.go index dd2b4e93c..9c5694844 100644 --- a/validation/rbac/globalrolesv2/globalroles_v2_test.go +++ b/validation/rbac/globalrolesv2/globalroles_v2_test.go @@ -62,21 +62,21 @@ func (gr *GlobalRolesV2TestSuite) validateRBACResources(createdUser *management. require.NoError(gr.T(), err) clusterCount := len(clusterNames) expectedCrtbCount := clusterCount * len(inheritedRoles) - crtbs, err := rbac.ListCRTBsByLabel(gr.client, rbac.GrbOwnerLabel, grbOwner, expectedCrtbCount) + crtbs, err := rbacapi.ListCRTBsByLabel(gr.client, rbac.GrbOwnerLabel, grbOwner, expectedCrtbCount) require.NoError(gr.T(), err) actualCrtbCount := len(crtbs.Items) require.Equal(gr.T(), expectedCrtbCount, actualCrtbCount, "Unexpected number of ClusterRoleTemplateBindings: Expected %d, Actual %d", expectedCrtbCount, actualCrtbCount) log.Info("Verify that the cluster role bindings are created for the downstream cluster.") expectedCrbCount := expectedCrtbCount - crbs, err := rbac.GetClusterRoleBindingsForCRTBs(gr.client, crtbs) + crbs, err := rbacapi.GetClusterRoleBindingsForCRTBs(gr.client, crtbs) require.NoError(gr.T(), err) actualCrbCount := len(crbs.Items) require.Equal(gr.T(), expectedCrbCount, actualCrbCount, "Unexpected number of ClusterRoleBindings: Expected %d, Actual %d", expectedCrbCount, actualCrbCount) log.Info("Verify that the role bindings are created for the downstream cluster.") expectedRbCount := expectedCrtbCount - rbs, err := rbac.GetRoleBindingsForCRTBs(gr.client, crtbs) + rbs, err := rbacapi.GetRoleBindingsForCRTBs(gr.client, crtbs) require.NoError(gr.T(), err) actualRbCount := len(rbs.Items) require.Equal(gr.T(), expectedRbCount, actualRbCount, "Unexpected number of RoleBindings: Expected %d, Actual %d", expectedRbCount, actualRbCount) @@ -89,7 +89,7 @@ func (gr *GlobalRolesV2TestSuite) TestCreateUserWithInheritedClusterRoles() { log.Info("Create a global role with inheritedClusterRoles.") inheritedClusterRoles := []string{rbac.ClusterOwner.String()} - createdGlobalRole, err := rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) + createdGlobalRole, err := rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) require.NoError(gr.T(), err) log.Info("Create a user with global role standard user and custom global role.") @@ -105,7 +105,7 @@ func (gr *GlobalRolesV2TestSuite) TestCreateUserWithMultipleInheritedClusterRole log.Info("Create a global role with inheritedClusterRoles.") inheritedClusterRoles := []string{rbac.CrtbView.String(), rbac.ProjectsCreate.String(), rbac.ProjectsView.String()} - createdGlobalRole, err := rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) + createdGlobalRole, err := rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) require.NoError(gr.T(), err) log.Info("Create a user with global role standard user and custom global role.") @@ -130,7 +130,7 @@ func (gr *GlobalRolesV2TestSuite) TestCreateUserWithInheritedCustomClusterRole() log.Info("Create a global role with inheritedClusterRoles.") inheritedClusterRoles := []string{inheritedRoleTemplate.ID} - createdGlobalRole, err := rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) + createdGlobalRole, err := rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) require.NoError(gr.T(), err) log.Info("Create a user with global role standard user and custom global role.") @@ -154,7 +154,7 @@ func (gr *GlobalRolesV2TestSuite) TestClusterCreationAfterAddingGlobalRoleWithIn log.Info("Create a global role with inheritedClusterRoles.") inheritedClusterRoles := []string{rbac.ClusterMember.String()} - createdGlobalRole, err := rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) + createdGlobalRole, err := rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) require.NoError(gr.T(), err) log.Info("Create a user with global role standard user and custom global role.") @@ -208,7 +208,7 @@ func (gr *GlobalRolesV2TestSuite) TestUpdateExistingUserWithCustomGlobalRoleInhe log.Info("Create a global role with inheritedClusterRoles.") inheritedClusterRoles := []string{rbac.ClusterOwner.String()} - createdGlobalRole, err := rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) + createdGlobalRole, err := rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) require.NoError(gr.T(), err) log.Info("Create a user with global role standard user.") @@ -224,7 +224,7 @@ func (gr *GlobalRolesV2TestSuite) TestUpdateExistingUserWithCustomGlobalRoleInhe GlobalRoleName: createdGlobalRole.Name, } - _, err = rbacapi.CreateGlobalRoleBinding(gr.client, grb) + _, err = gr.client.WranglerContext.Mgmt.GlobalRoleBinding().Create(grb) require.NoError(gr.T(), err) _, expectedClusterCount := gr.validateRBACResources(createdUser, createdGlobalRole, inheritedClusterRoles) @@ -244,7 +244,7 @@ func (gr *GlobalRolesV2TestSuite) TestUserDeletionAndResourceCleanupWithInherite log.Info("Create a global role with inheritedClusterRoles.") inheritedClusterRoles := []string{rbac.ClusterOwner.String()} - createdGlobalRole, err := rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) + createdGlobalRole, err := rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) require.NoError(gr.T(), err) log.Info("Create a user with global role standard user and custom global role.") @@ -282,19 +282,19 @@ func (gr *GlobalRolesV2TestSuite) TestUserDeletionAndResourceCleanupWithInherite log.Info("Verify that the cluster role template bindings are deleted for the downstream clusters.") expectedCrtbCount := 0 - crtbs, err := rbac.ListCRTBsByLabel(gr.client, rbac.GrbOwnerLabel, grbOwner, expectedCrtbCount) + crtbs, err := rbacapi.ListCRTBsByLabel(gr.client, rbac.GrbOwnerLabel, grbOwner, expectedCrtbCount) require.NoError(gr.T(), err) actualCrtbCount := len(crtbs.Items) require.Equal(gr.T(), expectedCrtbCount, actualCrtbCount, "Unexpected number of ClusterRoleTemplateBindings: Expected %d, Actual %d", expectedCrtbCount, actualCrtbCount) log.Info("Verify that the cluster role bindings are deleted for the downstream cluster.") - crbs, err := rbac.GetClusterRoleBindingsForCRTBs(gr.client, crtbs) + crbs, err := rbacapi.GetClusterRoleBindingsForCRTBs(gr.client, crtbs) require.NoError(gr.T(), err) actualCrbCount := len(crbs.Items) require.Equal(gr.T(), 0, actualCrbCount, "Unexpected number of ClusterRoleBindings: Expected %d, Actual %d", 0, actualCrbCount) log.Info("Verify that the role bindings are deleted for the downstream cluster.") - rbs, err := rbac.GetRoleBindingsForCRTBs(gr.client, crtbs) + rbs, err := rbacapi.GetRoleBindingsForCRTBs(gr.client, crtbs) require.NoError(gr.T(), err) actualRbCount := len(rbs.Items) require.Equal(gr.T(), 0, actualRbCount, "Unexpected number of RoleBindings: Expected %d, Actual %d", 0, actualRbCount) @@ -306,7 +306,7 @@ func (gr *GlobalRolesV2TestSuite) TestUserWithInheritedClusterRolesImpactFromDel log.Info("Create a global role with inheritedClusterRoles.") inheritedClusterRoles := []string{rbac.ClusterOwner.String()} - createdGlobalRole, err := rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) + createdGlobalRole, err := rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) require.NoError(gr.T(), err) log.Info("Create a user with global role standard user and custom global role.") @@ -342,19 +342,19 @@ func (gr *GlobalRolesV2TestSuite) TestUserWithInheritedClusterRolesImpactFromDel log.Info("Verify that the cluster role template bindings are deleted for the downstream clusters.") expectedCrtbCount := 0 - crtbs, err := rbac.ListCRTBsByLabel(gr.client, rbac.GrbOwnerLabel, grbOwner, expectedCrtbCount) + crtbs, err := rbacapi.ListCRTBsByLabel(gr.client, rbac.GrbOwnerLabel, grbOwner, expectedCrtbCount) require.NoError(gr.T(), err) actualCrtbCount := len(crtbs.Items) require.Equal(gr.T(), expectedCrtbCount, actualCrtbCount, "Unexpected number of ClusterRoleTemplateBindings: Expected %d, Actual %d", expectedCrtbCount, actualCrtbCount) log.Info("Verify that the cluster role bindings are deleted for the downstream cluster.") - crbs, err := rbac.GetClusterRoleBindingsForCRTBs(gr.client, crtbs) + crbs, err := rbacapi.GetClusterRoleBindingsForCRTBs(gr.client, crtbs) require.NoError(gr.T(), err) actualCrbCount := len(crbs.Items) require.Equal(gr.T(), 0, actualCrbCount, "Unexpected number of ClusterRoleBindings: Expected %d, Actual %d", 0, actualCrbCount) log.Info("Verify that the role bindings are deleted for the downstream cluster.") - rbs, err := rbac.GetRoleBindingsForCRTBs(gr.client, crtbs) + rbs, err := rbacapi.GetRoleBindingsForCRTBs(gr.client, crtbs) require.NoError(gr.T(), err) actualRbCount := len(rbs.Items) require.Equal(gr.T(), 0, actualRbCount, "Unexpected number of RoleBindings: Expected %d, Actual %d", 0, actualRbCount) @@ -372,7 +372,7 @@ func (gr *GlobalRolesV2TestSuite) TestUserWithInheritedClusterRolesImpactFromDel log.Info("Create a global role with inheritedClusterRoles.") inheritedClusterRoles := []string{rbac.ClusterMember.String()} - createdGlobalRole, err := rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) + createdGlobalRole, err := rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) require.NoError(gr.T(), err) log.Info("Create a user with global role standard user and custom global role.") @@ -414,19 +414,19 @@ func (gr *GlobalRolesV2TestSuite) TestUserWithInheritedClusterRolesImpactFromDel require.NotEmpty(gr.T(), grbOwner, "Global Role Binding does not exist for user %s", user.ID) log.Infof("Verify that the cluster role template bindings are deleted for user %s.", user.ID) - crtbs, err := rbac.ListCRTBsByLabel(gr.client, rbac.GrbOwnerLabel, grbOwner, 0) + crtbs, err := rbacapi.ListCRTBsByLabel(gr.client, rbac.GrbOwnerLabel, grbOwner, 0) require.NoError(gr.T(), err) actualCrtbCount := len(crtbs.Items) require.Equal(gr.T(), 0, actualCrtbCount, "Unexpected number of ClusterRoleTemplateBindings for user %s: Expected %d, Actual %d", user.ID, 0, actualCrtbCount) log.Infof("Verify that the cluster role bindings are deleted for the downstream cluster.") - crbs, err := rbac.GetClusterRoleBindingsForCRTBs(gr.client, crtbs) + crbs, err := rbacapi.GetClusterRoleBindingsForCRTBs(gr.client, crtbs) require.NoError(gr.T(), err) actualCrbCount := len(crbs.Items) require.Equal(gr.T(), 0, actualCrbCount, "Unexpected number of ClusterRoleBindings: Expected %d, Actual %d", 0, actualCrbCount) log.Info("Verify that the role bindings are deleted for the downstream cluster.") - rbs, err := rbac.GetRoleBindingsForCRTBs(gr.client, crtbs) + rbs, err := rbacapi.GetRoleBindingsForCRTBs(gr.client, crtbs) require.NoError(gr.T(), err) actualRbCount := len(rbs.Items) require.Equal(gr.T(), 0, actualRbCount, "Unexpected number of RoleBindings: Expected %d, Actual %d", 0, actualRbCount) @@ -462,7 +462,7 @@ func (gr *GlobalRolesV2TestSuite) TestUserWithInheritedClusterRolesImpactFromClu log.Info("Create a global role with inheritedClusterRoles.") inheritedClusterRoles := []string{rbac.ClusterOwner.String()} - createdGlobalRole, err := rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) + createdGlobalRole, err := rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(gr.client, inheritedClusterRoles) require.NoError(gr.T(), err) log.Info("Create a user with global role standard user and custom global role.") @@ -498,21 +498,21 @@ func (gr *GlobalRolesV2TestSuite) TestUserWithInheritedClusterRolesImpactFromClu log.Info("Verify that the cluster role template bindings are deleted for the downstream cluster.") expectedCrtbCount := actualClusterCount - 1 - crtbs, err := rbac.ListCRTBsByLabel(gr.client, rbac.GrbOwnerLabel, grbOwner, expectedCrtbCount) + crtbs, err := rbacapi.ListCRTBsByLabel(gr.client, rbac.GrbOwnerLabel, grbOwner, expectedCrtbCount) require.NoError(gr.T(), err) actualCrtbCount := len(crtbs.Items) require.Equal(gr.T(), expectedCrtbCount, actualCrtbCount, "Unexpected number of ClusterRoleTemplateBindings: Expected %d, Actual %d", expectedCrtbCount, actualCrtbCount) log.Info("Verify that the cluster role bindings are deleted for the downstream cluster.") expectedCrbCount := expectedCrtbCount - crbs, err := rbac.GetClusterRoleBindingsForCRTBs(gr.client, crtbs) + crbs, err := rbacapi.GetClusterRoleBindingsForCRTBs(gr.client, crtbs) require.NoError(gr.T(), err) actualCrbCount := len(crbs.Items) require.Equal(gr.T(), expectedCrbCount, actualCrbCount, "Unexpected number of ClusterRoleBindings: Expected %d, Actual %d", expectedCrbCount, actualCrbCount) log.Info("Verify that the role bindings are deleted for the downstream cluster.") expectedRbCount := expectedCrtbCount - rbs, err := rbac.GetRoleBindingsForCRTBs(gr.client, crtbs) + rbs, err := rbacapi.GetRoleBindingsForCRTBs(gr.client, crtbs) require.NoError(gr.T(), err) actualRbCount := len(rbs.Items) require.Equal(gr.T(), expectedRbCount, actualRbCount, "Unexpected number of RoleBindings: Expected %d, Actual %d", expectedRbCount, actualRbCount) diff --git a/validation/rbac/globalrolesv2/globalroles_v2_webhook_test.go b/validation/rbac/globalrolesv2/globalroles_v2_webhook_test.go index da103d3f3..ceb5e0cbf 100644 --- a/validation/rbac/globalrolesv2/globalroles_v2_webhook_test.go +++ b/validation/rbac/globalrolesv2/globalroles_v2_webhook_test.go @@ -59,7 +59,7 @@ func getCRTBFromGRBOwner(t *testing.T, client *rancher.Client, user *management. require.NotEmpty(t, grbOwner, "Global Role Binding not found for the user") log.Info("Verify that the cluster role template bindings are created for the downstream clusters.") - crtbList, err := rbac.ListCRTBsByLabel(client, rbac.GrbOwnerLabel, grbOwner, expectedCrtbCount) + crtbList, err := rbacapi.ListCRTBsByLabel(client, rbac.GrbOwnerLabel, grbOwner, expectedCrtbCount) return crtbList, err, grbOwner } @@ -108,16 +108,15 @@ func (grw *GlobalRolesV2WebhookTestSuite) TestRemoveOwnerLabelRejectedByWebhook( func (grw *GlobalRolesV2WebhookTestSuite) TestLockedRoleTemplateInInheritedClusterRole() { log.Info("Verify adding a locked custom cluster role template is rejected by webhook.") - roleTemplate := &v3.RoleTemplate{} roleTemplate.Name = namegen.AppendRandomString("customrole") roleTemplate.RoleTemplateNames = []string{rbac.ClusterOwner.String()} roleTemplate.Context = clusterContext roleTemplate.Locked = true - lockedRoleTemplate, err := rbacapi.CreateRoleTemplate(grw.client, roleTemplate) + lockedRoleTemplate, err := grw.client.WranglerContext.Mgmt.RoleTemplate().Create(roleTemplate) require.NoError(grw.T(), err) - _, err = rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(grw.client, []string{lockedRoleTemplate.Name}) + _, err = rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(grw.client, []string{lockedRoleTemplate.Name}) require.Error(grw.T(), err) pattern := "^failed to create global role with inherited cluster roles: admission webhook.*" + regexp.QuoteMeta(lockedRoleTemplate.Name+"\": unable to use locked roleTemplate") + "$" @@ -127,18 +126,17 @@ func (grw *GlobalRolesV2WebhookTestSuite) TestLockedRoleTemplateInInheritedClust func (grw *GlobalRolesV2WebhookTestSuite) TestAddGlobalRoleWithCustomTemplateAndLockRoleTemplate() { log.Info("Verify adding a custom cluster role template and then locking the template is not rejected by webhook.") - roleTemplate := &v3.RoleTemplate{} roleTemplate.Name = namegen.AppendRandomString("customrole") roleTemplate.RoleTemplateNames = []string{rbac.ClusterOwner.String()} roleTemplate.Context = clusterContext - customRoleTemplate, err := rbacapi.CreateRoleTemplate(grw.client, roleTemplate) + customRoleTemplate, err := grw.client.WranglerContext.Mgmt.RoleTemplate().Create(roleTemplate) require.NoError(grw.T(), err) - _, err = rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(grw.client, []string{customRoleTemplate.Name}) + _, err = rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(grw.client, []string{customRoleTemplate.Name}) require.NoError(grw.T(), err) - customRoleTemplate, err = grw.client.WranglerContext.Mgmt.RoleTemplate().Get(customRoleTemplate.Name, metav1.GetOptions{}) + customRoleTemplate, err = rbacapi.GetRoleTemplateByName(grw.client, customRoleTemplate.Name) require.NoError(grw.T(), err) customRoleTemplate.Locked = true lockCustomRoleTemplate, err := rbacapi.UpdateRoleTemplate(grw.client, customRoleTemplate) @@ -157,7 +155,7 @@ func (grw *GlobalRolesV2WebhookTestSuite) TestDeleteCustomRoleTemplateInInherite }) require.NoError(grw.T(), err) - gr, err := rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(grw.client, []string{inheritedRoleTemplate.ID}) + gr, err := rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(grw.client, []string{inheritedRoleTemplate.ID}) require.NoError(grw.T(), err) err = rbacapi.DeleteRoletemplate(grw.client, inheritedRoleTemplate.ID) @@ -177,7 +175,7 @@ func (grw *GlobalRolesV2WebhookTestSuite) TestAddProjectRoleTemplateInInheritedC }) require.NoError(grw.T(), err) - _, err = rbac.CreateGlobalRoleWithInheritedClusterRolesWrangler(grw.client, []string{inheritedRoleTemplate.ID}) + _, err = rbacapi.CreateGlobalRoleWithInheritedClusterRolesWrangler(grw.client, []string{inheritedRoleTemplate.ID}) require.Error(grw.T(), err) pattern := "admission webhook.*" + regexp.QuoteMeta("unable to bind a roleTemplate with non-cluster context: project") @@ -210,7 +208,7 @@ func (grw *GlobalRolesV2WebhookTestSuite) TestRoleTemplateWithBadUserSubject() { clusterRoleTemplateBinding.Labels = crtb.Labels clusterRoleTemplateBinding.ClusterName = crtb.ClusterName - createdCRTB, err := rbacapi.CreateClusterRoleTemplateBinding(grw.client, clusterRoleTemplateBinding) + createdCRTB, err := grw.client.WranglerContext.Mgmt.ClusterRoleTemplateBinding().Create(clusterRoleTemplateBinding) require.NoError(grw.T(), err) req, err := labels.NewRequirement(rbac.GrbOwnerLabel, selection.In, []string{grbOwner}) @@ -242,7 +240,7 @@ func (grw *GlobalRolesV2WebhookTestSuite) TestDuplicateCRTBsAreDeleted() { clusterRoleTemplateBinding.UserPrincipalName = localPrefix + user.Name clusterRoleTemplateBinding.Labels = crtb.Labels clusterRoleTemplateBinding.ClusterName = crtb.ClusterName - createdCRTB, err := rbacapi.CreateClusterRoleTemplateBinding(grw.client, clusterRoleTemplateBinding) + createdCRTB, err := grw.client.WranglerContext.Mgmt.ClusterRoleTemplateBinding().Create(clusterRoleTemplateBinding) require.NoError(grw.T(), err) req, err := labels.NewRequirement(rbac.GrbOwnerLabel, selection.In, []string{grbOwner}) @@ -283,7 +281,7 @@ func (grw *GlobalRolesV2WebhookTestSuite) TestCRTBWithLocalClusterReferenceIsDel clusterRoleTemplateBinding.Labels = crtb.Labels clusterRoleTemplateBinding.ClusterName = localcluster - createdCRTB, err := rbacapi.CreateClusterRoleTemplateBinding(grw.client, clusterRoleTemplateBinding) + createdCRTB, err := grw.client.WranglerContext.Mgmt.ClusterRoleTemplateBinding().Create(clusterRoleTemplateBinding) require.NoError(grw.T(), err) req, err := labels.NewRequirement(rbac.GrbOwnerLabel, selection.In, []string{grbOwner}) diff --git a/validation/rbac/grb/grb.go b/validation/rbac/grb/grb.go index dd86803b5..32805a2de 100644 --- a/validation/rbac/grb/grb.go +++ b/validation/rbac/grb/grb.go @@ -9,6 +9,7 @@ import ( management "github.com/rancher/shepherd/clients/rancher/generated/management/v3" "github.com/rancher/shepherd/extensions/users" namegen "github.com/rancher/shepherd/pkg/namegenerator" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/rbac" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -66,7 +67,7 @@ func createGlobalRoleAndUser(client *rancher.Client) (*v3.GlobalRole, *managemen return nil, nil, err } - createdGlobalRole, err = rbac.GetGlobalRoleByName(client, createdGlobalRole.Name) + createdGlobalRole, err = rbacapi.GetGlobalRoleByName(client, createdGlobalRole.Name) if err != nil { return nil, nil, err } diff --git a/validation/rbac/grb/grb_status_field_test.go b/validation/rbac/grb/grb_status_field_test.go index 32ce05c0a..a77f320be 100644 --- a/validation/rbac/grb/grb_status_field_test.go +++ b/validation/rbac/grb/grb_status_field_test.go @@ -14,6 +14,7 @@ import ( "github.com/rancher/shepherd/extensions/kubectl" "github.com/rancher/shepherd/extensions/users" "github.com/rancher/shepherd/pkg/session" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/rbac" "github.com/rancher/tests/actions/workloads/deployment" log "github.com/sirupsen/logrus" @@ -58,7 +59,7 @@ func (grbs *GlobalRoleBindingStatusFieldTestSuite) TestGlobalRoleBindingStatusFi require.NoError(grbs.T(), err) log.Info("Verify that the global role binding is created for the user.") - grb, err := rbac.GetGlobalRoleBindingByUserAndRole(grbs.client, createdUser.ID, createdGlobalRole.Name) + grb, err := rbacapi.GetGlobalRoleBindingByUserAndRole(grbs.client, createdUser.ID, createdGlobalRole.Name) require.NoError(grbs.T(), err) require.NotEmpty(grbs.T(), grb, "Global Role Binding not found for the user") @@ -76,7 +77,7 @@ func (grbs *GlobalRoleBindingStatusFieldTestSuite) TestGlobalRoleBindingStatusFi require.NoError(grbs.T(), err) log.Info("Verify that the global role binding is created for the user.") - grb, err := rbac.GetGlobalRoleBindingByUserAndRole(grbs.client, createdUser.ID, rbac.Admin.String()) + grb, err := rbacapi.GetGlobalRoleBindingByUserAndRole(grbs.client, createdUser.ID, rbac.Admin.String()) require.NoError(grbs.T(), err) require.NotEmpty(grbs.T(), grb, "Global Role Binding not found for the user") @@ -94,7 +95,7 @@ func (grbs *GlobalRoleBindingStatusFieldTestSuite) TestGlobalRoleBindingStatusFi require.NoError(grbs.T(), err) log.Info("Verify that the global role binding is created for the user.") - grb, err := rbac.GetGlobalRoleBindingByUserAndRole(grbs.client, createdUser.ID, createdGlobalRole.Name) + grb, err := rbacapi.GetGlobalRoleBindingByUserAndRole(grbs.client, createdUser.ID, createdGlobalRole.Name) require.NoError(grbs.T(), err) require.NotEmpty(grbs.T(), grb, "Global Role Binding not found for the user") @@ -109,7 +110,7 @@ func (grbs *GlobalRoleBindingStatusFieldTestSuite) TestGlobalRoleBindingStatusFi var updatedGrb *v3.GlobalRoleBinding err = kwait.PollUntilContextTimeout(context.TODO(), defaults.TwoMinuteTimeout, defaults.TwoMinuteTimeout, false, func(ctx context.Context) (bool, error) { var err error - updatedGrb, err = rbac.GetGlobalRoleBindingByUserAndRole(grbs.client, createdUser.ID, createdGlobalRole.Name) + updatedGrb, err = rbacapi.GetGlobalRoleBindingByUserAndRole(grbs.client, createdUser.ID, createdGlobalRole.Name) if err != nil { return false, err } @@ -145,7 +146,7 @@ func (grbs *GlobalRoleBindingStatusFieldTestSuite) TestGlobalRoleBindingStatusFi require.NoError(grbs.T(), err) log.Info("Verify that the global role binding is created for the user.") - grb, err := rbac.GetGlobalRoleBindingByUserAndRole(grbs.client, createdUser.ID, rbac.Admin.String()) + grb, err := rbacapi.GetGlobalRoleBindingByUserAndRole(grbs.client, createdUser.ID, rbac.Admin.String()) require.NoError(grbs.T(), err) require.NotEmpty(grbs.T(), grb, "Global Role Binding not found for the user") diff --git a/validation/rbac/grb/grb_upn_test.go b/validation/rbac/grb/grb_upn_test.go index 0f6713834..298d7d34d 100644 --- a/validation/rbac/grb/grb_upn_test.go +++ b/validation/rbac/grb/grb_upn_test.go @@ -59,7 +59,7 @@ func (upn *GlobalRoleBindingUserPrincipalNameTestSuite) TestCreateGlobalRoleBind log.Info("Create a globalrolebinding with userPrincipalName set") customGlobalRoleBinding.Name = namegen.AppendRandomString("testgrb") customGlobalRoleBinding.GlobalRoleName = globalRoleWithInheritedClusterMember.Name - _, err = rbacapi.CreateGlobalRoleBinding(upn.client, &customGlobalRoleBinding) + _, err = upn.client.WranglerContext.Mgmt.GlobalRoleBinding().Create(&customGlobalRoleBinding) require.NoError(upn.T(), err) log.Info("Verify user in globalrolebinding userPrincipalName field is created") @@ -83,7 +83,7 @@ func (upn *GlobalRoleBindingUserPrincipalNameTestSuite) TestGlobalRoleBindingPri customGlobalRoleBinding.Name = namegen.AppendRandomString("testgrb") customGlobalRoleBinding.GlobalRoleName = globalRoleWithInheritedClusterMember.Name customGlobalRoleBinding.Annotations[principalDisplayNameAnnotation] = testPrincipalDisplayName - createdGlobalRoleBinding, err := rbacapi.CreateGlobalRoleBinding(upn.client, &customGlobalRoleBinding) + createdGlobalRoleBinding, err := upn.client.WranglerContext.Mgmt.GlobalRoleBinding().Create(&customGlobalRoleBinding) require.NoError(upn.T(), err) require.Equal(upn.T(), testPrincipalDisplayName, createdGlobalRoleBinding.Annotations[principalDisplayNameAnnotation]) } @@ -104,7 +104,7 @@ func (upn *GlobalRoleBindingUserPrincipalNameTestSuite) TestGlobalRoleBindingUse customGlobalRoleBinding.Name = namegen.AppendRandomString("testgrb-both") customGlobalRoleBinding.GlobalRoleName = globalRoleWithInheritedClusterMember.Name customGlobalRoleBinding.GroupPrincipalName = testGroupPrincipalName - _, err = rbacapi.CreateGlobalRoleBinding(upn.client, &customGlobalRoleBinding) + _, err = upn.client.WranglerContext.Mgmt.GlobalRoleBinding().Create(&customGlobalRoleBinding) require.Error(upn.T(), err) require.Contains(upn.T(), err.Error(), "Forbidden: bindings can not set both userName/userPrincipalName and groupPrincipalName") @@ -113,7 +113,7 @@ func (upn *GlobalRoleBindingUserPrincipalNameTestSuite) TestGlobalRoleBindingUse customGlobalRoleBinding.GlobalRoleName = globalRoleWithInheritedClusterMember.Name customGlobalRoleBinding.GroupPrincipalName = testGroupPrincipalName customGlobalRoleBinding.UserName = namegen.AppendRandomString("test-username") - _, err = rbacapi.CreateGlobalRoleBinding(upn.client, &customGlobalRoleBinding) + _, err = upn.client.WranglerContext.Mgmt.GlobalRoleBinding().Create(&customGlobalRoleBinding) require.Error(upn.T(), err) require.Contains(upn.T(), err.Error(), "Forbidden: bindings can not set both userName/userPrincipalName and groupPrincipalName") } diff --git a/validation/rbac/psa/project_updatepsa_test.go b/validation/rbac/psa/project_updatepsa_test.go index 497ece98e..519870b0d 100644 --- a/validation/rbac/psa/project_updatepsa_test.go +++ b/validation/rbac/psa/project_updatepsa_test.go @@ -12,6 +12,7 @@ import ( "github.com/rancher/shepherd/pkg/session" clusterapi "github.com/rancher/tests/actions/kubeapi/clusters" namespaceapi "github.com/rancher/tests/actions/kubeapi/namespaces" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/projects" "github.com/rancher/tests/actions/rbac" log "github.com/sirupsen/logrus" @@ -122,7 +123,7 @@ func (pu *ProjectUpdatePsaTestSuite) TestCreateNamespaceWithPsaLabelsWithUpdateP log.Infof("Granting 'updatepsa' permission to user %v", newUser.Username) customRoleTemplate, err := createUpdatePSARoleTemplate(pu.client) assert.NoError(pu.T(), err) - _, err = rbac.CreateProjectRoleTemplateBinding(pu.client, newUser, adminProject, customRoleTemplate.Name) + _, err = rbacapi.CreateProjectRoleTemplateBinding(pu.client, newUser, adminProject, customRoleTemplate.Name) assert.NoError(pu.T(), err) log.Infof("As a %v, creating a namespace with PSA labels in the project %v", tt.role.String(), adminProject.Name) @@ -216,7 +217,7 @@ func (pu *ProjectUpdatePsaTestSuite) TestUpdateNamespaceWithPsaLabelsWithUpdateP log.Infof("Granting 'updatepsa' permission to user %v", newUser.Username) customRoleTemplate, err := createUpdatePSARoleTemplate(pu.client) assert.NoError(pu.T(), err) - _, err = rbac.CreateProjectRoleTemplateBinding(pu.client, newUser, adminProject, customRoleTemplate.Name) + _, err = rbacapi.CreateProjectRoleTemplateBinding(pu.client, newUser, adminProject, customRoleTemplate.Name) assert.NoError(pu.T(), err) log.Infof("As %v, updating PSA labels in namespace %v", tt.role.String(), createdNamespace.Name) @@ -252,11 +253,11 @@ func (pu *ProjectUpdatePsaTestSuite) TestCreateNamespaceWithPsaLabelsAsStandardU log.Infof("Created user: %v", newUser.Username) log.Infof("Granting 'updatepsa' permission to user %v", newUser.Username) - _, err = rbac.CreateProjectRoleTemplateBinding(pu.client, newUser, adminProject, customRoleTemplate2.Name) + _, err = rbacapi.CreateProjectRoleTemplateBinding(pu.client, newUser, adminProject, customRoleTemplate2.Name) require.NoError(pu.T(), err) log.Infof("Granting 'create namespaces' permission to user %v", newUser.Username) - _, err = rbac.CreateProjectRoleTemplateBinding(pu.client, newUser, adminProject, rbac.CreateNS.String()) + _, err = rbacapi.CreateProjectRoleTemplateBinding(pu.client, newUser, adminProject, rbac.CreateNS.String()) require.NoError(pu.T(), err) log.Infof("As user %v, create a namespace with PSA labels in project %v", newUser.Username, adminProject.Name) @@ -288,11 +289,11 @@ func (pu *ProjectUpdatePsaTestSuite) TestVerifyCreateNamespaceWithPsaLabelsWithM log.Infof("Created user: %v", newUser.Username) log.Infof("Granting 'updatepsa' permission to user %v", newUser.Username) - _, err = rbac.CreateProjectRoleTemplateBinding(pu.client, newUser, adminProject, customRoleTemplate2.Name) + _, err = rbacapi.CreateProjectRoleTemplateBinding(pu.client, newUser, adminProject, customRoleTemplate2.Name) require.NoError(pu.T(), err) log.Infof("Granting 'create namespaces' permission to user %v", newUser.Username) - _, err = rbac.CreateProjectRoleTemplateBinding(pu.client, newUser, adminProject, rbac.CreateNS.String()) + _, err = rbacapi.CreateProjectRoleTemplateBinding(pu.client, newUser, adminProject, rbac.CreateNS.String()) require.NoError(pu.T(), err) log.Infof("As user %v, create a namespace with PSA labels in project %v", newUser.Username, adminProject.Name) diff --git a/validation/rbac/psa/psa.go b/validation/rbac/psa/psa.go index 7b26048b7..4f64f4c7a 100644 --- a/validation/rbac/psa/psa.go +++ b/validation/rbac/psa/psa.go @@ -17,6 +17,7 @@ import ( extensionsworkloads "github.com/rancher/shepherd/extensions/workloads" wloads "github.com/rancher/shepherd/extensions/workloads" namegen "github.com/rancher/shepherd/pkg/namegenerator" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/namespaces" "github.com/rancher/tests/actions/rbac" appv1 "k8s.io/api/apps/v1" @@ -219,9 +220,9 @@ func generatePSALabels() map[string]string { func createUpdatePSARoleTemplate(client *rancher.Client) (*v3.RoleTemplate, error) { updatePsaRules := []rbacv1.PolicyRule{ { - Verbs: []string{rbac.UpdatePsaVerb}, - APIGroups: []string{rbac.ManagementAPIGroup}, - Resources: []string{rbac.ProjectResource}, + Verbs: []string{rbacapi.UpdatePsaVerb}, + APIGroups: []string{rbacapi.ManagementAPIGroup}, + Resources: []string{rbacapi.ProjectResource}, }, } @@ -249,7 +250,7 @@ func createUpdatePSARoleTemplate(client *rancher.Client) (*v3.RoleTemplate, erro ObjectMeta: metav1.ObjectMeta{ Name: roleTemplateName, }, - Context: rbac.ProjectContext, + Context: rbacapi.ProjectContext, Rules: updatePsaRules, DisplayName: displayName, External: false, diff --git a/validation/rbac/rbac_test.go b/validation/rbac/rbac_test.go index 879c9fa67..b81ee50a9 100644 --- a/validation/rbac/rbac_test.go +++ b/validation/rbac/rbac_test.go @@ -12,6 +12,7 @@ import ( "github.com/rancher/shepherd/extensions/users" "github.com/rancher/shepherd/pkg/config" "github.com/rancher/shepherd/pkg/session" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/projects" "github.com/rancher/tests/actions/rbac" log "github.com/sirupsen/logrus" @@ -59,10 +60,10 @@ func (rb *RBTestSuite) sequentialTestRBAC(role rbac.Role, member string, user *m if member == rbac.StandardUser.String() { if strings.Contains(role.String(), "project") { - _, err = rbac.CreateProjectRoleTemplateBinding(rb.client, user, adminProject, role.String()) + _, err = rbacapi.CreateProjectRoleTemplateBinding(rb.client, user, adminProject, role.String()) require.NoError(rb.T(), err) } else { - _, err = rbac.CreateClusterRoleTemplateBinding(rb.client, rb.cluster.ID, user, role.String()) + _, err = rbacapi.CreateClusterRoleTemplateBinding(rb.client, rb.cluster.ID, user, role.String()) require.NoError(rb.T(), err) } } diff --git a/validation/rbac/snapshotrbac/snapshot_rbac_test.go b/validation/rbac/snapshotrbac/snapshot_rbac_test.go index e532cfbfc..aaa34b048 100644 --- a/validation/rbac/snapshotrbac/snapshot_rbac_test.go +++ b/validation/rbac/snapshotrbac/snapshot_rbac_test.go @@ -11,6 +11,7 @@ import ( "github.com/rancher/shepherd/extensions/clusters" "github.com/rancher/shepherd/extensions/etcdsnapshot" "github.com/rancher/shepherd/pkg/session" + rbacapi "github.com/rancher/tests/actions/kubeapi/rbac" "github.com/rancher/tests/actions/projects" rbac "github.com/rancher/tests/actions/rbac" log "github.com/sirupsen/logrus" @@ -85,10 +86,10 @@ func (etcd *SnapshotRBACTestSuite) TestRKE2K3SSnapshotRBAC() { if tt.member == rbac.StandardUser.String() { if strings.Contains(tt.role, "project") { - _, err = rbac.CreateProjectRoleTemplateBinding(etcd.client, clusterUser, adminProject, tt.role) + _, err = rbacapi.CreateProjectRoleTemplateBinding(etcd.client, clusterUser, adminProject, tt.role) require.NoError(etcd.T(), err) } else { - _, err = rbac.CreateClusterRoleTemplateBinding(etcd.client, etcd.cluster.ID, clusterUser, tt.role) + _, err = rbacapi.CreateClusterRoleTemplateBinding(etcd.client, etcd.cluster.ID, clusterUser, tt.role) require.NoError(etcd.T(), err) } }