rbac_test.go 21 KB

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