1
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
39
40 GetRoleReferenceRules(roleRef rbacv1.RoleRef, namespace string) ([]rbacv1.PolicyRule, error)
41
42
43
44
45 RulesFor(user user.Info, namespace string) ([]rbacv1.PolicyRule, error)
46
47
48
49 VisitRulesFor(user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool)
50 }
51
52
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
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
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
262
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
291
292 saNamespace := namespace
293 if len(subject.Namespace) > 0 {
294 saNamespace = subject.Namespace
295 }
296 if len(saNamespace) == 0 {
297 return false
298 }
299
300 return serviceaccount.MatchesUsername(saNamespace, subject.Name, user.GetName())
301 default:
302 return false
303 }
304 }
305
306
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
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
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 }
369
View as plain text