1
16
17
18 package policybased
19
20 import (
21 "context"
22
23 rbacv1 "k8s.io/api/rbac/v1"
24 "k8s.io/apimachinery/pkg/api/errors"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 "k8s.io/apimachinery/pkg/runtime"
27 "k8s.io/apiserver/pkg/authorization/authorizer"
28 genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
29 "k8s.io/apiserver/pkg/registry/rest"
30 kapihelper "k8s.io/kubernetes/pkg/apis/core/helper"
31 "k8s.io/kubernetes/pkg/apis/rbac"
32 rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1"
33 rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
34 rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
35 )
36
37 var groupResource = rbac.Resource("rolebindings")
38
39 type Storage struct {
40 rest.StandardStorage
41
42 authorizer authorizer.Authorizer
43
44 ruleResolver rbacregistryvalidation.AuthorizationRuleResolver
45 }
46
47 func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleResolver rbacregistryvalidation.AuthorizationRuleResolver) *Storage {
48 return &Storage{s, authorizer, ruleResolver}
49 }
50
51
52 func (r *Storage) Destroy() {
53 r.StandardStorage.Destroy()
54 }
55
56 func (r *Storage) NamespaceScoped() bool {
57 return true
58 }
59
60 func (r *Storage) StorageVersion() runtime.GroupVersioner {
61 svp, ok := r.StandardStorage.(rest.StorageVersionProvider)
62 if !ok {
63 return nil
64 }
65 return svp.StorageVersion()
66 }
67
68 var _ rest.StorageVersionProvider = &Storage{}
69
70 func (s *Storage) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
71 if rbacregistry.EscalationAllowed(ctx) {
72 return s.StandardStorage.Create(ctx, obj, createValidation, options)
73 }
74
75
76
77 namespace, ok := genericapirequest.NamespaceFrom(ctx)
78 if !ok {
79 return nil, errors.NewBadRequest("namespace is required")
80 }
81
82 roleBinding := obj.(*rbac.RoleBinding)
83 if rbacregistry.BindingAuthorized(ctx, roleBinding.RoleRef, namespace, s.authorizer) {
84 return s.StandardStorage.Create(ctx, obj, createValidation, options)
85 }
86
87 v1RoleRef := rbacv1.RoleRef{}
88 err := rbacv1helpers.Convert_rbac_RoleRef_To_v1_RoleRef(&roleBinding.RoleRef, &v1RoleRef, nil)
89 if err != nil {
90 return nil, err
91 }
92 rules, err := s.ruleResolver.GetRoleReferenceRules(v1RoleRef, namespace)
93 if err != nil {
94 return nil, err
95 }
96 if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
97 return nil, errors.NewForbidden(groupResource, roleBinding.Name, err)
98 }
99 return s.StandardStorage.Create(ctx, obj, createValidation, options)
100 }
101
102 func (s *Storage) Update(ctx context.Context, name string, obj rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
103 if rbacregistry.EscalationAllowed(ctx) {
104 return s.StandardStorage.Update(ctx, name, obj, createValidation, updateValidation, forceAllowCreate, options)
105 }
106
107 nonEscalatingInfo := rest.WrapUpdatedObjectInfo(obj, func(ctx context.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error) {
108
109
110 namespace, ok := genericapirequest.NamespaceFrom(ctx)
111 if !ok {
112 return nil, errors.NewBadRequest("namespace is required")
113 }
114
115 roleBinding := obj.(*rbac.RoleBinding)
116
117
118 if rbacregistry.IsOnlyMutatingGCFields(obj, oldObj, kapihelper.Semantic) {
119 return obj, nil
120 }
121
122
123 if rbacregistry.BindingAuthorized(ctx, roleBinding.RoleRef, namespace, s.authorizer) {
124 return obj, nil
125 }
126
127
128 v1RoleRef := rbacv1.RoleRef{}
129 err := rbacv1helpers.Convert_rbac_RoleRef_To_v1_RoleRef(&roleBinding.RoleRef, &v1RoleRef, nil)
130 if err != nil {
131 return nil, err
132 }
133 rules, err := s.ruleResolver.GetRoleReferenceRules(v1RoleRef, namespace)
134 if err != nil {
135 return nil, err
136 }
137 if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
138 return nil, errors.NewForbidden(groupResource, roleBinding.Name, err)
139 }
140 return obj, nil
141 })
142
143 return s.StandardStorage.Update(ctx, name, nonEscalatingInfo, createValidation, updateValidation, forceAllowCreate, options)
144 }
145
146 var _ rest.SingularNameProvider = &Storage{}
147
148 func (s *Storage) GetSingularName() string {
149 snp, ok := s.StandardStorage.(rest.SingularNameProvider)
150 if !ok {
151 return ""
152 }
153 return snp.GetSingularName()
154 }
155
View as plain text