k8s.io/kubernetes@v1.29.3/pkg/registry/rbac/validation/rule.go (about) 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 validation 18 19 import ( 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 37 type 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. 53 func 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 91 type DefaultRuleResolver struct { 92 roleGetter RoleGetter 93 roleBindingLister RoleBindingLister 94 clusterRoleGetter ClusterRoleGetter 95 clusterRoleBindingLister ClusterRoleBindingLister 96 } 97 98 func NewDefaultRuleResolver(roleGetter RoleGetter, roleBindingLister RoleBindingLister, clusterRoleGetter ClusterRoleGetter, clusterRoleBindingLister ClusterRoleBindingLister) *DefaultRuleResolver { 99 return &DefaultRuleResolver{roleGetter, roleBindingLister, clusterRoleGetter, clusterRoleBindingLister} 100 } 101 102 type RoleGetter interface { 103 GetRole(namespace, name string) (*rbacv1.Role, error) 104 } 105 106 type RoleBindingLister interface { 107 ListRoleBindings(namespace string) ([]*rbacv1.RoleBinding, error) 108 } 109 110 type ClusterRoleGetter interface { 111 GetClusterRole(name string) (*rbacv1.ClusterRole, error) 112 } 113 114 type ClusterRoleBindingLister interface { 115 ListClusterRoleBindings() ([]*rbacv1.ClusterRoleBinding, error) 116 } 117 118 func (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 124 type ruleAccumulator struct { 125 rules []rbacv1.PolicyRule 126 errors []error 127 } 128 129 func (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 139 func 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 151 type clusterRoleBindingDescriber struct { 152 binding *rbacv1.ClusterRoleBinding 153 subject *rbacv1.Subject 154 } 155 156 func (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 165 type roleBindingDescriber struct { 166 binding *rbacv1.RoleBinding 167 subject *rbacv1.Subject 168 } 169 170 func (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 179 func (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. 240 func (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 263 func 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 272 func 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 281 func 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. 307 func 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 317 func 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. 322 type StaticRoles struct { 323 roles []*rbacv1.Role 324 roleBindings []*rbacv1.RoleBinding 325 clusterRoles []*rbacv1.ClusterRole 326 clusterRoleBindings []*rbacv1.ClusterRoleBinding 327 } 328 329 func (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 341 func (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 350 func (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 366 func (r *StaticRoles) ListClusterRoleBindings() ([]*rbacv1.ClusterRoleBinding, error) { 367 return r.clusterRoleBindings, nil 368 }