func (o *SCCModificationOptions) CompleteUsers(f *clientcmd.Factory, args []string, saNames []string) error { if (len(args) < 2) && (len(saNames) == 0) { return errors.New("you must specify at least two arguments (<scc> <user> [user]...) or a service account (<scc> -z <service account name>) ") } o.SCCName = args[0] o.Subjects = authorizationapi.BuildSubjects(args[1:], []string{}, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) var err error _, o.SCCInterface, err = f.Clients() if err != nil { return err } o.DefaultSubjectNamespace, _, err = f.DefaultNamespace() if err != nil { return err } for _, sa := range saNames { o.Subjects = append(o.Subjects, kapi.ObjectReference{Namespace: o.DefaultSubjectNamespace, Name: sa, Kind: "ServiceAccount"}) } return nil }
func (o *ReconcileClusterRoleBindingsOptions) Complete(cmd *cobra.Command, f *clientcmd.Factory, args []string, excludeUsers, excludeGroups []string) error { oclient, _, err := f.Clients() if err != nil { return err } o.RoleBindingClient = oclient.ClusterRoleBindings() o.Output = kcmdutil.GetFlagString(cmd, "output") o.ExcludeSubjects = authorizationapi.BuildSubjects(excludeUsers, excludeGroups, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) mapper, _ := f.Object(false) for _, resourceString := range args { resource, name, err := cmdutil.ResolveResource(authorizationapi.Resource("clusterroles"), resourceString, mapper) if err != nil { return err } if resource != authorizationapi.Resource("clusterroles") { return fmt.Errorf("%v is not a valid resource type for this command", resource) } if len(name) == 0 { return fmt.Errorf("%s did not contain a name", resourceString) } o.RolesToReconcile = append(o.RolesToReconcile, name) } return nil }
func (o *SCCModificationOptions) CompleteUsers(f *clientcmd.Factory, args []string, saNames []string) error { if len(args) < 1 { return errors.New("you must specify a scc") } o.SCCName = args[0] o.Subjects = authorizationapi.BuildSubjects(args[1:], []string{}, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) if (len(o.Subjects) == 0) && (len(saNames) == 0) { return errors.New("you must specify at least one user or service account") } _, kc, _, err := f.Clients() if err != nil { return err } o.SCCInterface = adapter.FromUnversionedClient(kc).Core() o.DefaultSubjectNamespace, _, err = f.DefaultNamespace() if err != nil { return err } for _, sa := range saNames { o.Subjects = append(o.Subjects, kapi.ObjectReference{Namespace: o.DefaultSubjectNamespace, Name: sa, Kind: "ServiceAccount"}) } return nil }
func parseRequestedSubject(requestedSubject string) (unversioned.GroupResource, string, string, error) { subjects := authorizationapi.BuildSubjects([]string{requestedSubject}, nil, // validates whether the usernames are regular users or system users uservalidation.ValidateUserName, // validates group names, but we never pass any groups func(s string, b bool) (bool, string) { return true, "" }) if len(subjects) == 0 { return unversioned.GroupResource{}, "", "", fmt.Errorf("subject must be in the form of a username, not %v", requestedSubject) } resource := unversioned.GroupResource{} switch subjects[0].GetObjectKind().GroupVersionKind().GroupKind() { case userapi.Kind(authorizationapi.UserKind): resource = userapi.Resource(authorizationapi.UserResource) case userapi.Kind(authorizationapi.SystemUserKind): resource = userapi.Resource(authorizationapi.SystemUserResource) case kapi.Kind(authorizationapi.ServiceAccountKind): resource = kapi.Resource(authorizationapi.ServiceAccountResource) default: return unversioned.GroupResource{}, "", "", fmt.Errorf("unknown subject type: %v", subjects[0]) } return resource, subjects[0].Namespace, subjects[0].Name, nil }
func (o *RoleModificationOptions) AddRole() error { roleBindings, err := o.RoleBindingAccessor.GetExistingRoleBindingsForRole(o.RoleNamespace, o.RoleName) if err != nil { return err } roleBindingNames, err := o.RoleBindingAccessor.GetExistingRoleBindingNames() if err != nil { return err } var roleBinding *authorizationapi.RoleBinding isUpdate := true if len(roleBindings) == 0 { roleBinding = &authorizationapi.RoleBinding{} isUpdate = false } else { // only need to add the user or group to a single roleBinding on the role. Just choose the first one roleBinding = roleBindings[0] } roleBinding.RoleRef.Namespace = o.RoleNamespace roleBinding.RoleRef.Name = o.RoleName newSubjects := authorizationapi.BuildSubjects(o.Users, o.Groups, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) newSubjects = append(newSubjects, o.Subjects...) subjectCheck: for _, newSubject := range newSubjects { for _, existingSubject := range roleBinding.Subjects { if existingSubject.Kind == newSubject.Kind && existingSubject.Name == newSubject.Name && existingSubject.Namespace == newSubject.Namespace { continue subjectCheck } } roleBinding.Subjects = append(roleBinding.Subjects, newSubject) } if isUpdate { err = o.RoleBindingAccessor.UpdateRoleBinding(roleBinding) } else { roleBinding.Name = getUniqueName(o.RoleName, roleBindingNames) err = o.RoleBindingAccessor.CreateRoleBinding(roleBinding) // If the rolebinding was created in the meantime, rerun if kapierrors.IsAlreadyExists(err) { return o.AddRole() } } if err != nil { return err } return nil }
func convert_v1_ClusterRoleBinding_To_api_ClusterRoleBinding(in *ClusterRoleBinding, out *newer.ClusterRoleBinding, s conversion.Scope) error { if err := s.DefaultConvert(in, out, conversion.IgnoreMissingFields|conversion.AllowDifferentFieldTypeNames); err != nil { return err } // if the users and groups fields are cleared, then respect only subjects. The field was set in the DefaultConvert above if in.UserNames == nil && in.GroupNames == nil { return nil } out.Subjects = newer.BuildSubjects(in.UserNames, in.GroupNames, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) return nil }
func Convert_v1_RoleBinding_To_api_RoleBinding(in *RoleBinding, out *newer.RoleBinding, s conversion.Scope) error { if err := autoConvert_v1_RoleBinding_To_api_RoleBinding(in, out, s); err != nil { return err } // if the users and groups fields are cleared, then respect only subjects. The field was set in the DefaultConvert above if in.UserNames == nil && in.GroupNames == nil { return nil } out.Subjects = newer.BuildSubjects(in.UserNames, in.GroupNames, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) return nil }
func (o *ReconcileClusterRoleBindingsOptions) Complete(cmd *cobra.Command, f *clientcmd.Factory, args []string, excludeUsers, excludeGroups []string) error { if len(args) != 0 { return kcmdutil.UsageError(cmd, "no arguments are allowed") } oclient, _, err := f.Clients() if err != nil { return err } o.RoleBindingClient = oclient.ClusterRoleBindings() o.Output = kcmdutil.GetFlagString(cmd, "output") o.ExcludeSubjects = authorizationapi.BuildSubjects(excludeUsers, excludeGroups, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) return nil }
func (o *SCCModificationOptions) CompleteGroups(f *clientcmd.Factory, args []string) error { if len(args) < 2 { return errors.New("you must specify at least two arguments: <scc> <group> [group]...") } o.SCCName = args[0] o.Subjects = authorizationapi.BuildSubjects([]string{}, args[1:], uservalidation.ValidateUserName, uservalidation.ValidateGroupName) var err error _, o.SCCInterface, err = f.Clients() if err != nil { return err } o.DefaultSubjectNamespace, _, err = f.DefaultNamespace() if err != nil { return err } return nil }
func (o *RoleModificationOptions) RemoveRole() error { roleBindings, err := o.RoleBindingAccessor.GetExistingRoleBindingsForRole(o.RoleNamespace, o.RoleName) if err != nil { return err } if len(roleBindings) == 0 { return fmt.Errorf("unable to locate RoleBinding for %v/%v", o.RoleNamespace, o.RoleName) } subjectsToRemove := authorizationapi.BuildSubjects(o.Users, o.Groups, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) subjectsToRemove = append(subjectsToRemove, o.Subjects...) for _, roleBinding := range roleBindings { roleBinding.Subjects = removeSubjects(roleBinding.Subjects, subjectsToRemove) err = o.RoleBindingAccessor.UpdateRoleBinding(roleBinding) if err != nil { return err } } return nil }
func TestBasicUserBasedGroupManipulation(t *testing.T) { testutil.RequireEtcd(t) defer testutil.DumpEtcdOnFailure(t) _, clusterAdminKubeConfig, err := testserver.StartTestMasterAPI() if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Errorf("unexpected error: %v", err) } clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } valerieOpenshiftClient, _, _, err := testutil.GetClientForUser(*clusterAdminClientConfig, "valerie") if err != nil { t.Fatalf("unexpected error: %v", err) } // make sure we don't get back system groups firstValerie, err := clusterAdminClient.Users().Get("valerie") if err != nil { t.Fatalf("unexpected error: %v", err) } if len(firstValerie.Groups) != 0 { t.Errorf("unexpected groups: %v", firstValerie.Groups) } // make sure that user/~ returns groups for unbacked users expectedClusterAdminGroups := []string{"system:cluster-admins"} clusterAdminUser, err := clusterAdminClient.Users().Get("~") if err != nil { t.Fatalf("unexpected error: %v", err) } if !reflect.DeepEqual(clusterAdminUser.Groups, expectedClusterAdminGroups) { t.Errorf("expected %v, got %v", clusterAdminUser.Groups, expectedClusterAdminGroups) } valerieGroups := []string{"theGroup"} firstValerie.Groups = append(firstValerie.Groups, valerieGroups...) _, err = clusterAdminClient.Users().Update(firstValerie) if err != nil { t.Errorf("unexpected error: %v", err) } // make sure that user/~ doesn't get back system groups when it merges secondValerie, err := valerieOpenshiftClient.Users().Get("~") if err != nil { t.Fatalf("unexpected error: %v", err) } if !reflect.DeepEqual(secondValerie.Groups, valerieGroups) { t.Errorf("expected %v, got %v", secondValerie.Groups, valerieGroups) } _, err = valerieOpenshiftClient.Projects().Get("empty") if err == nil { t.Fatalf("expected error") } emptyProject := &projectapi.Project{} emptyProject.Name = "empty" _, err = clusterAdminClient.Projects().Create(emptyProject) if err != nil { t.Fatalf("unexpected error: %v", err) } roleBinding := &authorizationapi.RoleBinding{} roleBinding.Name = "admins" roleBinding.RoleRef.Name = "admin" roleBinding.Subjects = authorizationapi.BuildSubjects([]string{}, valerieGroups, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) _, err = clusterAdminClient.RoleBindings("empty").Create(roleBinding) if err != nil { t.Fatalf("unexpected error: %v", err) } if err := testutil.WaitForPolicyUpdate(valerieOpenshiftClient, "empty", "get", kapi.Resource("pods"), true); err != nil { t.Error(err) } // make sure that user groups are respected for policy _, err = valerieOpenshiftClient.Projects().Get("empty") if err != nil { t.Fatalf("unexpected error: %v", err) } }
func TestBasicGroupManipulation(t *testing.T) { testutil.RequireEtcd(t) defer testutil.DumpEtcdOnFailure(t) _, clusterAdminKubeConfig, err := testserver.StartTestMasterAPI() if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Errorf("unexpected error: %v", err) } clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } valerieOpenshiftClient, _, _, err := testutil.GetClientForUser(*clusterAdminClientConfig, "valerie") if err != nil { t.Fatalf("unexpected error: %v", err) } theGroup := &userapi.Group{} theGroup.Name = "thegroup" theGroup.Users = append(theGroup.Users, "valerie", "victor") _, err = clusterAdminClient.Groups().Create(theGroup) if err != nil { t.Errorf("unexpected error: %v", err) } _, err = valerieOpenshiftClient.Projects().Get("empty") if err == nil { t.Fatalf("expected error") } emptyProject := &projectapi.Project{} emptyProject.Name = "empty" _, err = clusterAdminClient.Projects().Create(emptyProject) if err != nil { t.Fatalf("unexpected error: %v", err) } roleBinding := &authorizationapi.RoleBinding{} roleBinding.Name = "admins" roleBinding.RoleRef.Name = "admin" roleBinding.Subjects = authorizationapi.BuildSubjects([]string{}, []string{theGroup.Name}, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) _, err = clusterAdminClient.RoleBindings("empty").Create(roleBinding) if err != nil { t.Fatalf("unexpected error: %v", err) } if err := testutil.WaitForPolicyUpdate(valerieOpenshiftClient, "empty", "get", kapi.Resource("pods"), true); err != nil { t.Error(err) } // make sure that user groups are respected for policy _, err = valerieOpenshiftClient.Projects().Get("empty") if err != nil { t.Errorf("unexpected error: %v", err) } victorOpenshiftClient, _, _, err := testutil.GetClientForUser(*clusterAdminClientConfig, "victor") if err != nil { t.Fatalf("unexpected error: %v", err) } _, err = victorOpenshiftClient.Projects().Get("empty") if err != nil { t.Errorf("unexpected error: %v", err) } }
func (c *MasterConfig) impersonationFilter(handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { requestedUser := req.Header.Get(authenticationapi.ImpersonateUserHeader) if len(requestedUser) == 0 { handler.ServeHTTP(w, req) return } subjects := authorizationapi.BuildSubjects([]string{requestedUser}, req.Header[authenticationapi.ImpersonateGroupHeader], // validates whether the usernames are regular users or system users uservalidation.ValidateUserName, // validates group names are regular groups or system groups uservalidation.ValidateGroupName) ctx, exists := c.RequestContextMapper.Get(req) if !exists { forbidden("context not found", nil, w, req) return } // if groups are not specified, then we need to look them up differently depending on the type of user // if they are specified, then they are the authority groupsSpecified := len(req.Header[authenticationapi.ImpersonateGroupHeader]) > 0 // make sure we're allowed to impersonate each subject. While we're iterating through, start building username // and group information username := "" groups := []string{} for _, subject := range subjects { actingAsAttributes := &authorizer.DefaultAuthorizationAttributes{ Verb: "impersonate", } switch subject.GetObjectKind().GroupVersionKind().GroupKind() { case userapi.Kind(authorizationapi.GroupKind): actingAsAttributes.APIGroup = userapi.GroupName actingAsAttributes.Resource = authorizationapi.GroupResource actingAsAttributes.ResourceName = subject.Name groups = append(groups, subject.Name) case userapi.Kind(authorizationapi.SystemGroupKind): actingAsAttributes.APIGroup = userapi.GroupName actingAsAttributes.Resource = authorizationapi.SystemGroupResource actingAsAttributes.ResourceName = subject.Name groups = append(groups, subject.Name) case userapi.Kind(authorizationapi.UserKind): actingAsAttributes.APIGroup = userapi.GroupName actingAsAttributes.Resource = authorizationapi.UserResource actingAsAttributes.ResourceName = subject.Name username = subject.Name if !groupsSpecified { if actualGroups, err := c.GroupCache.GroupsFor(subject.Name); err == nil { for _, group := range actualGroups { groups = append(groups, group.Name) } } groups = append(groups, bootstrappolicy.AuthenticatedGroup, bootstrappolicy.AuthenticatedOAuthGroup) } case userapi.Kind(authorizationapi.SystemUserKind): actingAsAttributes.APIGroup = userapi.GroupName actingAsAttributes.Resource = authorizationapi.SystemUserResource actingAsAttributes.ResourceName = subject.Name username = subject.Name if !groupsSpecified { if subject.Name == bootstrappolicy.UnauthenticatedUsername { groups = append(groups, bootstrappolicy.UnauthenticatedGroup) } else { groups = append(groups, bootstrappolicy.AuthenticatedGroup) } } case kapi.Kind(authorizationapi.ServiceAccountKind): actingAsAttributes.APIGroup = kapi.GroupName actingAsAttributes.Resource = authorizationapi.ServiceAccountResource actingAsAttributes.ResourceName = subject.Name username = serviceaccount.MakeUsername(subject.Namespace, subject.Name) if !groupsSpecified { groups = append(serviceaccount.MakeGroupNames(subject.Namespace, subject.Name), bootstrappolicy.AuthenticatedGroup) } default: forbidden(fmt.Sprintf("unknown subject type: %v", subject), actingAsAttributes, w, req) return } authCheckCtx := kapi.WithNamespace(ctx, subject.Namespace) allowed, reason, err := c.Authorizer.Authorize(authCheckCtx, actingAsAttributes) if err != nil { forbidden(err.Error(), actingAsAttributes, w, req) return } if !allowed { forbidden(reason, actingAsAttributes, w, req) return } } var extra map[string][]string if requestScopes, ok := req.Header[authenticationapi.ImpersonateUserScopeHeader]; ok { extra = map[string][]string{authorizationapi.ScopesKey: requestScopes} } newUser := &user.DefaultInfo{ Name: username, Groups: groups, Extra: extra, } c.RequestContextMapper.Update(req, kapi.WithUser(ctx, newUser)) oldUser, _ := kapi.UserFrom(ctx) httplog.LogOf(req, w).Addf("%v is acting as %v", oldUser, newUser) handler.ServeHTTP(w, req) }) }
func (o *RemoveFromProjectOptions) Run() error { bindingList, err := o.Client.PolicyBindings(o.BindingNamespace).List(kapi.ListOptions{}) if err != nil { return err } sort.Sort(authorizationapi.PolicyBindingSorter(bindingList.Items)) usersRemoved := sets.String{} groupsRemoved := sets.String{} sasRemoved := sets.String{} othersRemoved := sets.String{} subjectsToRemove := authorizationapi.BuildSubjects(o.Users, o.Groups, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) for _, currPolicyBinding := range bindingList.Items { for _, currBinding := range authorizationapi.SortRoleBindings(currPolicyBinding.RoleBindings, true) { originalSubjects := make([]kapi.ObjectReference, len(currBinding.Subjects)) copy(originalSubjects, currBinding.Subjects) oldUsers, oldGroups, oldSAs, oldOthers := authorizationapi.SubjectsStrings(currBinding.Namespace, originalSubjects) oldUsersSet, oldGroupsSet, oldSAsSet, oldOtherSet := sets.NewString(oldUsers...), sets.NewString(oldGroups...), sets.NewString(oldSAs...), sets.NewString(oldOthers...) currBinding.Subjects = removeSubjects(currBinding.Subjects, subjectsToRemove) newUsers, newGroups, newSAs, newOthers := authorizationapi.SubjectsStrings(currBinding.Namespace, currBinding.Subjects) newUsersSet, newGroupsSet, newSAsSet, newOtherSet := sets.NewString(newUsers...), sets.NewString(newGroups...), sets.NewString(newSAs...), sets.NewString(newOthers...) if len(currBinding.Subjects) == len(originalSubjects) { continue } _, err = o.Client.RoleBindings(o.BindingNamespace).Update(currBinding) if err != nil { return err } roleDisplayName := fmt.Sprintf("%s/%s", currBinding.RoleRef.Namespace, currBinding.RoleRef.Name) if len(currBinding.RoleRef.Namespace) == 0 { roleDisplayName = currBinding.RoleRef.Name } if diff := oldUsersSet.Difference(newUsersSet); len(diff) != 0 { fmt.Fprintf(o.Out, "Removing %s from users %v in project %s.\n", roleDisplayName, diff.List(), o.BindingNamespace) usersRemoved.Insert(diff.List()...) } if diff := oldGroupsSet.Difference(newGroupsSet); len(diff) != 0 { fmt.Fprintf(o.Out, "Removing %s from groups %v in project %s.\n", roleDisplayName, diff.List(), o.BindingNamespace) groupsRemoved.Insert(diff.List()...) } if diff := oldSAsSet.Difference(newSAsSet); len(diff) != 0 { fmt.Fprintf(o.Out, "Removing %s from serviceaccounts %v in project %s.\n", roleDisplayName, diff.List(), o.BindingNamespace) sasRemoved.Insert(diff.List()...) } if diff := oldOtherSet.Difference(newOtherSet); len(diff) != 0 { fmt.Fprintf(o.Out, "Removing %s from subjects %v in project %s.\n", roleDisplayName, diff.List(), o.BindingNamespace) othersRemoved.Insert(diff.List()...) } } } if diff := sets.NewString(o.Users...).Difference(usersRemoved); len(diff) != 0 { fmt.Fprintf(o.Out, "Users %v were not bound to roles in project %s.\n", diff.List(), o.BindingNamespace) } if diff := sets.NewString(o.Groups...).Difference(groupsRemoved); len(diff) != 0 { fmt.Fprintf(o.Out, "Groups %v were not bound to roles in project %s.\n", diff.List(), o.BindingNamespace) } return nil }