...

Source file src/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/rbac_test.go

Documentation: k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package rbac
    18  
    19  import (
    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  
    34  func 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  
    43  func newRole(name, namespace string, rules ...rbacv1.PolicyRule) *rbacv1.Role {
    44  	return &rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: name}, Rules: rules}
    45  }
    46  
    47  func newClusterRole(name string, rules ...rbacv1.PolicyRule) *rbacv1.ClusterRole {
    48  	return &rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: name}, Rules: rules}
    49  }
    50  
    51  const (
    52  	bindToRole        uint16 = 0x0
    53  	bindToClusterRole uint16 = 0x1
    54  )
    55  
    56  func 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  
    83  func 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  
   110  type 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  
   120  func (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  
   125  func (d *defaultAttributes) GetUser() user.Info {
   126  	return &user.DefaultInfo{Name: d.user, Groups: strings.Split(d.groups, ",")}
   127  }
   128  func (d *defaultAttributes) GetVerb() string         { return d.verb }
   129  func (d *defaultAttributes) IsReadOnly() bool        { return d.verb == "get" || d.verb == "watch" }
   130  func (d *defaultAttributes) GetNamespace() string    { return d.namespace }
   131  func (d *defaultAttributes) GetResource() string     { return d.resource }
   132  func (d *defaultAttributes) GetSubresource() string  { return d.subresource }
   133  func (d *defaultAttributes) GetName() string         { return "" }
   134  func (d *defaultAttributes) GetAPIGroup() string     { return d.apiGroup }
   135  func (d *defaultAttributes) GetAPIVersion() string   { return "" }
   136  func (d *defaultAttributes) IsResourceRequest() bool { return true }
   137  func (d *defaultAttributes) GetPath() string         { return "" }
   138  
   139  func 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  
   265  func 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  
   400  type requestAttributeBuilder struct {
   401  	request authorizer.AttributesRecord
   402  }
   403  
   404  func resourceRequest(verb string) *requestAttributeBuilder {
   405  	return &requestAttributeBuilder{
   406  		request: authorizer.AttributesRecord{ResourceRequest: true, Verb: verb},
   407  	}
   408  }
   409  
   410  func nonresourceRequest(verb string) *requestAttributeBuilder {
   411  	return &requestAttributeBuilder{
   412  		request: authorizer.AttributesRecord{ResourceRequest: false, Verb: verb},
   413  	}
   414  }
   415  
   416  func (r *requestAttributeBuilder) Group(group string) *requestAttributeBuilder {
   417  	r.request.APIGroup = group
   418  	return r
   419  }
   420  
   421  func (r *requestAttributeBuilder) Resource(resource string) *requestAttributeBuilder {
   422  	r.request.Resource = resource
   423  	return r
   424  }
   425  
   426  func (r *requestAttributeBuilder) Subresource(subresource string) *requestAttributeBuilder {
   427  	r.request.Subresource = subresource
   428  	return r
   429  }
   430  
   431  func (r *requestAttributeBuilder) Name(name string) *requestAttributeBuilder {
   432  	r.request.Name = name
   433  	return r
   434  }
   435  
   436  func (r *requestAttributeBuilder) URL(url string) *requestAttributeBuilder {
   437  	r.request.Path = url
   438  	return r
   439  }
   440  
   441  func (r *requestAttributeBuilder) New() authorizer.AttributesRecord {
   442  	return r.request
   443  }
   444  
   445  func 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  

View as plain text