1
16
17 package rbac
18
19 import (
20 "fmt"
21 "strings"
22
23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24 "k8s.io/apimachinery/pkg/util/sets"
25 )
26
27
28 func ResourceMatches(rule *PolicyRule, combinedRequestedResource, requestedSubresource string) bool {
29 for _, ruleResource := range rule.Resources {
30
31 if ruleResource == ResourceAll {
32 return true
33 }
34
35 if ruleResource == combinedRequestedResource {
36 return true
37 }
38
39
40
41 if len(requestedSubresource) == 0 {
42 continue
43 }
44
45 if len(ruleResource) == len(requestedSubresource)+2 &&
46 strings.HasPrefix(ruleResource, "*/") &&
47 strings.HasSuffix(ruleResource, requestedSubresource) {
48 return true
49
50 }
51 }
52
53 return false
54 }
55
56
57 func SubjectsStrings(subjects []Subject) ([]string, []string, []string, []string) {
58 users := []string{}
59 groups := []string{}
60 sas := []string{}
61 others := []string{}
62
63 for _, subject := range subjects {
64 switch subject.Kind {
65 case ServiceAccountKind:
66 sas = append(sas, fmt.Sprintf("%s/%s", subject.Namespace, subject.Name))
67
68 case UserKind:
69 users = append(users, subject.Name)
70
71 case GroupKind:
72 groups = append(groups, subject.Name)
73
74 default:
75 others = append(others, fmt.Sprintf("%s/%s/%s", subject.Kind, subject.Namespace, subject.Name))
76 }
77 }
78
79 return users, groups, sas, others
80 }
81
82 func (r PolicyRule) String() string {
83 return "PolicyRule" + r.CompactString()
84 }
85
86
87 func (r PolicyRule) CompactString() string {
88 formatStringParts := []string{}
89 formatArgs := []interface{}{}
90 if len(r.APIGroups) > 0 {
91 formatStringParts = append(formatStringParts, "APIGroups:%q")
92 formatArgs = append(formatArgs, r.APIGroups)
93 }
94 if len(r.Resources) > 0 {
95 formatStringParts = append(formatStringParts, "Resources:%q")
96 formatArgs = append(formatArgs, r.Resources)
97 }
98 if len(r.NonResourceURLs) > 0 {
99 formatStringParts = append(formatStringParts, "NonResourceURLs:%q")
100 formatArgs = append(formatArgs, r.NonResourceURLs)
101 }
102 if len(r.ResourceNames) > 0 {
103 formatStringParts = append(formatStringParts, "ResourceNames:%q")
104 formatArgs = append(formatArgs, r.ResourceNames)
105 }
106 if len(r.Verbs) > 0 {
107 formatStringParts = append(formatStringParts, "Verbs:%q")
108 formatArgs = append(formatArgs, r.Verbs)
109 }
110 formatString := "{" + strings.Join(formatStringParts, ", ") + "}"
111 return fmt.Sprintf(formatString, formatArgs...)
112 }
113
114
115
116
117
118 type PolicyRuleBuilder struct {
119 PolicyRule PolicyRule
120 }
121
122
123 func NewRule(verbs ...string) *PolicyRuleBuilder {
124 return &PolicyRuleBuilder{
125 PolicyRule: PolicyRule{Verbs: sets.NewString(verbs...).List()},
126 }
127 }
128
129
130 func (r *PolicyRuleBuilder) Groups(groups ...string) *PolicyRuleBuilder {
131 r.PolicyRule.APIGroups = combine(r.PolicyRule.APIGroups, groups)
132 return r
133 }
134
135
136 func (r *PolicyRuleBuilder) Resources(resources ...string) *PolicyRuleBuilder {
137 r.PolicyRule.Resources = combine(r.PolicyRule.Resources, resources)
138 return r
139 }
140
141
142 func (r *PolicyRuleBuilder) Names(names ...string) *PolicyRuleBuilder {
143 r.PolicyRule.ResourceNames = combine(r.PolicyRule.ResourceNames, names)
144 return r
145 }
146
147
148 func (r *PolicyRuleBuilder) URLs(urls ...string) *PolicyRuleBuilder {
149 r.PolicyRule.NonResourceURLs = combine(r.PolicyRule.NonResourceURLs, urls)
150 return r
151 }
152
153
154 func (r *PolicyRuleBuilder) RuleOrDie() PolicyRule {
155 ret, err := r.Rule()
156 if err != nil {
157 panic(err)
158 }
159 return ret
160 }
161
162 func combine(s1, s2 []string) []string {
163 s := sets.NewString(s1...)
164 s.Insert(s2...)
165 return s.List()
166 }
167
168
169 func (r *PolicyRuleBuilder) Rule() (PolicyRule, error) {
170 if len(r.PolicyRule.Verbs) == 0 {
171 return PolicyRule{}, fmt.Errorf("verbs are required: %#v", r.PolicyRule)
172 }
173
174 switch {
175 case len(r.PolicyRule.NonResourceURLs) > 0:
176 if len(r.PolicyRule.APIGroups) != 0 || len(r.PolicyRule.Resources) != 0 || len(r.PolicyRule.ResourceNames) != 0 {
177 return PolicyRule{}, fmt.Errorf("non-resource rule may not have apiGroups, resources, or resourceNames: %#v", r.PolicyRule)
178 }
179 case len(r.PolicyRule.Resources) > 0:
180
181
182 if len(r.PolicyRule.APIGroups) == 0 {
183
184 return PolicyRule{}, fmt.Errorf("resource rule must have apiGroups: %#v", r.PolicyRule)
185 }
186
187
188
189 if len(r.PolicyRule.ResourceNames) != 0 {
190 illegalVerbs := []string{}
191 for _, verb := range r.PolicyRule.Verbs {
192 switch verb {
193 case "list", "watch", "create", "deletecollection":
194 illegalVerbs = append(illegalVerbs, verb)
195 }
196 }
197 if len(illegalVerbs) > 0 {
198 return PolicyRule{}, fmt.Errorf("verbs %v do not have names available: %#v", illegalVerbs, r.PolicyRule)
199 }
200 }
201
202 default:
203 return PolicyRule{}, fmt.Errorf("a rule must have either nonResourceURLs or resources: %#v", r.PolicyRule)
204 }
205
206 return r.PolicyRule, nil
207 }
208
209
210
211
212
213 type ClusterRoleBindingBuilder struct {
214 ClusterRoleBinding ClusterRoleBinding
215 }
216
217
218
219
220
221 func NewClusterBinding(clusterRoleName string) *ClusterRoleBindingBuilder {
222 return &ClusterRoleBindingBuilder{
223 ClusterRoleBinding: ClusterRoleBinding{
224 ObjectMeta: metav1.ObjectMeta{Name: clusterRoleName},
225 RoleRef: RoleRef{
226 APIGroup: GroupName,
227 Kind: "ClusterRole",
228 Name: clusterRoleName,
229 },
230 },
231 }
232 }
233
234
235 func (r *ClusterRoleBindingBuilder) Groups(groups ...string) *ClusterRoleBindingBuilder {
236 for _, group := range groups {
237 r.ClusterRoleBinding.Subjects = append(r.ClusterRoleBinding.Subjects, Subject{Kind: GroupKind, APIGroup: GroupName, Name: group})
238 }
239 return r
240 }
241
242
243 func (r *ClusterRoleBindingBuilder) Users(users ...string) *ClusterRoleBindingBuilder {
244 for _, user := range users {
245 r.ClusterRoleBinding.Subjects = append(r.ClusterRoleBinding.Subjects, Subject{Kind: UserKind, APIGroup: GroupName, Name: user})
246 }
247 return r
248 }
249
250
251 func (r *ClusterRoleBindingBuilder) SAs(namespace string, serviceAccountNames ...string) *ClusterRoleBindingBuilder {
252 for _, saName := range serviceAccountNames {
253 r.ClusterRoleBinding.Subjects = append(r.ClusterRoleBinding.Subjects, Subject{Kind: ServiceAccountKind, Namespace: namespace, Name: saName})
254 }
255 return r
256 }
257
258
259 func (r *ClusterRoleBindingBuilder) BindingOrDie() ClusterRoleBinding {
260 ret, err := r.Binding()
261 if err != nil {
262 panic(err)
263 }
264 return ret
265 }
266
267
268
269 func (r *ClusterRoleBindingBuilder) Binding() (ClusterRoleBinding, error) {
270 if len(r.ClusterRoleBinding.Subjects) == 0 {
271 return ClusterRoleBinding{}, fmt.Errorf("subjects are required: %#v", r.ClusterRoleBinding)
272 }
273
274 return r.ClusterRoleBinding, nil
275 }
276
277
278
279
280 type RoleBindingBuilder struct {
281 RoleBinding RoleBinding
282 }
283
284
285
286
287
288 func NewRoleBinding(roleName, namespace string) *RoleBindingBuilder {
289 return &RoleBindingBuilder{
290 RoleBinding: RoleBinding{
291 ObjectMeta: metav1.ObjectMeta{
292 Name: roleName,
293 Namespace: namespace,
294 },
295 RoleRef: RoleRef{
296 APIGroup: GroupName,
297 Kind: "Role",
298 Name: roleName,
299 },
300 },
301 }
302 }
303
304
305
306
307
308 func NewRoleBindingForClusterRole(roleName, namespace string) *RoleBindingBuilder {
309 return &RoleBindingBuilder{
310 RoleBinding: RoleBinding{
311 ObjectMeta: metav1.ObjectMeta{
312 Name: roleName,
313 Namespace: namespace,
314 },
315 RoleRef: RoleRef{
316 APIGroup: GroupName,
317 Kind: "ClusterRole",
318 Name: roleName,
319 },
320 },
321 }
322 }
323
324
325 func (r *RoleBindingBuilder) Groups(groups ...string) *RoleBindingBuilder {
326 for _, group := range groups {
327 r.RoleBinding.Subjects = append(r.RoleBinding.Subjects, Subject{Kind: GroupKind, APIGroup: GroupName, Name: group})
328 }
329 return r
330 }
331
332
333 func (r *RoleBindingBuilder) Users(users ...string) *RoleBindingBuilder {
334 for _, user := range users {
335 r.RoleBinding.Subjects = append(r.RoleBinding.Subjects, Subject{Kind: UserKind, APIGroup: GroupName, Name: user})
336 }
337 return r
338 }
339
340
341
342 func (r *RoleBindingBuilder) SAs(namespace string, serviceAccountNames ...string) *RoleBindingBuilder {
343 for _, saName := range serviceAccountNames {
344 r.RoleBinding.Subjects = append(r.RoleBinding.Subjects, Subject{Kind: ServiceAccountKind, Namespace: namespace, Name: saName})
345 }
346 return r
347 }
348
349
350 func (r *RoleBindingBuilder) BindingOrDie() RoleBinding {
351 ret, err := r.Binding()
352 if err != nil {
353 panic(err)
354 }
355 return ret
356 }
357
358
359
360 func (r *RoleBindingBuilder) Binding() (RoleBinding, error) {
361 if len(r.RoleBinding.Subjects) == 0 {
362 return RoleBinding{}, fmt.Errorf("subjects are required: %#v", r.RoleBinding)
363 }
364
365 return r.RoleBinding, nil
366 }
367
368
369 type SortableRuleSlice []PolicyRule
370
371 func (s SortableRuleSlice) Len() int { return len(s) }
372 func (s SortableRuleSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
373 func (s SortableRuleSlice) Less(i, j int) bool {
374 return strings.Compare(s[i].String(), s[j].String()) < 0
375 }
376
View as plain text