rbac_test.go 21 KB

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