...

Source file src/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/subject_locator.go

Documentation: k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Package rbac implements the authorizer.Authorizer interface using roles base access control.
    18  package rbac
    19  
    20  import (
    21  	rbacv1 "k8s.io/api/rbac/v1"
    22  	utilerrors "k8s.io/apimachinery/pkg/util/errors"
    23  	"k8s.io/apiserver/pkg/authentication/user"
    24  	"k8s.io/apiserver/pkg/authorization/authorizer"
    25  	rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
    26  )
    27  
    28  type RoleToRuleMapper interface {
    29  	// GetRoleReferenceRules attempts to resolve the role reference of a RoleBinding or ClusterRoleBinding.  The passed namespace should be the namespace
    30  	// of the role binding, the empty string if a cluster role binding.
    31  	GetRoleReferenceRules(roleRef rbacv1.RoleRef, namespace string) ([]rbacv1.PolicyRule, error)
    32  }
    33  
    34  type SubjectLocator interface {
    35  	AllowedSubjects(attributes authorizer.Attributes) ([]rbacv1.Subject, error)
    36  }
    37  
    38  var _ = SubjectLocator(&SubjectAccessEvaluator{})
    39  
    40  type SubjectAccessEvaluator struct {
    41  	superUser string
    42  
    43  	roleBindingLister        rbacregistryvalidation.RoleBindingLister
    44  	clusterRoleBindingLister rbacregistryvalidation.ClusterRoleBindingLister
    45  	roleToRuleMapper         RoleToRuleMapper
    46  }
    47  
    48  func NewSubjectAccessEvaluator(roles rbacregistryvalidation.RoleGetter, roleBindings rbacregistryvalidation.RoleBindingLister, clusterRoles rbacregistryvalidation.ClusterRoleGetter, clusterRoleBindings rbacregistryvalidation.ClusterRoleBindingLister, superUser string) *SubjectAccessEvaluator {
    49  	subjectLocator := &SubjectAccessEvaluator{
    50  		superUser:                superUser,
    51  		roleBindingLister:        roleBindings,
    52  		clusterRoleBindingLister: clusterRoleBindings,
    53  		roleToRuleMapper: rbacregistryvalidation.NewDefaultRuleResolver(
    54  			roles, roleBindings, clusterRoles, clusterRoleBindings,
    55  		),
    56  	}
    57  	return subjectLocator
    58  }
    59  
    60  // AllowedSubjects returns the subjects that can perform an action and any errors encountered while computing the list.
    61  // It is possible to have both subjects and errors returned if some rolebindings couldn't be resolved, but others could be.
    62  func (r *SubjectAccessEvaluator) AllowedSubjects(requestAttributes authorizer.Attributes) ([]rbacv1.Subject, error) {
    63  	subjects := []rbacv1.Subject{{Kind: rbacv1.GroupKind, APIGroup: rbacv1.GroupName, Name: user.SystemPrivilegedGroup}}
    64  	if len(r.superUser) > 0 {
    65  		subjects = append(subjects, rbacv1.Subject{Kind: rbacv1.UserKind, APIGroup: rbacv1.GroupName, Name: r.superUser})
    66  	}
    67  	errorlist := []error{}
    68  
    69  	if clusterRoleBindings, err := r.clusterRoleBindingLister.ListClusterRoleBindings(); err != nil {
    70  		errorlist = append(errorlist, err)
    71  
    72  	} else {
    73  		for _, clusterRoleBinding := range clusterRoleBindings {
    74  			rules, err := r.roleToRuleMapper.GetRoleReferenceRules(clusterRoleBinding.RoleRef, "")
    75  			if err != nil {
    76  				// if we have an error, just keep track of it and keep processing.  Since rules are additive,
    77  				// missing a reference is bad, but we can continue with other rolebindings and still have a list
    78  				// that does not contain any invalid values
    79  				errorlist = append(errorlist, err)
    80  			}
    81  			if RulesAllow(requestAttributes, rules...) {
    82  				subjects = append(subjects, clusterRoleBinding.Subjects...)
    83  			}
    84  		}
    85  	}
    86  
    87  	if namespace := requestAttributes.GetNamespace(); len(namespace) > 0 {
    88  		if roleBindings, err := r.roleBindingLister.ListRoleBindings(namespace); err != nil {
    89  			errorlist = append(errorlist, err)
    90  
    91  		} else {
    92  			for _, roleBinding := range roleBindings {
    93  				rules, err := r.roleToRuleMapper.GetRoleReferenceRules(roleBinding.RoleRef, namespace)
    94  				if err != nil {
    95  					// if we have an error, just keep track of it and keep processing.  Since rules are additive,
    96  					// missing a reference is bad, but we can continue with other rolebindings and still have a list
    97  					// that does not contain any invalid values
    98  					errorlist = append(errorlist, err)
    99  				}
   100  				if RulesAllow(requestAttributes, rules...) {
   101  					subjects = append(subjects, roleBinding.Subjects...)
   102  				}
   103  			}
   104  		}
   105  	}
   106  
   107  	dedupedSubjects := []rbacv1.Subject{}
   108  	for _, subject := range subjects {
   109  		found := false
   110  		for _, curr := range dedupedSubjects {
   111  			if curr == subject {
   112  				found = true
   113  				break
   114  			}
   115  		}
   116  
   117  		if !found {
   118  			dedupedSubjects = append(dedupedSubjects, subject)
   119  		}
   120  	}
   121  
   122  	return subjects, utilerrors.NewAggregate(errorlist)
   123  }
   124  

View as plain text