1/* 2Copyright 2016 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package validation 18 19import ( 20 "context" 21 "errors" 22 "fmt" 23 "strings" 24 25 "k8s.io/klog/v2" 26 27 rbacv1 "k8s.io/api/rbac/v1" 28 utilerrors "k8s.io/apimachinery/pkg/util/errors" 29 "k8s.io/apimachinery/pkg/util/sets" 30 "k8s.io/apiserver/pkg/authentication/serviceaccount" 31 "k8s.io/apiserver/pkg/authentication/user" 32 genericapirequest "k8s.io/apiserver/pkg/endpoints/request" 33 "k8s.io/component-helpers/auth/rbac/validation" 34 rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1" 35) 36 37type AuthorizationRuleResolver interface { 38 // GetRoleReferenceRules attempts to resolve the role reference of a RoleBinding or ClusterRoleBinding. The passed namespace should be the namespace 39 // of the role binding, the empty string if a cluster role binding. 40 GetRoleReferenceRules(roleRef rbacv1.RoleRef, namespace string) ([]rbacv1.PolicyRule, error) 41 42 // RulesFor returns the list of rules that apply to a given user in a given namespace and error. If an error is returned, the slice of 43 // PolicyRules may not be complete, but it contains all retrievable rules. This is done because policy rules are purely additive and policy determinations 44 // can be made on the basis of those rules that are found. 45 RulesFor(user user.Info, namespace string) ([]rbacv1.PolicyRule, error) 46 47 // VisitRulesFor invokes visitor() with each rule that applies to a given user in a given namespace, and each error encountered resolving those rules. 48 // If visitor() returns false, visiting is short-circuited. 49 VisitRulesFor(user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool) 50} 51 52// ConfirmNoEscalation determines if the roles for a given user in a given namespace encompass the provided role. 53func ConfirmNoEscalation(ctx context.Context, ruleResolver AuthorizationRuleResolver, rules []rbacv1.PolicyRule) error { 54 ruleResolutionErrors := []error{} 55 56 user, ok := genericapirequest.UserFrom(ctx) 57 if !ok { 58 return fmt.Errorf("no user on context") 59 } 60 namespace, _ := genericapirequest.NamespaceFrom(ctx) 61 62 ownerRules, err := ruleResolver.RulesFor(user, namespace) 63 if err != nil { 64 // As per AuthorizationRuleResolver contract, this may return a non fatal error with an incomplete list of policies. Log the error and continue. 65 klog.V(1).Infof("non-fatal error getting local rules for %v: %v", user, err) 66 ruleResolutionErrors = append(ruleResolutionErrors, err) 67 } 68 69 ownerRightsCover, missingRights := validation.Covers(ownerRules, rules) 70 if !ownerRightsCover { 71 compactMissingRights := missingRights 72 if compact, err := CompactRules(missingRights); err == nil { 73 compactMissingRights = compact 74 } 75 76 missingDescriptions := sets.NewString() 77 for _, missing := range compactMissingRights { 78 missingDescriptions.Insert(rbacv1helpers.CompactString(missing)) 79 } 80 81 msg := fmt.Sprintf("user %q (groups=%q) is attempting to grant RBAC permissions not currently held:\n%s", user.GetName(), user.GetGroups(), strings.Join(missingDescriptions.List(), "\n")) 82 if len(ruleResolutionErrors) > 0 { 83 msg = msg + fmt.Sprintf("; resolution errors: %v", ruleResolutionErrors) 84 } 85 86 return errors.New(msg) 87 } 88 return nil 89} 90 91type DefaultRuleResolver struct { 92 roleGetter RoleGetter 93 roleBindingLister RoleBindingLister 94 clusterRoleGetter ClusterRoleGetter 95 clusterRoleBindingLister ClusterRoleBindingLister 96} 97 98func NewDefaultRuleResolver(roleGetter RoleGetter, roleBindingLister RoleBindingLister, clusterRoleGetter ClusterRoleGetter, clusterRoleBindingLister ClusterRoleBindingLister) *DefaultRuleResolver { 99 return &DefaultRuleResolver{roleGetter, roleBindingLister, clusterRoleGetter, clusterRoleBindingLister} 100} 101 102type RoleGetter interface { 103 GetRole(namespace, name string) (*rbacv1.Role, error) 104} 105 106type RoleBindingLister interface { 107 ListRoleBindings(namespace string) ([]*rbacv1.RoleBinding, error) 108} 109 110type ClusterRoleGetter interface { 111 GetClusterRole(name string) (*rbacv1.ClusterRole, error) 112} 113 114type ClusterRoleBindingLister interface { 115 ListClusterRoleBindings() ([]*rbacv1.ClusterRoleBinding, error) 116} 117 118func (r *DefaultRuleResolver) RulesFor(user user.Info, namespace string) ([]rbacv1.PolicyRule, error) { 119 visitor := &ruleAccumulator{} 120 r.VisitRulesFor(user, namespace, visitor.visit) 121 return visitor.rules, utilerrors.NewAggregate(visitor.errors) 122} 123 124type ruleAccumulator struct { 125 rules []rbacv1.PolicyRule 126 errors []error 127} 128 129func (r *ruleAccumulator) visit(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool { 130 if rule != nil { 131 r.rules = append(r.rules, *rule) 132 } 133 if err != nil { 134 r.errors = append(r.errors, err) 135 } 136 return true 137} 138 139func describeSubject(s *rbacv1.Subject, bindingNamespace string) string { 140 switch s.Kind { 141 case rbacv1.ServiceAccountKind: 142 if len(s.Namespace) > 0 { 143 return fmt.Sprintf("%s %q", s.Kind, s.Name+"/"+s.Namespace) 144 } 145 return fmt.Sprintf("%s %q", s.Kind, s.Name+"/"+bindingNamespace) 146 default: 147 return fmt.Sprintf("%s %q", s.Kind, s.Name) 148 } 149} 150 151type clusterRoleBindingDescriber struct { 152 binding *rbacv1.ClusterRoleBinding 153 subject *rbacv1.Subject 154} 155 156func (d *clusterRoleBindingDescriber) String() string { 157 return fmt.Sprintf("ClusterRoleBinding %q of %s %q to %s", 158 d.binding.Name, 159 d.binding.RoleRef.Kind, 160 d.binding.RoleRef.Name, 161 describeSubject(d.subject, ""), 162 ) 163} 164 165type roleBindingDescriber struct { 166 binding *rbacv1.RoleBinding 167 subject *rbacv1.Subject 168} 169 170func (d *roleBindingDescriber) String() string { 171 return fmt.Sprintf("RoleBinding %q of %s %q to %s", 172 d.binding.Name+"/"+d.binding.Namespace, 173 d.binding.RoleRef.Kind, 174 d.binding.RoleRef.Name, 175 describeSubject(d.subject, d.binding.Namespace), 176 ) 177} 178 179func (r *DefaultRuleResolver) VisitRulesFor(user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool) { 180 if clusterRoleBindings, err := r.clusterRoleBindingLister.ListClusterRoleBindings(); err != nil { 181 if !visitor(nil, nil, err) { 182 return 183 } 184 } else { 185 sourceDescriber := &clusterRoleBindingDescriber{} 186 for _, clusterRoleBinding := range clusterRoleBindings { 187 subjectIndex, applies := appliesTo(user, clusterRoleBinding.Subjects, "") 188 if !applies { 189 continue 190 } 191 rules, err := r.GetRoleReferenceRules(clusterRoleBinding.RoleRef, "") 192 if err != nil { 193 if !visitor(nil, nil, err) { 194 return 195 } 196 continue 197 } 198 sourceDescriber.binding = clusterRoleBinding 199 sourceDescriber.subject = &clusterRoleBinding.Subjects[subjectIndex] 200 for i := range rules { 201 if !visitor(sourceDescriber, &rules[i], nil) { 202 return 203 } 204 } 205 } 206 } 207 208 if len(namespace) > 0 { 209 if roleBindings, err := r.roleBindingLister.ListRoleBindings(namespace); err != nil { 210 if !visitor(nil, nil, err) { 211 return 212 } 213 } else { 214 sourceDescriber := &roleBindingDescriber{} 215 for _, roleBinding := range roleBindings { 216 subjectIndex, applies := appliesTo(user, roleBinding.Subjects, namespace) 217 if !applies { 218 continue 219 } 220 rules, err := r.GetRoleReferenceRules(roleBinding.RoleRef, namespace) 221 if err != nil { 222 if !visitor(nil, nil, err) { 223 return 224 } 225 continue 226 } 227 sourceDescriber.binding = roleBinding 228 sourceDescriber.subject = &roleBinding.Subjects[subjectIndex] 229 for i := range rules { 230 if !visitor(sourceDescriber, &rules[i], nil) { 231 return 232 } 233 } 234 } 235 } 236 } 237} 238 239// GetRoleReferenceRules attempts to resolve the RoleBinding or ClusterRoleBinding. 240func (r *DefaultRuleResolver) GetRoleReferenceRules(roleRef rbacv1.RoleRef, bindingNamespace string) ([]rbacv1.PolicyRule, error) { 241 switch roleRef.Kind { 242 case "Role": 243 role, err := r.roleGetter.GetRole(bindingNamespace, roleRef.Name) 244 if err != nil { 245 return nil, err 246 } 247 return role.Rules, nil 248 249 case "ClusterRole": 250 clusterRole, err := r.clusterRoleGetter.GetClusterRole(roleRef.Name) 251 if err != nil { 252 return nil, err 253 } 254 return clusterRole.Rules, nil 255 256 default: 257 return nil, fmt.Errorf("unsupported role reference kind: %q", roleRef.Kind) 258 } 259} 260 261// appliesTo returns whether any of the bindingSubjects applies to the specified subject, 262// and if true, the index of the first subject that applies 263func appliesTo(user user.Info, bindingSubjects []rbacv1.Subject, namespace string) (int, bool) { 264 for i, bindingSubject := range bindingSubjects { 265 if appliesToUser(user, bindingSubject, namespace) { 266 return i, true 267 } 268 } 269 return 0, false 270} 271 272func has(set []string, ele string) bool { 273 for _, s := range set { 274 if s == ele { 275 return true 276 } 277 } 278 return false 279} 280 281func appliesToUser(user user.Info, subject rbacv1.Subject, namespace string) bool { 282 switch subject.Kind { 283 case rbacv1.UserKind: 284 return user.GetName() == subject.Name 285 286 case rbacv1.GroupKind: 287 return has(user.GetGroups(), subject.Name) 288 289 case rbacv1.ServiceAccountKind: 290 // default the namespace to namespace we're working in if its available. This allows rolebindings that reference 291 // SAs in th local namespace to avoid having to qualify them. 292 saNamespace := namespace 293 if len(subject.Namespace) > 0 { 294 saNamespace = subject.Namespace 295 } 296 if len(saNamespace) == 0 { 297 return false 298 } 299 // use a more efficient comparison for RBAC checking 300 return serviceaccount.MatchesUsername(saNamespace, subject.Name, user.GetName()) 301 default: 302 return false 303 } 304} 305 306// NewTestRuleResolver returns a rule resolver from lists of role objects. 307func NewTestRuleResolver(roles []*rbacv1.Role, roleBindings []*rbacv1.RoleBinding, clusterRoles []*rbacv1.ClusterRole, clusterRoleBindings []*rbacv1.ClusterRoleBinding) (AuthorizationRuleResolver, *StaticRoles) { 308 r := StaticRoles{ 309 roles: roles, 310 roleBindings: roleBindings, 311 clusterRoles: clusterRoles, 312 clusterRoleBindings: clusterRoleBindings, 313 } 314 return newMockRuleResolver(&r), &r 315} 316 317func newMockRuleResolver(r *StaticRoles) AuthorizationRuleResolver { 318 return NewDefaultRuleResolver(r, r, r, r) 319} 320 321// StaticRoles is a rule resolver that resolves from lists of role objects. 322type StaticRoles struct { 323 roles []*rbacv1.Role 324 roleBindings []*rbacv1.RoleBinding 325 clusterRoles []*rbacv1.ClusterRole 326 clusterRoleBindings []*rbacv1.ClusterRoleBinding 327} 328 329func (r *StaticRoles) GetRole(namespace, name string) (*rbacv1.Role, error) { 330 if len(namespace) == 0 { 331 return nil, errors.New("must provide namespace when getting role") 332 } 333 for _, role := range r.roles { 334 if role.Namespace == namespace && role.Name == name { 335 return role, nil 336 } 337 } 338 return nil, errors.New("role not found") 339} 340 341func (r *StaticRoles) GetClusterRole(name string) (*rbacv1.ClusterRole, error) { 342 for _, clusterRole := range r.clusterRoles { 343 if clusterRole.Name == name { 344 return clusterRole, nil 345 } 346 } 347 return nil, errors.New("clusterrole not found") 348} 349 350func (r *StaticRoles) ListRoleBindings(namespace string) ([]*rbacv1.RoleBinding, error) { 351 if len(namespace) == 0 { 352 return nil, errors.New("must provide namespace when listing role bindings") 353 } 354 355 roleBindingList := []*rbacv1.RoleBinding{} 356 for _, roleBinding := range r.roleBindings { 357 if roleBinding.Namespace != namespace { 358 continue 359 } 360 // TODO(ericchiang): need to implement label selectors? 361 roleBindingList = append(roleBindingList, roleBinding) 362 } 363 return roleBindingList, nil 364} 365 366func (r *StaticRoles) ListClusterRoleBindings() ([]*rbacv1.ClusterRoleBinding, error) { 367 return r.clusterRoleBindings, nil 368} 369