1/* 2Copyright 2016 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package rbac 18 19import ( 20 "context" 21 "fmt" 22 "strings" 23 "testing" 24 25 rbacv1 "k8s.io/api/rbac/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apiserver/pkg/authentication/user" 28 "k8s.io/apiserver/pkg/authorization/authorizer" 29 rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1" 30 rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation" 31 "k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy" 32) 33 34func newRule(verbs, apiGroups, resources, nonResourceURLs string) rbacv1.PolicyRule { 35 return rbacv1.PolicyRule{ 36 Verbs: strings.Split(verbs, ","), 37 APIGroups: strings.Split(apiGroups, ","), 38 Resources: strings.Split(resources, ","), 39 NonResourceURLs: strings.Split(nonResourceURLs, ","), 40 } 41} 42 43func newRole(name, namespace string, rules ...rbacv1.PolicyRule) *rbacv1.Role { 44 return &rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: name}, Rules: rules} 45} 46 47func newClusterRole(name string, rules ...rbacv1.PolicyRule) *rbacv1.ClusterRole { 48 return &rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: name}, Rules: rules} 49} 50 51const ( 52 bindToRole uint16 = 0x0 53 bindToClusterRole uint16 = 0x1 54) 55 56func newClusterRoleBinding(roleName string, subjects ...string) *rbacv1.ClusterRoleBinding { 57 r := &rbacv1.ClusterRoleBinding{ 58 ObjectMeta: metav1.ObjectMeta{}, 59 RoleRef: rbacv1.RoleRef{ 60 APIGroup: rbacv1.GroupName, 61 Kind: "ClusterRole", // ClusterRoleBindings can only refer to ClusterRole 62 Name: roleName, 63 }, 64 } 65 66 r.Subjects = make([]rbacv1.Subject, len(subjects)) 67 for i, subject := range subjects { 68 split := strings.SplitN(subject, ":", 2) 69 r.Subjects[i].Kind, r.Subjects[i].Name = split[0], split[1] 70 71 switch r.Subjects[i].Kind { 72 case rbacv1.ServiceAccountKind: 73 r.Subjects[i].APIGroup = "" 74 case rbacv1.UserKind, rbacv1.GroupKind: 75 r.Subjects[i].APIGroup = rbacv1.GroupName 76 default: 77 panic(fmt.Errorf("invalid kind %s", r.Subjects[i].Kind)) 78 } 79 } 80 return r 81} 82 83func newRoleBinding(namespace, roleName string, bindType uint16, subjects ...string) *rbacv1.RoleBinding { 84 r := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Namespace: namespace}} 85 86 switch bindType { 87 case bindToRole: 88 r.RoleRef = rbacv1.RoleRef{APIGroup: rbacv1.GroupName, Kind: "Role", Name: roleName} 89 case bindToClusterRole: 90 r.RoleRef = rbacv1.RoleRef{APIGroup: rbacv1.GroupName, Kind: "ClusterRole", Name: roleName} 91 } 92 93 r.Subjects = make([]rbacv1.Subject, len(subjects)) 94 for i, subject := range subjects { 95 split := strings.SplitN(subject, ":", 2) 96 r.Subjects[i].Kind, r.Subjects[i].Name = split[0], split[1] 97 98 switch r.Subjects[i].Kind { 99 case rbacv1.ServiceAccountKind: 100 r.Subjects[i].APIGroup = "" 101 case rbacv1.UserKind, rbacv1.GroupKind: 102 r.Subjects[i].APIGroup = rbacv1.GroupName 103 default: 104 panic(fmt.Errorf("invalid kind %s", r.Subjects[i].Kind)) 105 } 106 } 107 return r 108} 109 110type defaultAttributes struct { 111 user string 112 groups string 113 verb string 114 resource string 115 subresource string 116 namespace string 117 apiGroup string 118} 119 120func (d *defaultAttributes) String() string { 121 return fmt.Sprintf("user=(%s), groups=(%s), verb=(%s), resource=(%s), namespace=(%s), apiGroup=(%s)", 122 d.user, strings.Split(d.groups, ","), d.verb, d.resource, d.namespace, d.apiGroup) 123} 124 125func (d *defaultAttributes) GetUser() user.Info { 126 return &user.DefaultInfo{Name: d.user, Groups: strings.Split(d.groups, ",")} 127} 128func (d *defaultAttributes) GetVerb() string { return d.verb } 129func (d *defaultAttributes) IsReadOnly() bool { return d.verb == "get" || d.verb == "watch" } 130func (d *defaultAttributes) GetNamespace() string { return d.namespace } 131func (d *defaultAttributes) GetResource() string { return d.resource } 132func (d *defaultAttributes) GetSubresource() string { return d.subresource } 133func (d *defaultAttributes) GetName() string { return "" } 134func (d *defaultAttributes) GetAPIGroup() string { return d.apiGroup } 135func (d *defaultAttributes) GetAPIVersion() string { return "" } 136func (d *defaultAttributes) IsResourceRequest() bool { return true } 137func (d *defaultAttributes) GetPath() string { return "" } 138 139func TestAuthorizer(t *testing.T) { 140 tests := []struct { 141 roles []*rbacv1.Role 142 roleBindings []*rbacv1.RoleBinding 143 clusterRoles []*rbacv1.ClusterRole 144 clusterRoleBindings []*rbacv1.ClusterRoleBinding 145 146 shouldPass []authorizer.Attributes 147 shouldFail []authorizer.Attributes 148 }{ 149 { 150 clusterRoles: []*rbacv1.ClusterRole{ 151 newClusterRole("admin", newRule("*", "*", "*", "*")), 152 }, 153 roleBindings: []*rbacv1.RoleBinding{ 154 newRoleBinding("ns1", "admin", bindToClusterRole, "User:admin", "Group:admins"), 155 }, 156 shouldPass: []authorizer.Attributes{ 157 &defaultAttributes{"admin", "", "get", "Pods", "", "ns1", ""}, 158 &defaultAttributes{"admin", "", "watch", "Pods", "", "ns1", ""}, 159 &defaultAttributes{"admin", "group1", "watch", "Foobar", "", "ns1", ""}, 160 &defaultAttributes{"joe", "admins", "watch", "Foobar", "", "ns1", ""}, 161 &defaultAttributes{"joe", "group1,admins", "watch", "Foobar", "", "ns1", ""}, 162 }, 163 shouldFail: []authorizer.Attributes{ 164 &defaultAttributes{"admin", "", "GET", "Pods", "", "ns2", ""}, 165 &defaultAttributes{"admin", "", "GET", "Nodes", "", "", ""}, 166 &defaultAttributes{"admin", "admins", "GET", "Pods", "", "ns2", ""}, 167 &defaultAttributes{"admin", "admins", "GET", "Nodes", "", "", ""}, 168 }, 169 }, 170 { 171 // Non-resource-url tests 172 clusterRoles: []*rbacv1.ClusterRole{ 173 newClusterRole("non-resource-url-getter", newRule("get", "", "", "/apis")), 174 newClusterRole("non-resource-url", newRule("*", "", "", "/apis")), 175 newClusterRole("non-resource-url-prefix", newRule("get", "", "", "/apis/*")), 176 }, 177 clusterRoleBindings: []*rbacv1.ClusterRoleBinding{ 178 newClusterRoleBinding("non-resource-url-getter", "User:foo", "Group:bar"), 179 newClusterRoleBinding("non-resource-url", "User:admin", "Group:admin"), 180 newClusterRoleBinding("non-resource-url-prefix", "User:prefixed", "Group:prefixed"), 181 }, 182 shouldPass: []authorizer.Attributes{ 183 authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "foo"}, Verb: "get", Path: "/apis"}, 184 authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"bar"}}, Verb: "get", Path: "/apis"}, 185 authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "admin"}, Verb: "get", Path: "/apis"}, 186 authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"admin"}}, Verb: "get", Path: "/apis"}, 187 authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "admin"}, Verb: "watch", Path: "/apis"}, 188 authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"admin"}}, Verb: "watch", Path: "/apis"}, 189 190 authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "prefixed"}, Verb: "get", Path: "/apis/v1"}, 191 authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"prefixed"}}, Verb: "get", Path: "/apis/v1"}, 192 authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "prefixed"}, Verb: "get", Path: "/apis/v1/foobar"}, 193 authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"prefixed"}}, Verb: "get", Path: "/apis/v1/foorbar"}, 194 }, 195 shouldFail: []authorizer.Attributes{ 196 // wrong verb 197 authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "foo"}, Verb: "watch", Path: "/apis"}, 198 authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"bar"}}, Verb: "watch", Path: "/apis"}, 199 200 // wrong path 201 authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "foo"}, Verb: "get", Path: "/api/v1"}, 202 authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"bar"}}, Verb: "get", Path: "/api/v1"}, 203 authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "admin"}, Verb: "get", Path: "/api/v1"}, 204 authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"admin"}}, Verb: "get", Path: "/api/v1"}, 205 206 // not covered by prefix 207 authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "prefixed"}, Verb: "get", Path: "/api/v1"}, 208 authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"prefixed"}}, Verb: "get", Path: "/api/v1"}, 209 }, 210 }, 211 { 212 // test subresource resolution 213 clusterRoles: []*rbacv1.ClusterRole{ 214 newClusterRole("admin", newRule("*", "*", "pods", "*")), 215 }, 216 roleBindings: []*rbacv1.RoleBinding{ 217 newRoleBinding("ns1", "admin", bindToClusterRole, "User:admin", "Group:admins"), 218 }, 219 shouldPass: []authorizer.Attributes{ 220 &defaultAttributes{"admin", "", "get", "pods", "", "ns1", ""}, 221 }, 222 shouldFail: []authorizer.Attributes{ 223 &defaultAttributes{"admin", "", "get", "pods", "status", "ns1", ""}, 224 }, 225 }, 226 { 227 // test subresource resolution 228 clusterRoles: []*rbacv1.ClusterRole{ 229 newClusterRole("admin", 230 newRule("*", "*", "pods/status", "*"), 231 newRule("*", "*", "*/scale", "*"), 232 ), 233 }, 234 roleBindings: []*rbacv1.RoleBinding{ 235 newRoleBinding("ns1", "admin", bindToClusterRole, "User:admin", "Group:admins"), 236 }, 237 shouldPass: []authorizer.Attributes{ 238 &defaultAttributes{"admin", "", "get", "pods", "status", "ns1", ""}, 239 &defaultAttributes{"admin", "", "get", "pods", "scale", "ns1", ""}, 240 &defaultAttributes{"admin", "", "get", "deployments", "scale", "ns1", ""}, 241 &defaultAttributes{"admin", "", "get", "anything", "scale", "ns1", ""}, 242 }, 243 shouldFail: []authorizer.Attributes{ 244 &defaultAttributes{"admin", "", "get", "pods", "", "ns1", ""}, 245 }, 246 }, 247 } 248 for i, tt := range tests { 249 ruleResolver, _ := rbacregistryvalidation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings) 250 a := RBACAuthorizer{ruleResolver} 251 for _, attr := range tt.shouldPass { 252 if decision, _, _ := a.Authorize(context.Background(), attr); decision != authorizer.DecisionAllow { 253 t.Errorf("case %d: incorrectly restricted %s", i, attr) 254 } 255 } 256 257 for _, attr := range tt.shouldFail { 258 if decision, _, _ := a.Authorize(context.Background(), attr); decision == authorizer.DecisionAllow { 259 t.Errorf("case %d: incorrectly passed %s", i, attr) 260 } 261 } 262 } 263} 264 265func TestRuleMatches(t *testing.T) { 266 tests := []struct { 267 name string 268 rule rbacv1.PolicyRule 269 270 requestsToExpected map[authorizer.AttributesRecord]bool 271 }{ 272 { 273 name: "star verb, exact match other", 274 rule: rbacv1helpers.NewRule("*").Groups("group1").Resources("resource1").RuleOrDie(), 275 requestsToExpected: map[authorizer.AttributesRecord]bool{ 276 resourceRequest("verb1").Group("group1").Resource("resource1").New(): true, 277 resourceRequest("verb1").Group("group2").Resource("resource1").New(): false, 278 resourceRequest("verb1").Group("group1").Resource("resource2").New(): false, 279 resourceRequest("verb1").Group("group2").Resource("resource2").New(): false, 280 resourceRequest("verb2").Group("group1").Resource("resource1").New(): true, 281 resourceRequest("verb2").Group("group2").Resource("resource1").New(): false, 282 resourceRequest("verb2").Group("group1").Resource("resource2").New(): false, 283 resourceRequest("verb2").Group("group2").Resource("resource2").New(): false, 284 }, 285 }, 286 { 287 name: "star group, exact match other", 288 rule: rbacv1helpers.NewRule("verb1").Groups("*").Resources("resource1").RuleOrDie(), 289 requestsToExpected: map[authorizer.AttributesRecord]bool{ 290 resourceRequest("verb1").Group("group1").Resource("resource1").New(): true, 291 resourceRequest("verb1").Group("group2").Resource("resource1").New(): true, 292 resourceRequest("verb1").Group("group1").Resource("resource2").New(): false, 293 resourceRequest("verb1").Group("group2").Resource("resource2").New(): false, 294 resourceRequest("verb2").Group("group1").Resource("resource1").New(): false, 295 resourceRequest("verb2").Group("group2").Resource("resource1").New(): false, 296 resourceRequest("verb2").Group("group1").Resource("resource2").New(): false, 297 resourceRequest("verb2").Group("group2").Resource("resource2").New(): false, 298 }, 299 }, 300 { 301 name: "star resource, exact match other", 302 rule: rbacv1helpers.NewRule("verb1").Groups("group1").Resources("*").RuleOrDie(), 303 requestsToExpected: map[authorizer.AttributesRecord]bool{ 304 resourceRequest("verb1").Group("group1").Resource("resource1").New(): true, 305 resourceRequest("verb1").Group("group2").Resource("resource1").New(): false, 306 resourceRequest("verb1").Group("group1").Resource("resource2").New(): true, 307 resourceRequest("verb1").Group("group2").Resource("resource2").New(): false, 308 resourceRequest("verb2").Group("group1").Resource("resource1").New(): false, 309 resourceRequest("verb2").Group("group2").Resource("resource1").New(): false, 310 resourceRequest("verb2").Group("group1").Resource("resource2").New(): false, 311 resourceRequest("verb2").Group("group2").Resource("resource2").New(): false, 312 }, 313 }, 314 { 315 name: "tuple expansion", 316 rule: rbacv1helpers.NewRule("verb1", "verb2").Groups("group1", "group2").Resources("resource1", "resource2").RuleOrDie(), 317 requestsToExpected: map[authorizer.AttributesRecord]bool{ 318 resourceRequest("verb1").Group("group1").Resource("resource1").New(): true, 319 resourceRequest("verb1").Group("group2").Resource("resource1").New(): true, 320 resourceRequest("verb1").Group("group1").Resource("resource2").New(): true, 321 resourceRequest("verb1").Group("group2").Resource("resource2").New(): true, 322 resourceRequest("verb2").Group("group1").Resource("resource1").New(): true, 323 resourceRequest("verb2").Group("group2").Resource("resource1").New(): true, 324 resourceRequest("verb2").Group("group1").Resource("resource2").New(): true, 325 resourceRequest("verb2").Group("group2").Resource("resource2").New(): true, 326 }, 327 }, 328 { 329 name: "subresource expansion", 330 rule: rbacv1helpers.NewRule("*").Groups("*").Resources("resource1/subresource1").RuleOrDie(), 331 requestsToExpected: map[authorizer.AttributesRecord]bool{ 332 resourceRequest("verb1").Group("group1").Resource("resource1").Subresource("subresource1").New(): true, 333 resourceRequest("verb1").Group("group2").Resource("resource1").Subresource("subresource2").New(): false, 334 resourceRequest("verb1").Group("group1").Resource("resource2").Subresource("subresource1").New(): false, 335 resourceRequest("verb1").Group("group2").Resource("resource2").Subresource("subresource1").New(): false, 336 resourceRequest("verb2").Group("group1").Resource("resource1").Subresource("subresource1").New(): true, 337 resourceRequest("verb2").Group("group2").Resource("resource1").Subresource("subresource2").New(): false, 338 resourceRequest("verb2").Group("group1").Resource("resource2").Subresource("subresource1").New(): false, 339 resourceRequest("verb2").Group("group2").Resource("resource2").Subresource("subresource1").New(): false, 340 }, 341 }, 342 { 343 name: "star nonresource, exact match other", 344 rule: rbacv1helpers.NewRule("verb1").URLs("*").RuleOrDie(), 345 requestsToExpected: map[authorizer.AttributesRecord]bool{ 346 nonresourceRequest("verb1").URL("/foo").New(): true, 347 nonresourceRequest("verb1").URL("/foo/bar").New(): true, 348 nonresourceRequest("verb1").URL("/foo/baz").New(): true, 349 nonresourceRequest("verb1").URL("/foo/bar/one").New(): true, 350 nonresourceRequest("verb1").URL("/foo/baz/one").New(): true, 351 nonresourceRequest("verb2").URL("/foo").New(): false, 352 nonresourceRequest("verb2").URL("/foo/bar").New(): false, 353 nonresourceRequest("verb2").URL("/foo/baz").New(): false, 354 nonresourceRequest("verb2").URL("/foo/bar/one").New(): false, 355 nonresourceRequest("verb2").URL("/foo/baz/one").New(): false, 356 }, 357 }, 358 { 359 name: "star nonresource subpath", 360 rule: rbacv1helpers.NewRule("verb1").URLs("/foo/*").RuleOrDie(), 361 requestsToExpected: map[authorizer.AttributesRecord]bool{ 362 nonresourceRequest("verb1").URL("/foo").New(): false, 363 nonresourceRequest("verb1").URL("/foo/bar").New(): true, 364 nonresourceRequest("verb1").URL("/foo/baz").New(): true, 365 nonresourceRequest("verb1").URL("/foo/bar/one").New(): true, 366 nonresourceRequest("verb1").URL("/foo/baz/one").New(): true, 367 nonresourceRequest("verb1").URL("/notfoo").New(): false, 368 nonresourceRequest("verb1").URL("/notfoo/bar").New(): false, 369 nonresourceRequest("verb1").URL("/notfoo/baz").New(): false, 370 nonresourceRequest("verb1").URL("/notfoo/bar/one").New(): false, 371 nonresourceRequest("verb1").URL("/notfoo/baz/one").New(): false, 372 }, 373 }, 374 { 375 name: "star verb, exact nonresource", 376 rule: rbacv1helpers.NewRule("*").URLs("/foo", "/foo/bar/one").RuleOrDie(), 377 requestsToExpected: map[authorizer.AttributesRecord]bool{ 378 nonresourceRequest("verb1").URL("/foo").New(): true, 379 nonresourceRequest("verb1").URL("/foo/bar").New(): false, 380 nonresourceRequest("verb1").URL("/foo/baz").New(): false, 381 nonresourceRequest("verb1").URL("/foo/bar/one").New(): true, 382 nonresourceRequest("verb1").URL("/foo/baz/one").New(): false, 383 nonresourceRequest("verb2").URL("/foo").New(): true, 384 nonresourceRequest("verb2").URL("/foo/bar").New(): false, 385 nonresourceRequest("verb2").URL("/foo/baz").New(): false, 386 nonresourceRequest("verb2").URL("/foo/bar/one").New(): true, 387 nonresourceRequest("verb2").URL("/foo/baz/one").New(): false, 388 }, 389 }, 390 } 391 for _, tc := range tests { 392 for request, expected := range tc.requestsToExpected { 393 if e, a := expected, RuleAllows(request, &tc.rule); e != a { 394 t.Errorf("%q: expected %v, got %v for %v", tc.name, e, a, request) 395 } 396 } 397 } 398} 399 400type requestAttributeBuilder struct { 401 request authorizer.AttributesRecord 402} 403 404func resourceRequest(verb string) *requestAttributeBuilder { 405 return &requestAttributeBuilder{ 406 request: authorizer.AttributesRecord{ResourceRequest: true, Verb: verb}, 407 } 408} 409 410func nonresourceRequest(verb string) *requestAttributeBuilder { 411 return &requestAttributeBuilder{ 412 request: authorizer.AttributesRecord{ResourceRequest: false, Verb: verb}, 413 } 414} 415 416func (r *requestAttributeBuilder) Group(group string) *requestAttributeBuilder { 417 r.request.APIGroup = group 418 return r 419} 420 421func (r *requestAttributeBuilder) Resource(resource string) *requestAttributeBuilder { 422 r.request.Resource = resource 423 return r 424} 425 426func (r *requestAttributeBuilder) Subresource(subresource string) *requestAttributeBuilder { 427 r.request.Subresource = subresource 428 return r 429} 430 431func (r *requestAttributeBuilder) Name(name string) *requestAttributeBuilder { 432 r.request.Name = name 433 return r 434} 435 436func (r *requestAttributeBuilder) URL(url string) *requestAttributeBuilder { 437 r.request.Path = url 438 return r 439} 440 441func (r *requestAttributeBuilder) New() authorizer.AttributesRecord { 442 return r.request 443} 444 445func BenchmarkAuthorize(b *testing.B) { 446 bootstrapRoles := []rbacv1.ClusterRole{} 447 bootstrapRoles = append(bootstrapRoles, bootstrappolicy.ControllerRoles()...) 448 bootstrapRoles = append(bootstrapRoles, bootstrappolicy.ClusterRoles()...) 449 450 bootstrapBindings := []rbacv1.ClusterRoleBinding{} 451 bootstrapBindings = append(bootstrapBindings, bootstrappolicy.ClusterRoleBindings()...) 452 bootstrapBindings = append(bootstrapBindings, bootstrappolicy.ControllerRoleBindings()...) 453 454 clusterRoles := []*rbacv1.ClusterRole{} 455 for i := range bootstrapRoles { 456 clusterRoles = append(clusterRoles, &bootstrapRoles[i]) 457 } 458 clusterRoleBindings := []*rbacv1.ClusterRoleBinding{} 459 for i := range bootstrapBindings { 460 clusterRoleBindings = append(clusterRoleBindings, &bootstrapBindings[i]) 461 } 462 463 _, resolver := rbacregistryvalidation.NewTestRuleResolver(nil, nil, clusterRoles, clusterRoleBindings) 464 465 authz := New(resolver, resolver, resolver, resolver) 466 467 nodeUser := &user.DefaultInfo{Name: "system:node:node1", Groups: []string{"system:nodes", "system:authenticated"}} 468 requests := []struct { 469 name string 470 attrs authorizer.Attributes 471 }{ 472 { 473 "allow list pods", 474 authorizer.AttributesRecord{ 475 ResourceRequest: true, 476 User: nodeUser, 477 Verb: "list", 478 Resource: "pods", 479 Subresource: "", 480 Name: "", 481 Namespace: "", 482 APIGroup: "", 483 APIVersion: "v1", 484 }, 485 }, 486 { 487 "allow update pods/status", 488 authorizer.AttributesRecord{ 489 ResourceRequest: true, 490 User: nodeUser, 491 Verb: "update", 492 Resource: "pods", 493 Subresource: "status", 494 Name: "mypods", 495 Namespace: "myns", 496 APIGroup: "", 497 APIVersion: "v1", 498 }, 499 }, 500 { 501 "forbid educate dolphins", 502 authorizer.AttributesRecord{ 503 ResourceRequest: true, 504 User: nodeUser, 505 Verb: "educate", 506 Resource: "dolphins", 507 Subresource: "", 508 Name: "", 509 Namespace: "", 510 APIGroup: "", 511 APIVersion: "v1", 512 }, 513 }, 514 } 515 516 b.ResetTimer() 517 for _, request := range requests { 518 b.Run(request.name, func(b *testing.B) { 519 for i := 0; i < b.N; i++ { 520 authz.Authorize(context.Background(), request.attrs) 521 } 522 }) 523 } 524} 525