mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +00:00
Merge pull request #35300 from deads2k/rbac-17-subjectlocator
Automatic merge from submit-queue (batch tested with PRs 35300, 36709, 37643, 37813, 37697) add rbac action to subjects type This adds the ability to go from an authorization action to the list subjects who have the power to perform the action. This will be used to either back an RBAC specific endpoint or generic authorization endpoint. Because of the way authorization works today, the set of subjects returned will always be a subset of those with access since any authorizer can say yes. @kubernetes/sig-auth
This commit is contained in:
commit
b1a3f3794a
@ -190,28 +190,29 @@ func appliesToUser(user user.Info, subject rbac.Subject, namespace string) bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewTestRuleResolver returns a rule resolver from lists of role objects.
|
// NewTestRuleResolver returns a rule resolver from lists of role objects.
|
||||||
func NewTestRuleResolver(roles []*rbac.Role, roleBindings []*rbac.RoleBinding, clusterRoles []*rbac.ClusterRole, clusterRoleBindings []*rbac.ClusterRoleBinding) AuthorizationRuleResolver {
|
func NewTestRuleResolver(roles []*rbac.Role, roleBindings []*rbac.RoleBinding, clusterRoles []*rbac.ClusterRole, clusterRoleBindings []*rbac.ClusterRoleBinding) (AuthorizationRuleResolver, *StaticRoles) {
|
||||||
r := staticRoles{
|
r := StaticRoles{
|
||||||
roles: roles,
|
roles: roles,
|
||||||
roleBindings: roleBindings,
|
roleBindings: roleBindings,
|
||||||
clusterRoles: clusterRoles,
|
clusterRoles: clusterRoles,
|
||||||
clusterRoleBindings: clusterRoleBindings,
|
clusterRoleBindings: clusterRoleBindings,
|
||||||
}
|
}
|
||||||
return newMockRuleResolver(&r)
|
return newMockRuleResolver(&r), &r
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMockRuleResolver(r *staticRoles) AuthorizationRuleResolver {
|
func newMockRuleResolver(r *StaticRoles) AuthorizationRuleResolver {
|
||||||
return NewDefaultRuleResolver(r, r, r, r)
|
return NewDefaultRuleResolver(r, r, r, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
type staticRoles struct {
|
// StaticRoles is a rule resolver that resolves from lists of role objects.
|
||||||
|
type StaticRoles struct {
|
||||||
roles []*rbac.Role
|
roles []*rbac.Role
|
||||||
roleBindings []*rbac.RoleBinding
|
roleBindings []*rbac.RoleBinding
|
||||||
clusterRoles []*rbac.ClusterRole
|
clusterRoles []*rbac.ClusterRole
|
||||||
clusterRoleBindings []*rbac.ClusterRoleBinding
|
clusterRoleBindings []*rbac.ClusterRoleBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *staticRoles) GetRole(namespace, name string) (*rbac.Role, error) {
|
func (r *StaticRoles) GetRole(namespace, name string) (*rbac.Role, error) {
|
||||||
if len(namespace) == 0 {
|
if len(namespace) == 0 {
|
||||||
return nil, errors.New("must provide namespace when getting role")
|
return nil, errors.New("must provide namespace when getting role")
|
||||||
}
|
}
|
||||||
@ -223,7 +224,7 @@ func (r *staticRoles) GetRole(namespace, name string) (*rbac.Role, error) {
|
|||||||
return nil, errors.New("role not found")
|
return nil, errors.New("role not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *staticRoles) GetClusterRole(name string) (*rbac.ClusterRole, error) {
|
func (r *StaticRoles) GetClusterRole(name string) (*rbac.ClusterRole, error) {
|
||||||
for _, clusterRole := range r.clusterRoles {
|
for _, clusterRole := range r.clusterRoles {
|
||||||
if clusterRole.Name == name {
|
if clusterRole.Name == name {
|
||||||
return clusterRole, nil
|
return clusterRole, nil
|
||||||
@ -232,7 +233,7 @@ func (r *staticRoles) GetClusterRole(name string) (*rbac.ClusterRole, error) {
|
|||||||
return nil, errors.New("role not found")
|
return nil, errors.New("role not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *staticRoles) ListRoleBindings(namespace string) ([]*rbac.RoleBinding, error) {
|
func (r *StaticRoles) ListRoleBindings(namespace string) ([]*rbac.RoleBinding, error) {
|
||||||
if len(namespace) == 0 {
|
if len(namespace) == 0 {
|
||||||
return nil, errors.New("must provide namespace when listing role bindings")
|
return nil, errors.New("must provide namespace when listing role bindings")
|
||||||
}
|
}
|
||||||
@ -248,6 +249,6 @@ func (r *staticRoles) ListRoleBindings(namespace string) ([]*rbac.RoleBinding, e
|
|||||||
return roleBindingList, nil
|
return roleBindingList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *staticRoles) ListClusterRoleBindings() ([]*rbac.ClusterRoleBinding, error) {
|
func (r *StaticRoles) ListClusterRoleBindings() ([]*rbac.ClusterRoleBinding, error) {
|
||||||
return r.clusterRoleBindings, nil
|
return r.clusterRoleBindings, nil
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ func TestDefaultRuleResolver(t *testing.T) {
|
|||||||
Resources: []string{"*"},
|
Resources: []string{"*"},
|
||||||
}
|
}
|
||||||
|
|
||||||
staticRoles1 := staticRoles{
|
staticRoles1 := StaticRoles{
|
||||||
roles: []*rbac.Role{
|
roles: []*rbac.Role{
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Namespace: "namespace1", Name: "readthings"},
|
ObjectMeta: api.ObjectMeta{Namespace: "namespace1", Name: "readthings"},
|
||||||
@ -111,7 +111,7 @@ func TestDefaultRuleResolver(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
staticRoles
|
StaticRoles
|
||||||
|
|
||||||
// For a given context, what are the rules that apply?
|
// For a given context, what are the rules that apply?
|
||||||
user user.Info
|
user user.Info
|
||||||
@ -119,32 +119,32 @@ func TestDefaultRuleResolver(t *testing.T) {
|
|||||||
effectiveRules []rbac.PolicyRule
|
effectiveRules []rbac.PolicyRule
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
staticRoles: staticRoles1,
|
StaticRoles: staticRoles1,
|
||||||
user: &user.DefaultInfo{Name: "foobar"},
|
user: &user.DefaultInfo{Name: "foobar"},
|
||||||
namespace: "namespace1",
|
namespace: "namespace1",
|
||||||
effectiveRules: []rbac.PolicyRule{ruleReadPods, ruleReadServices},
|
effectiveRules: []rbac.PolicyRule{ruleReadPods, ruleReadServices},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
staticRoles: staticRoles1,
|
StaticRoles: staticRoles1,
|
||||||
user: &user.DefaultInfo{Name: "foobar"},
|
user: &user.DefaultInfo{Name: "foobar"},
|
||||||
namespace: "namespace2",
|
namespace: "namespace2",
|
||||||
effectiveRules: []rbac.PolicyRule{},
|
effectiveRules: []rbac.PolicyRule{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
staticRoles: staticRoles1,
|
StaticRoles: staticRoles1,
|
||||||
// Same as above but without a namespace. Only cluster rules should apply.
|
// Same as above but without a namespace. Only cluster rules should apply.
|
||||||
user: &user.DefaultInfo{Name: "foobar", Groups: []string{"admin"}},
|
user: &user.DefaultInfo{Name: "foobar", Groups: []string{"admin"}},
|
||||||
effectiveRules: []rbac.PolicyRule{ruleAdmin},
|
effectiveRules: []rbac.PolicyRule{ruleAdmin},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
staticRoles: staticRoles1,
|
StaticRoles: staticRoles1,
|
||||||
user: &user.DefaultInfo{},
|
user: &user.DefaultInfo{},
|
||||||
effectiveRules: []rbac.PolicyRule{},
|
effectiveRules: []rbac.PolicyRule{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range tests {
|
for i, tc := range tests {
|
||||||
ruleResolver := newMockRuleResolver(&tc.staticRoles)
|
ruleResolver := newMockRuleResolver(&tc.StaticRoles)
|
||||||
rules, err := ruleResolver.RulesFor(tc.user, tc.namespace)
|
rules, err := ruleResolver.RulesFor(tc.user, tc.namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("case %d: GetEffectivePolicyRules(context)=%v", i, err)
|
t.Errorf("case %d: GetEffectivePolicyRules(context)=%v", i, err)
|
||||||
|
@ -12,19 +12,26 @@ load(
|
|||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = ["rbac.go"],
|
srcs = [
|
||||||
|
"rbac.go",
|
||||||
|
"subject_locator.go",
|
||||||
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/rbac:go_default_library",
|
"//pkg/apis/rbac:go_default_library",
|
||||||
"//pkg/apis/rbac/validation:go_default_library",
|
"//pkg/apis/rbac/validation:go_default_library",
|
||||||
"//pkg/auth/authorizer:go_default_library",
|
"//pkg/auth/authorizer:go_default_library",
|
||||||
"//pkg/auth/user:go_default_library",
|
"//pkg/auth/user:go_default_library",
|
||||||
|
"//pkg/util/errors:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
go_test(
|
go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
srcs = ["rbac_test.go"],
|
srcs = [
|
||||||
|
"rbac_test.go",
|
||||||
|
"subject_locator_test.go",
|
||||||
|
],
|
||||||
library = "go_default_library",
|
library = "go_default_library",
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
|
@ -221,7 +221,7 @@ func TestAuthorizer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
ruleResolver := validation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
|
ruleResolver, _ := validation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
|
||||||
a := RBACAuthorizer{tt.superUser, ruleResolver}
|
a := RBACAuthorizer{tt.superUser, ruleResolver}
|
||||||
for _, attr := range tt.shouldPass {
|
for _, attr := range tt.shouldPass {
|
||||||
if authorized, _, _ := a.Authorize(attr); !authorized {
|
if authorized, _, _ := a.Authorize(attr); !authorized {
|
||||||
|
117
plugin/pkg/auth/authorizer/rbac/subject_locator.go
Normal file
117
plugin/pkg/auth/authorizer/rbac/subject_locator.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Package rbac implements the authorizer.Authorizer interface using roles base access control.
|
||||||
|
package rbac
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/rbac/validation"
|
||||||
|
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||||
|
"k8s.io/kubernetes/pkg/auth/user"
|
||||||
|
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RoleToRuleMapper interface {
|
||||||
|
// GetRoleReferenceRules attempts to resolve the role reference of a RoleBinding or ClusterRoleBinding. The passed namespace should be the namespace
|
||||||
|
// of the role binding, the empty string if a cluster role binding.
|
||||||
|
GetRoleReferenceRules(roleRef rbac.RoleRef, namespace string) ([]rbac.PolicyRule, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SubjectAccessEvaluator struct {
|
||||||
|
superUser string
|
||||||
|
|
||||||
|
roleBindingLister validation.RoleBindingLister
|
||||||
|
clusterRoleBindingLister validation.ClusterRoleBindingLister
|
||||||
|
roleToRuleMapper RoleToRuleMapper
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSubjectAccessEvaluator(roles validation.RoleGetter, roleBindings validation.RoleBindingLister, clusterRoles validation.ClusterRoleGetter, clusterRoleBindings validation.ClusterRoleBindingLister, superUser string) *SubjectAccessEvaluator {
|
||||||
|
subjectLocator := &SubjectAccessEvaluator{
|
||||||
|
superUser: superUser,
|
||||||
|
roleBindingLister: roleBindings,
|
||||||
|
clusterRoleBindingLister: clusterRoleBindings,
|
||||||
|
roleToRuleMapper: validation.NewDefaultRuleResolver(
|
||||||
|
roles, roleBindings, clusterRoles, clusterRoleBindings,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
return subjectLocator
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllowedSubjects returns the subjects that can perform an action and any errors encountered while computing the list.
|
||||||
|
// It is possible to have both subjects and errors returned if some rolebindings couldn't be resolved, but others could be.
|
||||||
|
func (r *SubjectAccessEvaluator) AllowedSubjects(requestAttributes authorizer.Attributes) ([]rbac.Subject, error) {
|
||||||
|
subjects := []rbac.Subject{{Kind: rbac.GroupKind, Name: user.SystemPrivilegedGroup}}
|
||||||
|
if len(r.superUser) > 0 {
|
||||||
|
subjects = append(subjects, rbac.Subject{Kind: rbac.UserKind, APIVersion: "v1alpha1", Name: r.superUser})
|
||||||
|
}
|
||||||
|
errorlist := []error{}
|
||||||
|
|
||||||
|
if clusterRoleBindings, err := r.clusterRoleBindingLister.ListClusterRoleBindings(); err != nil {
|
||||||
|
errorlist = append(errorlist, err)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for _, clusterRoleBinding := range clusterRoleBindings {
|
||||||
|
rules, err := r.roleToRuleMapper.GetRoleReferenceRules(clusterRoleBinding.RoleRef, "")
|
||||||
|
if err != nil {
|
||||||
|
// if we have an error, just keep track of it and keep processing. Since rules are additive,
|
||||||
|
// missing a reference is bad, but we can continue with other rolebindings and still have a list
|
||||||
|
// that does not contain any invalid values
|
||||||
|
errorlist = append(errorlist, err)
|
||||||
|
}
|
||||||
|
if RulesAllow(requestAttributes, rules...) {
|
||||||
|
subjects = append(subjects, clusterRoleBinding.Subjects...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if namespace := requestAttributes.GetNamespace(); len(namespace) > 0 {
|
||||||
|
if roleBindings, err := r.roleBindingLister.ListRoleBindings(namespace); err != nil {
|
||||||
|
errorlist = append(errorlist, err)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for _, roleBinding := range roleBindings {
|
||||||
|
rules, err := r.roleToRuleMapper.GetRoleReferenceRules(roleBinding.RoleRef, namespace)
|
||||||
|
if err != nil {
|
||||||
|
// if we have an error, just keep track of it and keep processing. Since rules are additive,
|
||||||
|
// missing a reference is bad, but we can continue with other rolebindings and still have a list
|
||||||
|
// that does not contain any invalid values
|
||||||
|
errorlist = append(errorlist, err)
|
||||||
|
}
|
||||||
|
if RulesAllow(requestAttributes, rules...) {
|
||||||
|
subjects = append(subjects, roleBinding.Subjects...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dedupedSubjects := []rbac.Subject{}
|
||||||
|
for _, subject := range subjects {
|
||||||
|
found := false
|
||||||
|
for _, curr := range dedupedSubjects {
|
||||||
|
if curr == subject {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
dedupedSubjects = append(dedupedSubjects, subject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return subjects, utilerrors.NewAggregate(errorlist)
|
||||||
|
}
|
151
plugin/pkg/auth/authorizer/rbac/subject_locator_test.go
Normal file
151
plugin/pkg/auth/authorizer/rbac/subject_locator_test.go
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package rbac
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/rbac/validation"
|
||||||
|
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||||
|
"k8s.io/kubernetes/pkg/auth/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSubjectLocator(t *testing.T) {
|
||||||
|
type actionToSubjects struct {
|
||||||
|
action authorizer.Attributes
|
||||||
|
subjects []rbac.Subject
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
roles []*rbac.Role
|
||||||
|
roleBindings []*rbac.RoleBinding
|
||||||
|
clusterRoles []*rbac.ClusterRole
|
||||||
|
clusterRoleBindings []*rbac.ClusterRoleBinding
|
||||||
|
|
||||||
|
superUser string
|
||||||
|
|
||||||
|
actionsToSubjects []actionToSubjects
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no super user, star matches star",
|
||||||
|
clusterRoles: []*rbac.ClusterRole{
|
||||||
|
newClusterRole("admin", newRule("*", "*", "*", "*")),
|
||||||
|
},
|
||||||
|
clusterRoleBindings: []*rbac.ClusterRoleBinding{
|
||||||
|
newClusterRoleBinding("admin", "User:super-admin", "Group:super-admins"),
|
||||||
|
},
|
||||||
|
roleBindings: []*rbac.RoleBinding{
|
||||||
|
newRoleBinding("ns1", "admin", bindToClusterRole, "User:admin", "Group:admins"),
|
||||||
|
},
|
||||||
|
actionsToSubjects: []actionToSubjects{
|
||||||
|
{
|
||||||
|
&defaultAttributes{"", "", "get", "Pods", "", "ns1", ""},
|
||||||
|
[]rbac.Subject{
|
||||||
|
{Kind: rbac.GroupKind, Name: user.SystemPrivilegedGroup},
|
||||||
|
{Kind: rbac.UserKind, Name: "super-admin"},
|
||||||
|
{Kind: rbac.GroupKind, Name: "super-admins"},
|
||||||
|
{Kind: rbac.UserKind, Name: "admin"},
|
||||||
|
{Kind: rbac.GroupKind, Name: "admins"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// cluster role matches star in namespace
|
||||||
|
&defaultAttributes{"", "", "*", "Pods", "", "*", ""},
|
||||||
|
[]rbac.Subject{
|
||||||
|
{Kind: rbac.GroupKind, Name: user.SystemPrivilegedGroup},
|
||||||
|
{Kind: rbac.UserKind, Name: "super-admin"},
|
||||||
|
{Kind: rbac.GroupKind, Name: "super-admins"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// empty ns
|
||||||
|
&defaultAttributes{"", "", "*", "Pods", "", "", ""},
|
||||||
|
[]rbac.Subject{
|
||||||
|
{Kind: rbac.GroupKind, Name: user.SystemPrivilegedGroup},
|
||||||
|
{Kind: rbac.UserKind, Name: "super-admin"},
|
||||||
|
{Kind: rbac.GroupKind, Name: "super-admins"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "super user, local roles work",
|
||||||
|
superUser: "foo",
|
||||||
|
clusterRoles: []*rbac.ClusterRole{
|
||||||
|
newClusterRole("admin", newRule("*", "*", "*", "*")),
|
||||||
|
},
|
||||||
|
clusterRoleBindings: []*rbac.ClusterRoleBinding{
|
||||||
|
newClusterRoleBinding("admin", "User:super-admin", "Group:super-admins"),
|
||||||
|
},
|
||||||
|
roles: []*rbac.Role{
|
||||||
|
newRole("admin", "ns1", newRule("get", "*", "Pods", "*")),
|
||||||
|
},
|
||||||
|
roleBindings: []*rbac.RoleBinding{
|
||||||
|
newRoleBinding("ns1", "admin", bindToRole, "User:admin", "Group:admins"),
|
||||||
|
},
|
||||||
|
actionsToSubjects: []actionToSubjects{
|
||||||
|
{
|
||||||
|
&defaultAttributes{"", "", "get", "Pods", "", "ns1", ""},
|
||||||
|
[]rbac.Subject{
|
||||||
|
{Kind: rbac.GroupKind, Name: user.SystemPrivilegedGroup},
|
||||||
|
{Kind: rbac.UserKind, APIVersion: "v1alpha1", Name: "foo"},
|
||||||
|
{Kind: rbac.UserKind, Name: "super-admin"},
|
||||||
|
{Kind: rbac.GroupKind, Name: "super-admins"},
|
||||||
|
{Kind: rbac.UserKind, Name: "admin"},
|
||||||
|
{Kind: rbac.GroupKind, Name: "admins"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// verb matchies correctly
|
||||||
|
&defaultAttributes{"", "", "create", "Pods", "", "ns1", ""},
|
||||||
|
[]rbac.Subject{
|
||||||
|
{Kind: rbac.GroupKind, Name: user.SystemPrivilegedGroup},
|
||||||
|
{Kind: rbac.UserKind, APIVersion: "v1alpha1", Name: "foo"},
|
||||||
|
{Kind: rbac.UserKind, Name: "super-admin"},
|
||||||
|
{Kind: rbac.GroupKind, Name: "super-admins"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// binding only works in correct ns
|
||||||
|
&defaultAttributes{"", "", "get", "Pods", "", "ns2", ""},
|
||||||
|
[]rbac.Subject{
|
||||||
|
{Kind: rbac.GroupKind, Name: user.SystemPrivilegedGroup},
|
||||||
|
{Kind: rbac.UserKind, APIVersion: "v1alpha1", Name: "foo"},
|
||||||
|
{Kind: rbac.UserKind, Name: "super-admin"},
|
||||||
|
{Kind: rbac.GroupKind, Name: "super-admins"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
ruleResolver, lister := validation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
|
||||||
|
a := SubjectAccessEvaluator{tt.superUser, lister, lister, ruleResolver}
|
||||||
|
for i, action := range tt.actionsToSubjects {
|
||||||
|
actualSubjects, err := a.AllowedSubjects(action.action)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("case %q %d: error %v", tt.name, i, err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(actualSubjects, action.subjects) {
|
||||||
|
t.Errorf("case %q %d: expected %v actual %v", tt.name, i, action.subjects, actualSubjects)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user