1
16
17
18 package policybased
19
20 import (
21 "context"
22 "errors"
23
24 apierrors "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 "k8s.io/apiserver/pkg/registry/rest"
29 kapihelper "k8s.io/kubernetes/pkg/apis/core/helper"
30 "k8s.io/kubernetes/pkg/apis/rbac"
31 rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
32 rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
33 )
34
35 var groupResource = rbac.Resource("clusterroles")
36
37 type Storage struct {
38 rest.StandardStorage
39
40 authorizer authorizer.Authorizer
41
42 ruleResolver rbacregistryvalidation.AuthorizationRuleResolver
43 }
44
45 func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleResolver rbacregistryvalidation.AuthorizationRuleResolver) *Storage {
46 return &Storage{s, authorizer, ruleResolver}
47 }
48
49
50 func (r *Storage) Destroy() {
51 r.StandardStorage.Destroy()
52 }
53
54 func (r *Storage) NamespaceScoped() bool {
55 return false
56 }
57
58 func (r *Storage) StorageVersion() runtime.GroupVersioner {
59 svp, ok := r.StandardStorage.(rest.StorageVersionProvider)
60 if !ok {
61 return nil
62 }
63 return svp.StorageVersion()
64 }
65
66 var _ rest.StorageVersionProvider = &Storage{}
67
68 var fullAuthority = []rbac.PolicyRule{
69 rbac.NewRule("*").Groups("*").Resources("*").RuleOrDie(),
70 rbac.NewRule("*").URLs("*").RuleOrDie(),
71 }
72
73 func (s *Storage) Create(ctx context.Context, obj runtime.Object, createValidatingAdmission rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
74 if rbacregistry.EscalationAllowed(ctx) || rbacregistry.RoleEscalationAuthorized(ctx, s.authorizer) {
75 return s.StandardStorage.Create(ctx, obj, createValidatingAdmission, options)
76 }
77
78 clusterRole := obj.(*rbac.ClusterRole)
79 rules := clusterRole.Rules
80 if err := rbacregistryvalidation.ConfirmNoEscalationInternal(ctx, s.ruleResolver, rules); err != nil {
81 return nil, apierrors.NewForbidden(groupResource, clusterRole.Name, err)
82 }
83
84 if hasAggregationRule(clusterRole) {
85 if err := rbacregistryvalidation.ConfirmNoEscalationInternal(ctx, s.ruleResolver, fullAuthority); err != nil {
86 return nil, apierrors.NewForbidden(groupResource, clusterRole.Name, errors.New("must have cluster-admin privileges to use the aggregationRule"))
87 }
88 }
89
90 return s.StandardStorage.Create(ctx, obj, createValidatingAdmission, options)
91 }
92
93 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) {
94 if rbacregistry.EscalationAllowed(ctx) || rbacregistry.RoleEscalationAuthorized(ctx, s.authorizer) {
95 return s.StandardStorage.Update(ctx, name, obj, createValidation, updateValidation, forceAllowCreate, options)
96 }
97
98 nonEscalatingInfo := rest.WrapUpdatedObjectInfo(obj, func(ctx context.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error) {
99 clusterRole := obj.(*rbac.ClusterRole)
100 oldClusterRole := oldObj.(*rbac.ClusterRole)
101
102
103 if rbacregistry.IsOnlyMutatingGCFields(obj, oldObj, kapihelper.Semantic) {
104 return obj, nil
105 }
106
107 rules := clusterRole.Rules
108 if err := rbacregistryvalidation.ConfirmNoEscalationInternal(ctx, s.ruleResolver, rules); err != nil {
109 return nil, apierrors.NewForbidden(groupResource, clusterRole.Name, err)
110 }
111
112 if hasAggregationRule(clusterRole) || hasAggregationRule(oldClusterRole) {
113 if err := rbacregistryvalidation.ConfirmNoEscalationInternal(ctx, s.ruleResolver, fullAuthority); err != nil {
114 return nil, apierrors.NewForbidden(groupResource, clusterRole.Name, errors.New("must have cluster-admin privileges to use the aggregationRule"))
115 }
116 }
117
118 return obj, nil
119 })
120
121 return s.StandardStorage.Update(ctx, name, nonEscalatingInfo, createValidation, updateValidation, forceAllowCreate, options)
122 }
123
124 func hasAggregationRule(clusterRole *rbac.ClusterRole) bool {
125 return clusterRole.AggregationRule != nil && len(clusterRole.AggregationRule.ClusterRoleSelectors) > 0
126 }
127
128 var _ rest.SingularNameProvider = &Storage{}
129
130 func (s *Storage) GetSingularName() string {
131 snp, ok := s.StandardStorage.(rest.SingularNameProvider)
132 if !ok {
133 return ""
134 }
135 return snp.GetSingularName()
136 }
137
View as plain text