func (o *NewProjectOptions) Run(useNodeSelector bool) error { if _, err := o.Client.Projects().Get(o.ProjectName); err != nil { if !kerrors.IsNotFound(err) { return err } } else { return fmt.Errorf("project %v already exists", o.ProjectName) } project := &projectapi.Project{} project.Name = o.ProjectName project.Annotations = make(map[string]string) project.Annotations[projectapi.ProjectDescription] = o.Description project.Annotations[projectapi.ProjectDisplayName] = o.DisplayName if useNodeSelector { project.Annotations[projectapi.ProjectNodeSelector] = o.NodeSelector } project, err := o.Client.Projects().Create(project) if err != nil { return err } fmt.Printf("Created project %v\n", o.ProjectName) errs := []error{} if len(o.AdminUser) != 0 { adduser := &policy.RoleModificationOptions{ RoleName: o.AdminRole, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(project.Name, o.Client), Users: []string{o.AdminUser}, } if err := adduser.AddRole(); err != nil { fmt.Printf("%v could not be added to the %v role: %v\n", o.AdminUser, o.AdminRole, err) errs = append(errs, err) } } for _, binding := range bootstrappolicy.GetBootstrapServiceAccountProjectRoleBindings(o.ProjectName) { addRole := &policy.RoleModificationOptions{ RoleName: binding.RoleRef.Name, RoleNamespace: binding.RoleRef.Namespace, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(o.ProjectName, o.Client), Users: binding.Users.List(), Groups: binding.Groups.List(), } if err := addRole.AddRole(); err != nil { fmt.Printf("Could not add service accounts to the %v role: %v\n", binding.RoleRef.Name, err) errs = append(errs, err) } } return errorsutil.NewAggregate(errs) }
// ensureNamespaceServiceAccountRoleBindings initializes roles for service accounts in the namespace func (c *MasterConfig) ensureNamespaceServiceAccountRoleBindings(namespace *kapi.Namespace) { const ServiceAccountRolesInitializedAnnotation = "openshift.io/sa.initialized-roles" // Short-circuit if we're already initialized if namespace.Annotations[ServiceAccountRolesInitializedAnnotation] == "true" { return } hasErrors := false for _, binding := range bootstrappolicy.GetBootstrapServiceAccountProjectRoleBindings(namespace.Name) { addRole := &policy.RoleModificationOptions{ RoleName: binding.RoleRef.Name, RoleNamespace: binding.RoleRef.Namespace, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(namespace.Name, c.ServiceAccountRoleBindingClient()), Subjects: binding.Subjects, } if err := addRole.AddRole(); err != nil { glog.Errorf("Could not add service accounts to the %v role in the %q namespace: %v\n", binding.RoleRef.Name, namespace.Name, err) hasErrors = true } } // If we had errors, don't register initialization so we can try again if hasErrors { return } if namespace.Annotations == nil { namespace.Annotations = map[string]string{} } namespace.Annotations[ServiceAccountRolesInitializedAnnotation] = "true" if _, err := c.KubeClient().Namespaces().Update(namespace); err != nil { glog.Errorf("Error recording adding service account roles to %q namespace: %v", namespace.Name, err) } }
func setupBuildStrategyTest(t *testing.T) (clusterAdminClient, projectAdminClient, projectEditorClient *client.Client) { namespace := testutil.Namespace() _, clusterAdminKubeConfig, err := testserver.StartTestMaster() if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClient, err = testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } projectAdminClient, err = testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, namespace, "harold") if err != nil { t.Fatalf("unexpected error: %v", err) } projectEditorClient, _, _, err = testutil.GetClientForUser(*clusterAdminClientConfig, "joe") if err != nil { t.Fatalf("unexpected error: %v", err) } addJoe := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.EditRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(namespace, projectAdminClient), Users: []string{"joe"}, } if err := addJoe.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } if err := testutil.WaitForPolicyUpdate(projectEditorClient, namespace, "create", authorizationapi.DockerBuildResource, true); err != nil { t.Fatalf(err.Error()) } // Create builder image stream and tag imageStream := &imageapi.ImageStream{} imageStream.Name = "builderimage" _, err = clusterAdminClient.ImageStreams(testutil.Namespace()).Create(imageStream) if err != nil { t.Fatalf("Couldn't create ImageStream: %v", err) } // Create image stream mapping imageStreamMapping := &imageapi.ImageStreamMapping{} imageStreamMapping.Name = "builderimage" imageStreamMapping.Tag = "latest" imageStreamMapping.Image.Name = "image-id" imageStreamMapping.Image.DockerImageReference = "test/builderimage:latest" err = clusterAdminClient.ImageStreamMappings(testutil.Namespace()).Create(imageStreamMapping) if err != nil { t.Fatalf("Couldn't create ImageStreamMapping: %v", err) } return }
// ensureDefaultNamespaceServiceAccountRoles initializes roles for service accounts in the default namespace func (c *MasterConfig) ensureDefaultNamespaceServiceAccountRoles() { const ServiceAccountRolesInitializedAnnotation = "openshift.io/sa.initialized-roles" // Wait for the default namespace var defaultNamespace *kapi.Namespace for i := 0; i < 30; i++ { ns, err := c.KubeClient().Namespaces().Get(kapi.NamespaceDefault) if err == nil { defaultNamespace = ns break } if kapierror.IsNotFound(err) { time.Sleep(time.Second) continue } glog.Errorf("Error adding service account roles to default namespace: %v", err) return } if defaultNamespace == nil { glog.Errorf("Default namespace not found, could not initialize default service account roles") return } // Short-circuit if we're already initialized if defaultNamespace.Annotations[ServiceAccountRolesInitializedAnnotation] == "true" { return } hasErrors := false for _, binding := range bootstrappolicy.GetBootstrapServiceAccountProjectRoleBindings(kapi.NamespaceDefault) { addRole := &policy.RoleModificationOptions{ RoleName: binding.RoleRef.Name, RoleNamespace: binding.RoleRef.Namespace, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(kapi.NamespaceDefault, c.ServiceAccountRoleBindingClient()), Users: binding.Users.List(), Groups: binding.Groups.List(), } if err := addRole.AddRole(); err != nil { glog.Errorf("Could not add service accounts to the %v role in the %v namespace: %v\n", binding.RoleRef.Name, kapi.NamespaceDefault, err) hasErrors = true } } // If we had errors, don't register initialization so we can try again if !hasErrors { if defaultNamespace.Annotations == nil { defaultNamespace.Annotations = map[string]string{} } defaultNamespace.Annotations[ServiceAccountRolesInitializedAnnotation] = "true" if _, err := c.KubeClient().Namespaces().Update(defaultNamespace); err != nil { glog.Errorf("Error recording adding service account roles to default namespace: %v", err) } } }
// simulates: oadm policy add-cluster-role-to-user roleName userName func addClusterRoleToUser(c *oclient.Client, f *cmdutil.Factory, roleName string, userName string) error { namespace, _, err := f.DefaultNamespace() if err != nil { util.Info("No namespace!'\n") return err } options := policy.RoleModificationOptions{ RoleName: roleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(namespace, c), Users: []string{userName}, } return options.AddRole() }
func AddRoleToServiceAccount(osClient client.Interface, role, sa, namespace string) error { roleBindingAccessor := policy.NewLocalRoleBindingAccessor(namespace, osClient) addRole := policy.RoleModificationOptions{ RoleName: role, RoleBindingAccessor: roleBindingAccessor, Subjects: []kapi.ObjectReference{ { Namespace: namespace, Name: sa, Kind: "ServiceAccount", }, }, } return addRole.AddRole() }
func addRoleToE2EServiceAccounts(c *client.Client, namespaces []kapi.Namespace, roleName string) { err := kclient.RetryOnConflict(kclient.DefaultRetry, func() error { for _, ns := range namespaces { if strings.HasPrefix(ns.Name, "e2e-") && ns.Status.Phase != kapi.NamespaceTerminating { sa := fmt.Sprintf("system:serviceaccount:%s:default", ns.Name) addRole := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: roleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(ns.Name, c), Users: []string{sa}, } if err := addRole.AddRole(); err != nil { e2e.Logf("Warning: Failed to add role to e2e service account: %v", err) } } } return nil }) if err != nil { FatalErr(err) } }
func TestProjectWatch(t *testing.T) { testutil.RequireEtcd(t) defer testutil.DumpEtcdOnFailure(t) _, clusterAdminKubeConfig, err := testserver.StartTestMaster() if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } bobClient, _, _, err := testutil.GetClientForUser(*clusterAdminClientConfig, "bob") if err != nil { t.Fatalf("unexpected error: %v", err) } w, err := bobClient.Projects().Watch(kapi.ListOptions{}) if err != nil { t.Fatalf("unexpected error: %v", err) } if _, err := testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "ns-01", "bob"); err != nil { t.Fatalf("unexpected error: %v", err) } waitForAdd("ns-01", w, t) // TEST FOR ADD/REMOVE ACCESS joeClient, err := testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "ns-02", "joe") if err != nil { t.Fatalf("unexpected error: %v", err) } addBob := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.EditRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor("ns-02", joeClient), Users: []string{"bob"}, } if err := addBob.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } waitForAdd("ns-02", w, t) if err := addBob.RemoveRole(); err != nil { t.Fatalf("unexpected error: %v", err) } waitForDelete("ns-02", w, t) // TEST FOR DELETE PROJECT if _, err := testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "ns-03", "bob"); err != nil { t.Fatalf("unexpected error: %v", err) } waitForAdd("ns-03", w, t) if err := bobClient.Projects().Delete("ns-03"); err != nil { t.Fatalf("unexpected error: %v", err) } // wait for the delete waitForDelete("ns-03", w, t) // test the "start from beginning watch" beginningWatch, err := bobClient.Projects().Watch(kapi.ListOptions{ResourceVersion: "0"}) if err != nil { t.Fatalf("unexpected error: %v", err) } waitForAdd("ns-01", beginningWatch, t) fromNowWatch, err := bobClient.Projects().Watch(kapi.ListOptions{}) if err != nil { t.Fatalf("unexpected error: %v", err) } select { case event := <-fromNowWatch.ResultChan(): t.Fatalf("unexpected event %v", event) case <-time.After(3 * time.Second): } }
func TestAuthorizationSubjectAccessReview(t *testing.T) { _, clusterAdminKubeConfig, err := testserver.StartTestMaster() if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } haroldClient, err := testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "hammer-project", "harold") if err != nil { t.Fatalf("unexpected error: %v", err) } markClient, err := testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "mallet-project", "mark") if err != nil { t.Fatalf("unexpected error: %v", err) } dannyClient, _, dannyConfig, err := testutil.GetClientForUser(*clusterAdminClientConfig, "danny") if err != nil { t.Fatalf("error requesting token: %v", err) } addDanny := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.ViewRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor("default", clusterAdminClient), Users: []string{"danny"}, } if err := addDanny.AddRole(); err != nil { t.Errorf("unexpected error: %v", err) } askCanDannyGetProject := &authorizationapi.SubjectAccessReview{ User: "******", Action: authorizationapi.AuthorizationAttributes{Verb: "get", Resource: "projects"}, } subjectAccessReviewTest{ description: "cluster admin told danny can get project default", localInterface: clusterAdminClient.LocalSubjectAccessReviews("default"), localReview: &authorizationapi.LocalSubjectAccessReview{ User: "******", Action: authorizationapi.AuthorizationAttributes{Verb: "get", Resource: "projects"}, }, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: true, Reason: "allowed by rule in default", Namespace: "default", }, }.run(t) subjectAccessReviewTest{ description: "cluster admin told danny cannot get projects cluster-wide", clusterInterface: clusterAdminClient.SubjectAccessReviews(), clusterReview: askCanDannyGetProject, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: false, Reason: `User "danny" cannot get projects at the cluster scope`, Namespace: "", }, }.run(t) subjectAccessReviewTest{ description: "as danny, can I make cluster subject access reviews", clusterInterface: dannyClient.SubjectAccessReviews(), clusterReview: askCanDannyGetProject, err: `User "danny" cannot create subjectaccessreviews at the cluster scope`, }.run(t) addValerie := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.ViewRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor("hammer-project", haroldClient), Users: []string{"valerie"}, } if err := addValerie.AddRole(); err != nil { t.Errorf("unexpected error: %v", err) } addEdgar := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.EditRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor("mallet-project", markClient), Users: []string{"edgar"}, } if err := addEdgar.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } askCanValerieGetProject := &authorizationapi.LocalSubjectAccessReview{ User: "******", Action: authorizationapi.AuthorizationAttributes{Verb: "get", Resource: "projects"}, } subjectAccessReviewTest{ description: "harold told valerie can get project hammer-project", localInterface: haroldClient.LocalSubjectAccessReviews("hammer-project"), localReview: askCanValerieGetProject, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: true, Reason: "allowed by rule in hammer-project", Namespace: "hammer-project", }, }.run(t) subjectAccessReviewTest{ description: "mark told valerie cannot get project mallet-project", localInterface: markClient.LocalSubjectAccessReviews("mallet-project"), localReview: askCanValerieGetProject, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: false, Reason: `User "valerie" cannot get projects in project "mallet-project"`, Namespace: "mallet-project", }, }.run(t) askCanEdgarDeletePods := &authorizationapi.LocalSubjectAccessReview{ User: "******", Action: authorizationapi.AuthorizationAttributes{Verb: "delete", Resource: "pods"}, } subjectAccessReviewTest{ description: "mark told edgar can delete pods in mallet-project", localInterface: markClient.LocalSubjectAccessReviews("mallet-project"), localReview: askCanEdgarDeletePods, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: true, Reason: "allowed by rule in mallet-project", Namespace: "mallet-project", }, }.run(t) subjectAccessReviewTest{ description: "harold denied ability to run subject access review in project mallet-project", localInterface: haroldClient.LocalSubjectAccessReviews("mallet-project"), localReview: askCanEdgarDeletePods, err: `User "harold" cannot create localsubjectaccessreviews in project "mallet-project"`, }.run(t) askCanHaroldUpdateProject := &authorizationapi.LocalSubjectAccessReview{ User: "******", Action: authorizationapi.AuthorizationAttributes{Verb: "update", Resource: "projects"}, } subjectAccessReviewTest{ description: "harold told harold can update project hammer-project", localInterface: haroldClient.LocalSubjectAccessReviews("hammer-project"), localReview: askCanHaroldUpdateProject, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: true, Reason: "allowed by rule in hammer-project", Namespace: "hammer-project", }, }.run(t) askCanClusterAdminsCreateProject := &authorizationapi.SubjectAccessReview{ Groups: sets.NewString("system:cluster-admins"), Action: authorizationapi.AuthorizationAttributes{Verb: "create", Resource: "projects"}, } subjectAccessReviewTest{ description: "cluster admin told cluster admins can create projects", clusterInterface: clusterAdminClient.SubjectAccessReviews(), clusterReview: askCanClusterAdminsCreateProject, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: true, Reason: "allowed by cluster rule", Namespace: "", }, }.run(t) subjectAccessReviewTest{ description: "harold denied ability to run cluster subject access review", clusterInterface: haroldClient.SubjectAccessReviews(), clusterReview: askCanClusterAdminsCreateProject, err: `User "harold" cannot create subjectaccessreviews at the cluster scope`, }.run(t) askCanICreatePods := &authorizationapi.LocalSubjectAccessReview{ Action: authorizationapi.AuthorizationAttributes{Verb: "create", Resource: "pods"}, } subjectAccessReviewTest{ description: "harold told he can create pods in project hammer-project", localInterface: haroldClient.LocalSubjectAccessReviews("hammer-project"), localReview: askCanICreatePods, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: true, Reason: "allowed by rule in hammer-project", Namespace: "hammer-project", }, }.run(t) askCanICreatePolicyBindings := &authorizationapi.LocalSubjectAccessReview{ Action: authorizationapi.AuthorizationAttributes{Verb: "create", Resource: "policybindings"}, } subjectAccessReviewTest{ description: "harold told he can create policybindings in project hammer-project", localInterface: haroldClient.LocalSubjectAccessReviews("hammer-project"), localReview: askCanICreatePolicyBindings, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: false, Reason: `User "harold" cannot create policybindings in project "hammer-project"`, Namespace: "hammer-project", }, }.run(t) // impersonate SAR tests // impersonated empty token SAR shouldn't be allowed at all // impersonated danny token SAR shouldn't be allowed to see pods in hammer or in cluster // impersonated danny token SAR should be allowed to see pods in default // we need a token client for overriding if err != nil { t.Fatalf("unexpected error: %v", err) } otherAdminClient, _, _, err := testutil.GetClientForUser(*clusterAdminClientConfig, "other-admin") if err != nil { t.Fatalf("error requesting token: %v", err) } addOtherAdmin := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.ClusterAdminRoleName, RoleBindingAccessor: policy.NewClusterRoleBindingAccessor(clusterAdminClient), Users: []string{"other-admin"}, } if err := addOtherAdmin.AddRole(); err != nil { t.Errorf("unexpected error: %v", err) } subjectAccessReviewTest{ description: "empty token impersonate can't see pods in namespace", localInterface: otherAdminClient.ImpersonateLocalSubjectAccessReviews("hammer-project", ""), localReview: &authorizationapi.LocalSubjectAccessReview{ Action: authorizationapi.AuthorizationAttributes{Verb: "list", Resource: "pods"}, }, err: `impersonating token may not be empty`, }.run(t) subjectAccessReviewTest{ description: "empty token impersonate can't see pods in cluster", clusterInterface: otherAdminClient.ImpersonateSubjectAccessReviews(""), clusterReview: &authorizationapi.SubjectAccessReview{ Action: authorizationapi.AuthorizationAttributes{Verb: "list", Resource: "pods"}, }, err: `impersonating token may not be empty`, }.run(t) subjectAccessReviewTest{ description: "danny impersonate can't see pods in hammer namespace", localInterface: otherAdminClient.ImpersonateLocalSubjectAccessReviews("hammer-project", dannyConfig.BearerToken), localReview: &authorizationapi.LocalSubjectAccessReview{ Action: authorizationapi.AuthorizationAttributes{Verb: "list", Resource: "pods"}, }, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: false, Reason: `User "danny" cannot list pods in project "hammer-project"`, Namespace: "hammer-project", }, }.run(t) subjectAccessReviewTest{ description: "danny impersonate can't see pods in cluster", clusterInterface: otherAdminClient.ImpersonateSubjectAccessReviews(dannyConfig.BearerToken), clusterReview: &authorizationapi.SubjectAccessReview{ Action: authorizationapi.AuthorizationAttributes{Verb: "list", Resource: "pods"}, }, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: false, Reason: `User "danny" cannot list all pods in the cluster`, }, }.run(t) subjectAccessReviewTest{ description: "danny impersonate can see pods in default", localInterface: otherAdminClient.ImpersonateLocalSubjectAccessReviews("default", dannyConfig.BearerToken), localReview: &authorizationapi.LocalSubjectAccessReview{ Action: authorizationapi.AuthorizationAttributes{Verb: "list", Resource: "pods"}, }, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: true, Reason: `allowed by rule in default`, Namespace: "default", }, }.run(t) }
func setupBuildStrategyTest(t *testing.T, includeControllers bool) (clusterAdminClient, projectAdminClient, projectEditorClient *client.Client) { testutil.RequireEtcd(t) namespace := testutil.Namespace() var clusterAdminKubeConfig string var err error if includeControllers { _, clusterAdminKubeConfig, err = testserver.StartTestMaster() } else { _, clusterAdminKubeConfig, err = testserver.StartTestMasterAPI() } if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClient, err = testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } projectAdminClient, err = testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, namespace, "harold") if err != nil { t.Fatalf("unexpected error: %v", err) } projectEditorClient, _, _, err = testutil.GetClientForUser(*clusterAdminClientConfig, "joe") if err != nil { t.Fatalf("unexpected error: %v", err) } addJoe := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.EditRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(namespace, projectAdminClient), Users: []string{"joe"}, } if err := addJoe.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } if err := testutil.WaitForPolicyUpdate(projectEditorClient, namespace, "create", buildapi.Resource(authorizationapi.DockerBuildResource), true); err != nil { t.Fatalf(err.Error()) } // Create builder image stream and tag imageStream := &imageapi.ImageStream{} imageStream.Name = "builderimage" _, err = clusterAdminClient.ImageStreams(testutil.Namespace()).Create(imageStream) if err != nil { t.Fatalf("Couldn't create ImageStream: %v", err) } // Create image stream mapping imageStreamMapping := &imageapi.ImageStreamMapping{} imageStreamMapping.Name = "builderimage" imageStreamMapping.Tag = "latest" imageStreamMapping.Image.Name = "image-id" imageStreamMapping.Image.DockerImageReference = "test/builderimage:latest" err = clusterAdminClient.ImageStreamMappings(testutil.Namespace()).Create(imageStreamMapping) if err != nil { t.Fatalf("Couldn't create ImageStreamMapping: %v", err) } template, err := testutil.GetTemplateFixture("../../examples/jenkins/jenkins-ephemeral-template.json") if err != nil { t.Fatalf("unexpected error: %v", err) } template.Name = "jenkins" template.Namespace = "openshift" _, err = clusterAdminClient.Templates("openshift").Create(template) if err != nil { t.Fatalf("Couldn't create jenkins template: %v", err) } return }
func TestAuthorizationResourceAccessReview(t *testing.T) { testutil.RequireEtcd(t) defer testutil.DumpEtcdOnFailure(t) _, clusterAdminKubeConfig, err := testserver.StartTestMasterAPI() if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } haroldClient, err := testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "hammer-project", "harold") if err != nil { t.Fatalf("unexpected error: %v", err) } markClient, err := testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "mallet-project", "mark") if err != nil { t.Fatalf("unexpected error: %v", err) } addValerie := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.ViewRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor("hammer-project", haroldClient), Users: []string{"valerie"}, } if err := addValerie.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } addEdgar := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.EditRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor("mallet-project", markClient), Users: []string{"edgar"}, } if err := addEdgar.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } requestWhoCanViewDeploymentConfigs := &authorizationapi.ResourceAccessReview{ Action: authorizationapi.Action{Verb: "get", Resource: "deploymentconfigs"}, } localRequestWhoCanViewDeploymentConfigs := &authorizationapi.LocalResourceAccessReview{ Action: authorizationapi.Action{Verb: "get", Resource: "deploymentconfigs"}, } { test := localResourceAccessReviewTest{ description: "who can view deploymentconfigs in hammer by harold", clientInterface: haroldClient.LocalResourceAccessReviews("hammer-project"), review: localRequestWhoCanViewDeploymentConfigs, response: authorizationapi.ResourceAccessReviewResponse{ Users: sets.NewString("harold", "valerie"), Groups: sets.NewString(), Namespace: "hammer-project", }, } test.response.Users.Insert(globalClusterReaderUsers.List()...) test.response.Groups.Insert(globalClusterReaderGroups.List()...) test.run(t) } { test := localResourceAccessReviewTest{ description: "who can view deploymentconfigs in mallet by mark", clientInterface: markClient.LocalResourceAccessReviews("mallet-project"), review: localRequestWhoCanViewDeploymentConfigs, response: authorizationapi.ResourceAccessReviewResponse{ Users: sets.NewString("mark", "edgar"), Groups: sets.NewString(), Namespace: "mallet-project", }, } test.response.Users.Insert(globalClusterReaderUsers.List()...) test.response.Groups.Insert(globalClusterReaderGroups.List()...) test.run(t) } // mark should not be able to make global access review requests { test := resourceAccessReviewTest{ description: "who can view deploymentconfigs in all by mark", clientInterface: markClient.ResourceAccessReviews(), review: requestWhoCanViewDeploymentConfigs, err: "cannot ", } test.run(t) } // a cluster-admin should be able to make global access review requests { test := resourceAccessReviewTest{ description: "who can view deploymentconfigs in all by cluster-admin", clientInterface: clusterAdminClient.ResourceAccessReviews(), review: requestWhoCanViewDeploymentConfigs, response: authorizationapi.ResourceAccessReviewResponse{ Users: sets.NewString(), Groups: sets.NewString(), }, } test.response.Users.Insert(globalClusterReaderUsers.List()...) test.response.Groups.Insert(globalClusterReaderGroups.List()...) test.run(t) } { if err := clusterAdminClient.ClusterRoles().Delete(bootstrappolicy.AdminRoleName); err != nil { t.Errorf("unexpected error: %v", err) } test := localResourceAccessReviewTest{ description: "who can view deploymentconfigs in mallet by cluster-admin", clientInterface: clusterAdminClient.LocalResourceAccessReviews("mallet-project"), review: localRequestWhoCanViewDeploymentConfigs, response: authorizationapi.ResourceAccessReviewResponse{ Users: sets.NewString("edgar"), Groups: sets.NewString(), Namespace: "mallet-project", EvaluationError: `role "admin" not found`, }, } test.response.Users.Insert(globalClusterReaderUsers.List()...) test.response.Groups.Insert(globalClusterReaderGroups.List()...) test.run(t) } }
func setupBuildStrategyTest(t *testing.T, includeControllers bool) (clusterAdminClient, projectAdminClient, projectEditorClient *client.Client) { testutil.RequireEtcd(t) namespace := testutil.Namespace() var clusterAdminKubeConfig string var err error if includeControllers { _, clusterAdminKubeConfig, err = testserver.StartTestMaster() } else { _, clusterAdminKubeConfig, err = testserver.StartTestMasterAPI() } if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClient, err = testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } projectAdminClient, err = testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, namespace, "harold") if err != nil { t.Fatalf("unexpected error: %v", err) } projectEditorClient, _, _, err = testutil.GetClientForUser(*clusterAdminClientConfig, "joe") if err != nil { t.Fatalf("unexpected error: %v", err) } addJoe := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.EditRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(namespace, projectAdminClient), Users: []string{"joe"}, } if err := addJoe.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } if err := testutil.WaitForPolicyUpdate(projectEditorClient, namespace, "create", buildapi.Resource(authorizationapi.DockerBuildResource), true); err != nil { t.Fatalf(err.Error()) } // we need a template that doesn't create service accounts or rolebindings so editors can create // pipeline buildconfig's successfully, so we're not using the standard jenkins template. // but we do need a template that creates a service named jenkins. template, err := testutil.GetTemplateFixture("../../examples/jenkins/master-slave/jenkins-master-template.json") if err != nil { t.Fatalf("unexpected error: %v", err) } // pipeline defaults expect to find a template named jenkins-ephemeral // in the openshift namespace. template.Name = "jenkins-ephemeral" template.Namespace = "openshift" _, err = clusterAdminClient.Templates("openshift").Create(template) if err != nil { t.Fatalf("Couldn't create jenkins template: %v", err) } return }
func TestPolicyBasedRestrictionOfBuildStrategies(t *testing.T) { const namespace = "hammer" _, clusterAdminKubeConfig, err := testutil.StartTestMaster() if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } haroldClient, err := testutil.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, namespace, "harold") if err != nil { t.Fatalf("unexpected error: %v", err) } joeClient, err := testutil.GetClientForUser(*clusterAdminClientConfig, "joe") if err != nil { t.Fatalf("unexpected error: %v", err) } addJoe := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.EditRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(namespace, haroldClient), Users: []string{"joe"}, } if err := addJoe.AddRole(); err != nil { t.Errorf("unexpected error: %v", err) } if err := testutil.WaitForPolicyUpdate(joeClient, namespace, "create", authorizationapi.DockerBuildResource, true); err != nil { t.Error(err) } // by default admins and editors can create all type of builds _, err = createDockerBuild(t, haroldClient.Builds(namespace)) if err != nil { t.Errorf("unexpected error: %v", err) } _, err = createDockerBuild(t, joeClient.Builds(namespace)) if err != nil { t.Errorf("unexpected error: %v", err) } _, err = createSourceBuild(t, haroldClient.Builds(namespace)) if err != nil { t.Errorf("unexpected error: %v", err) } _, err = createSourceBuild(t, joeClient.Builds(namespace)) if err != nil { t.Errorf("unexpected error: %v", err) } _, err = createCustomBuild(t, haroldClient.Builds(namespace)) if err != nil { t.Errorf("unexpected error: %v", err) } _, err = createCustomBuild(t, joeClient.Builds(namespace)) if err != nil { t.Errorf("unexpected error: %v", err) } // remove resources from role so that certain build strategies are forbidden removeBuildStrategyPrivileges(t, clusterAdminClient.ClusterRoles(), bootstrappolicy.EditRoleName) if err := testutil.WaitForPolicyUpdate(joeClient, namespace, "create", authorizationapi.DockerBuildResource, false); err != nil { t.Error(err) } removeBuildStrategyPrivileges(t, clusterAdminClient.ClusterRoles(), bootstrappolicy.AdminRoleName) if err := testutil.WaitForPolicyUpdate(haroldClient, namespace, "create", authorizationapi.DockerBuildResource, false); err != nil { t.Error(err) } // make sure builds are rejected if _, err = createDockerBuild(t, haroldClient.Builds(namespace)); !kapierror.IsForbidden(err) { t.Errorf("expected forbidden, got %v", err) } if _, err = createDockerBuild(t, joeClient.Builds(namespace)); !kapierror.IsForbidden(err) { t.Errorf("expected forbidden, got %v", err) } if _, err = createSourceBuild(t, haroldClient.Builds(namespace)); !kapierror.IsForbidden(err) { t.Errorf("expected forbidden, got %v", err) } if _, err = createSourceBuild(t, joeClient.Builds(namespace)); !kapierror.IsForbidden(err) { t.Errorf("expected forbidden, got %v", err) } if _, err = createCustomBuild(t, haroldClient.Builds(namespace)); !kapierror.IsForbidden(err) { t.Errorf("expected forbidden, got %v", err) } if _, err = createCustomBuild(t, joeClient.Builds(namespace)); !kapierror.IsForbidden(err) { t.Errorf("expected forbidden, got %v", err) } }
// InstallMetrics checks whether metrics is installed and installs it if not already installed func (h *Helper) InstallMetrics(f *clientcmd.Factory, hostName, imagePrefix, imageVersion string) error { osClient, kubeClient, err := f.Clients() if err != nil { return errors.NewError("cannot obtain API clients").WithCause(err).WithDetails(h.OriginLog()) } _, err = kubeClient.Services(infraNamespace).Get(svcMetrics) if err == nil { // If there's no error, the metrics service already exists return nil } if !apierrors.IsNotFound(err) { return errors.NewError("error retrieving metrics service").WithCause(err).WithDetails(h.OriginLog()) } // Create metrics deployer service account routerSA := &kapi.ServiceAccount{} routerSA.Name = metricsDeployerSA _, err = kubeClient.ServiceAccounts(infraNamespace).Create(routerSA) if err != nil { return errors.NewError("cannot create metrics deployer service account").WithCause(err).WithDetails(h.OriginLog()) } // Add edit role to deployer service account roleBindingAccessor := policy.NewLocalRoleBindingAccessor(infraNamespace, osClient) addEditRole := policy.RoleModificationOptions{ RoleName: "edit", RoleBindingAccessor: roleBindingAccessor, Subjects: []kapi.ObjectReference{ { Namespace: infraNamespace, Name: metricsDeployerSA, Kind: "ServiceAccount", }, }, } if err = addEditRole.AddRole(); err != nil { return errors.NewError("cannot add edit role to metrics deployer service account").WithCause(err).WithDetails(h.OriginLog()) } // Add cluster reader role to heapster service account clusterRoleBindingAccessor := policy.NewClusterRoleBindingAccessor(osClient) addClusterReaderRole := policy.RoleModificationOptions{ RoleName: "cluster-reader", RoleBindingAccessor: clusterRoleBindingAccessor, Users: []string{"system:serviceaccount:openshift-infra:heapster"}, } if err = addClusterReaderRole.AddRole(); err != nil { return errors.NewError("cannot add cluster reader role to heapster service account").WithCause(err).WithDetails(h.OriginLog()) } // Create metrics deployer secret deployerSecret := &kapi.Secret{} deployerSecret.Name = metricsDeployerSecret deployerSecret.Data = map[string][]byte{"nothing": []byte("/dev/null")} if _, err = kubeClient.Secrets(infraNamespace).Create(deployerSecret); err != nil { return errors.NewError("cannot create metrics deployer secret").WithCause(err).WithDetails(h.OriginLog()) } // Create deployer Pod deployerPod := metricsDeployerPod(hostName, imagePrefix, imageVersion) if _, err = kubeClient.Pods(infraNamespace).Create(deployerPod); err != nil { return errors.NewError("cannot create metrics deployer pod").WithCause(err).WithDetails(h.OriginLog()) } return nil }
func TestAuthorizationResourceAccessReview(t *testing.T) { _, clusterAdminKubeConfig, err := testutil.StartTestMaster() if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } haroldClient, err := testutil.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "hammer-project", "harold") if err != nil { t.Fatalf("unexpected error: %v", err) } markClient, err := testutil.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "mallet-project", "mark") if err != nil { t.Fatalf("unexpected error: %v", err) } addValerie := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.ViewRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor("hammer-project", haroldClient), Users: []string{"valerie"}, } if err := addValerie.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } addEdgar := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.EditRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor("mallet-project", markClient), Users: []string{"edgar"}, } if err := addEdgar.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } requestWhoCanViewDeployments := &authorizationapi.ResourceAccessReview{Verb: "get", Resource: "deployments"} { test := resourceAccessReviewTest{ clientInterface: haroldClient.ResourceAccessReviews("hammer-project"), review: requestWhoCanViewDeployments, response: authorizationapi.ResourceAccessReviewResponse{ Users: util.NewStringSet("harold", "valerie"), Groups: globalClusterAdminGroups, Namespace: "hammer-project", }, } test.response.Users.Insert(globalClusterAdminUsers.List()...) test.response.Groups.Insert("system:cluster-readers") test.run(t) } { test := resourceAccessReviewTest{ clientInterface: markClient.ResourceAccessReviews("mallet-project"), review: requestWhoCanViewDeployments, response: authorizationapi.ResourceAccessReviewResponse{ Users: util.NewStringSet("mark", "edgar"), Groups: globalClusterAdminGroups, Namespace: "mallet-project", }, } test.response.Users.Insert(globalClusterAdminUsers.List()...) test.response.Groups.Insert("system:cluster-readers") test.run(t) } // mark should not be able to make global access review requests { test := resourceAccessReviewTest{ clientInterface: markClient.ClusterResourceAccessReviews(), review: requestWhoCanViewDeployments, err: "cannot ", } test.run(t) } // a cluster-admin should be able to make global access review requests { test := resourceAccessReviewTest{ clientInterface: clusterAdminClient.ClusterResourceAccessReviews(), review: requestWhoCanViewDeployments, response: authorizationapi.ResourceAccessReviewResponse{ Users: globalClusterAdminUsers, Groups: globalClusterAdminGroups, }, } test.response.Groups.Insert("system:cluster-readers") test.run(t) } }
func TestProjectWatch(t *testing.T) { testutil.RequireEtcd(t) _, clusterAdminKubeConfig, err := testserver.StartTestMasterAPI() if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } bobClient, _, _, err := testutil.GetClientForUser(*clusterAdminClientConfig, "bob") if err != nil { t.Fatalf("unexpected error: %v", err) } w, err := bobClient.Projects().Watch(kapi.ListOptions{}) if err != nil { t.Fatalf("unexpected error: %v", err) } if _, err := testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "ns-01", "bob"); err != nil { t.Fatalf("unexpected error: %v", err) } select { case event := <-w.ResultChan(): if event.Type != watch.Added { t.Errorf("expected added, got %v", event) } project := event.Object.(*projectapi.Project) if project.Name != "ns-01" { t.Fatalf("expected %v, got %#v", "ns-01", project) } case <-time.After(3 * time.Second): t.Fatalf("timeout") } joeClient, err := testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "ns-02", "joe") if err != nil { t.Fatalf("unexpected error: %v", err) } addBob := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.EditRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor("ns-02", joeClient), Users: []string{"bob"}, } if err := addBob.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } // wait for the add for { select { case event := <-w.ResultChan(): project := event.Object.(*projectapi.Project) t.Logf("got %#v %#v", event, project) if event.Type == watch.Added && project.Name == "ns-02" { return } case <-time.After(3 * time.Second): t.Fatalf("timeout") } } if err := addBob.RemoveRole(); err != nil { t.Fatalf("unexpected error: %v", err) } // wait for the delete for { select { case event := <-w.ResultChan(): project := event.Object.(*projectapi.Project) t.Logf("got %#v %#v", event, project) if event.Type == watch.Deleted && project.Name == "ns-02" { return } case <-time.After(3 * time.Second): t.Fatalf("timeout") } } // test the "start from beginning watch" beginningWatch, err := bobClient.Projects().Watch(kapi.ListOptions{ResourceVersion: "0"}) if err != nil { t.Fatalf("unexpected error: %v", err) } select { case event := <-beginningWatch.ResultChan(): if event.Type != watch.Added { t.Errorf("expected added, got %v", event) } project := event.Object.(*projectapi.Project) if project.Name != "ns-01" { t.Fatalf("expected %v, got %#v", "ns-01", project) } case <-time.After(3 * time.Second): t.Fatalf("timeout") } fromNowWatch, err := bobClient.Projects().Watch(kapi.ListOptions{}) if err != nil { t.Fatalf("unexpected error: %v", err) } select { case event := <-fromNowWatch.ResultChan(): t.Fatalf("unexpected event %v", event) case <-time.After(3 * time.Second): } }
func TestPolicyCommands(t *testing.T) { _, clusterAdminKubeConfig, err := testserver.StartTestMaster() if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } const projectName = "hammer-project" haroldClient, err := testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, projectName, "harold") if err != nil { t.Fatalf("unexpected error: %v", err) } addViewer := policy.RoleModificationOptions{ RoleName: bootstrappolicy.ViewRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(projectName, haroldClient), Users: []string{"valerie"}, Groups: []string{"my-group"}, } if err := addViewer.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } viewers, err := haroldClient.RoleBindings(projectName).Get("view") if err != nil { t.Fatalf("unexpected error: %v", err) } binding := authorizationinterfaces.NewLocalRoleBindingAdapter(viewers) if !binding.Users().Has("valerie") { t.Errorf("expected valerie in users: %v", binding.Users()) } if !binding.Groups().Has("my-group") { t.Errorf("expected my-group in groups: %v", binding.Groups()) } removeValerie := policy.RemoveFromProjectOptions{ BindingNamespace: projectName, Client: haroldClient, Users: []string{"valerie"}, Out: ioutil.Discard, } if err := removeValerie.Run(); err != nil { t.Fatalf("unexpected error: %v", err) } viewers, err = haroldClient.RoleBindings(projectName).Get("view") if err != nil { t.Fatalf("unexpected error: %v", err) } binding = authorizationinterfaces.NewLocalRoleBindingAdapter(viewers) if binding.Users().Has("valerie") { t.Errorf("unexpected valerie in users: %v", binding.Users()) } if !binding.Groups().Has("my-group") { t.Errorf("expected my-group in groups: %v", binding.Groups()) } removeMyGroup := policy.RemoveFromProjectOptions{ BindingNamespace: projectName, Client: haroldClient, Groups: []string{"my-group"}, Out: ioutil.Discard, } if err := removeMyGroup.Run(); err != nil { t.Fatalf("unexpected error: %v", err) } viewers, err = haroldClient.RoleBindings(projectName).Get("view") if err != nil { t.Fatalf("unexpected error: %v", err) } binding = authorizationinterfaces.NewLocalRoleBindingAdapter(viewers) if binding.Users().Has("valerie") { t.Errorf("unexpected valerie in users: %v", binding.Users()) } if binding.Groups().Has("my-group") { t.Errorf("unexpected my-group in groups: %v", binding.Groups()) } }
func TestAuthorizationSubjectAccessReview(t *testing.T) { _, clusterAdminKubeConfig, err := testutil.StartTestMaster() if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } haroldClient, err := testutil.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "hammer-project", "harold") if err != nil { t.Fatalf("unexpected error: %v", err) } markClient, err := testutil.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "mallet-project", "mark") if err != nil { t.Fatalf("unexpected error: %v", err) } dannyClient, err := testutil.GetClientForUser(*clusterAdminClientConfig, "danny") if err != nil { t.Fatalf("error requesting token: %v", err) } addDanny := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.ViewRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor("default", clusterAdminClient), Users: []string{"danny"}, } if err := addDanny.AddRole(); err != nil { t.Errorf("unexpected error: %v", err) } askCanDannyGetProject := &authorizationapi.SubjectAccessReview{User: "******", Verb: "get", Resource: "projects"} subjectAccessReviewTest{ description: "cluster admin told danny can get project default", clientInterface: clusterAdminClient.SubjectAccessReviews("default"), review: askCanDannyGetProject, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: true, Reason: "allowed by rule in default", Namespace: "default", }, }.run(t) subjectAccessReviewTest{ description: "cluster admin told danny cannot get projects cluster-wide", clientInterface: clusterAdminClient.ClusterSubjectAccessReviews(), review: askCanDannyGetProject, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: false, Reason: `User "danny" cannot get projects at the cluster scope`, Namespace: "", }, }.run(t) subjectAccessReviewTest{ description: "as danny, can I make cluster subject access reviews", clientInterface: dannyClient.ClusterSubjectAccessReviews(), review: askCanDannyGetProject, err: `User "danny" cannot create subjectaccessreviews at the cluster scope`, }.run(t) addValerie := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.ViewRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor("hammer-project", haroldClient), Users: []string{"valerie"}, } if err := addValerie.AddRole(); err != nil { t.Errorf("unexpected error: %v", err) } addEdgar := &policy.RoleModificationOptions{ RoleNamespace: "", RoleName: bootstrappolicy.EditRoleName, RoleBindingAccessor: policy.NewLocalRoleBindingAccessor("mallet-project", markClient), Users: []string{"edgar"}, } if err := addEdgar.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } askCanValerieGetProject := &authorizationapi.SubjectAccessReview{User: "******", Verb: "get", Resource: "projects"} subjectAccessReviewTest{ description: "harold told valerie can get project hammer-project", clientInterface: haroldClient.SubjectAccessReviews("hammer-project"), review: askCanValerieGetProject, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: true, Reason: "allowed by rule in hammer-project", Namespace: "hammer-project", }, }.run(t) subjectAccessReviewTest{ description: "mark told valerie cannot get project mallet-project", clientInterface: markClient.SubjectAccessReviews("mallet-project"), review: askCanValerieGetProject, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: false, Reason: `User "valerie" cannot get projects in project "mallet-project"`, Namespace: "mallet-project", }, }.run(t) askCanEdgarDeletePods := &authorizationapi.SubjectAccessReview{User: "******", Verb: "delete", Resource: "pods"} subjectAccessReviewTest{ description: "mark told edgar can delete pods in mallet-project", clientInterface: markClient.SubjectAccessReviews("mallet-project"), review: askCanEdgarDeletePods, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: true, Reason: "allowed by rule in mallet-project", Namespace: "mallet-project", }, }.run(t) subjectAccessReviewTest{ description: "harold denied ability to run subject access review in project mallet-project", clientInterface: haroldClient.SubjectAccessReviews("mallet-project"), review: askCanEdgarDeletePods, err: `User "harold" cannot create subjectaccessreviews in project "mallet-project"`, }.run(t) askCanHaroldUpdateProject := &authorizationapi.SubjectAccessReview{User: "******", Verb: "update", Resource: "projects"} subjectAccessReviewTest{ description: "harold told harold can update project hammer-project", clientInterface: haroldClient.SubjectAccessReviews("hammer-project"), review: askCanHaroldUpdateProject, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: true, Reason: "allowed by rule in hammer-project", Namespace: "hammer-project", }, }.run(t) askCanClusterAdminsCreateProject := &authorizationapi.SubjectAccessReview{Groups: util.NewStringSet("system:cluster-admins"), Verb: "create", Resource: "projects"} subjectAccessReviewTest{ description: "cluster admin told cluster admins can create projects", clientInterface: clusterAdminClient.ClusterSubjectAccessReviews(), review: askCanClusterAdminsCreateProject, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: true, Reason: "allowed by cluster rule:", Namespace: "", }, }.run(t) subjectAccessReviewTest{ description: "harold denied ability to run cluster subject access review", clientInterface: haroldClient.ClusterSubjectAccessReviews(), review: askCanClusterAdminsCreateProject, err: `User "harold" cannot create subjectaccessreviews at the cluster scope`, }.run(t) askCanICreatePods := &authorizationapi.SubjectAccessReview{Verb: "create", Resource: "pods"} subjectAccessReviewTest{ description: "harold told he can create pods in project hammer-project", clientInterface: haroldClient.SubjectAccessReviews("hammer-project"), review: askCanICreatePods, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: true, Reason: "allowed by rule in hammer-project", Namespace: "hammer-project", }, }.run(t) askCanICreatePolicyBindings := &authorizationapi.SubjectAccessReview{Verb: "create", Resource: "policybindings"} subjectAccessReviewTest{ description: "harold told he can create policybindings in project hammer-project", clientInterface: haroldClient.SubjectAccessReviews("hammer-project"), review: askCanICreatePolicyBindings, response: authorizationapi.SubjectAccessReviewResponse{ Allowed: false, Reason: `User "harold" cannot create policybindings in project "hammer-project"`, Namespace: "hammer-project", }, }.run(t) }
func TestInvalidRoleRefs(t *testing.T) { testutil.RequireEtcd(t) defer testutil.DumpEtcdOnFailure(t) _, clusterAdminKubeConfig, err := testserver.StartTestMaster() if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } bobClient, _, _, err := testutil.GetClientForUser(*clusterAdminClientConfig, "bob") if err != nil { t.Fatalf("unexpected error: %v", err) } aliceClient, _, _, err := testutil.GetClientForUser(*clusterAdminClientConfig, "alice") if err != nil { t.Fatalf("unexpected error: %v", err) } if _, err := testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "foo", "bob"); err != nil { t.Fatalf("unexpected error: %v", err) } if _, err := testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, "bar", "alice"); err != nil { t.Fatalf("unexpected error: %v", err) } roleName := "missing-role" if _, err := clusterAdminClient.ClusterRoles().Create(&authorizationapi.ClusterRole{ObjectMeta: kapi.ObjectMeta{Name: roleName}}); err != nil { t.Fatalf("unexpected error: %v", err) } modifyRole := &policy.RoleModificationOptions{RoleName: roleName, Users: []string{"someuser"}} // mess up rolebindings in "foo" modifyRole.RoleBindingAccessor = policy.NewLocalRoleBindingAccessor("foo", clusterAdminClient) if err := modifyRole.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } // mess up rolebindings in "bar" modifyRole.RoleBindingAccessor = policy.NewLocalRoleBindingAccessor("bar", clusterAdminClient) if err := modifyRole.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } // mess up clusterrolebindings modifyRole.RoleBindingAccessor = policy.NewClusterRoleBindingAccessor(clusterAdminClient) if err := modifyRole.AddRole(); err != nil { t.Fatalf("unexpected error: %v", err) } // Orphan the rolebindings by deleting the role if err := clusterAdminClient.ClusterRoles().Delete(roleName); err != nil { t.Fatalf("unexpected error: %v", err) } // wait for evaluation errors to show up in both namespaces and at cluster scope if err := wait.PollImmediate(100*time.Millisecond, 10*time.Second, func() (bool, error) { review := &authorizationapi.ResourceAccessReview{Action: authorizationapi.Action{Verb: "get", Resource: "pods"}} review.Action.Namespace = "foo" if resp, err := clusterAdminClient.ResourceAccessReviews().Create(review); err != nil || resp.EvaluationError == "" { return false, err } review.Action.Namespace = "bar" if resp, err := clusterAdminClient.ResourceAccessReviews().Create(review); err != nil || resp.EvaluationError == "" { return false, err } review.Action.Namespace = "" if resp, err := clusterAdminClient.ResourceAccessReviews().Create(review); err != nil || resp.EvaluationError == "" { return false, err } return true, nil }); err != nil { t.Fatalf("unexpected error: %v", err) } // Make sure bob still sees his project (and only his project) if projects, err := bobClient.Projects().List(kapi.ListOptions{}); err != nil { t.Fatalf("unexpected error: %v", err) } else if hasErr := hasExactlyTheseProjects(projects, sets.NewString("foo")); hasErr != nil { t.Error(hasErr) } // Make sure alice still sees her project (and only her project) if projects, err := aliceClient.Projects().List(kapi.ListOptions{}); err != nil { t.Fatalf("unexpected error: %v", err) } else if hasErr := hasExactlyTheseProjects(projects, sets.NewString("bar")); hasErr != nil { t.Error(hasErr) } // Make sure cluster admin still sees all projects if projects, err := clusterAdminClient.Projects().List(kapi.ListOptions{}); err != nil { t.Fatalf("unexpected error: %v", err) } else { projectNames := sets.NewString() for _, project := range projects.Items { projectNames.Insert(project.Name) } if !projectNames.HasAll("foo", "bar", "openshift-infra", "openshift", "default") { t.Errorf("Expected projects foo and bar, got %v", projectNames.List()) } } }