mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-13 19:28:55 +00:00
fix: role matching from authentication infos (#6358)
* fix: role matching from authentication infos Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * more tests Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
d920f60798
commit
ef7265ca6d
2 changed files with 417 additions and 274 deletions
|
@ -2,10 +2,8 @@ package userinfo
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
datautils "github.com/kyverno/kyverno/pkg/utils/data"
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
authenticationv1 "k8s.io/api/authentication/v1"
|
||||
|
@ -17,8 +15,6 @@ import (
|
|||
const (
|
||||
clusterroleKind = "ClusterRole"
|
||||
roleKind = "Role"
|
||||
// saPrefix represents service account prefix in admission requests
|
||||
saPrefix = "system:serviceaccount:"
|
||||
)
|
||||
|
||||
// GetRoleRef gets the list of roles and cluster roles for the incoming api-request
|
||||
|
@ -44,62 +40,53 @@ func GetRoleRef(rbLister rbacv1listers.RoleBindingLister, crbLister rbacv1lister
|
|||
|
||||
func getRoleRefByRoleBindings(roleBindings []*rbacv1.RoleBinding, userInfo authenticationv1.UserInfo) (roles []string, clusterRoles []string) {
|
||||
for _, rolebinding := range roleBindings {
|
||||
for _, subject := range rolebinding.Subjects {
|
||||
if matchSubjectsMap(subject, userInfo, rolebinding.Namespace) {
|
||||
switch rolebinding.RoleRef.Kind {
|
||||
case roleKind:
|
||||
roles = append(roles, rolebinding.Namespace+":"+rolebinding.RoleRef.Name)
|
||||
case clusterroleKind:
|
||||
clusterRoles = append(clusterRoles, rolebinding.RoleRef.Name)
|
||||
}
|
||||
if matchBindingSubjects(rolebinding.Subjects, userInfo, rolebinding.Namespace) {
|
||||
switch rolebinding.RoleRef.Kind {
|
||||
case roleKind:
|
||||
roles = append(roles, rolebinding.Namespace+":"+rolebinding.RoleRef.Name)
|
||||
case clusterroleKind:
|
||||
clusterRoles = append(clusterRoles, rolebinding.RoleRef.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return roles, clusterRoles
|
||||
}
|
||||
|
||||
// RoleRef in ClusterRoleBindings can only reference a ClusterRole in the global namespace
|
||||
func getRoleRefByClusterRoleBindings(clusterroleBindings []*rbacv1.ClusterRoleBinding, userInfo authenticationv1.UserInfo) (clusterRoles []string) {
|
||||
for _, clusterRoleBinding := range clusterroleBindings {
|
||||
for _, subject := range clusterRoleBinding.Subjects {
|
||||
if matchSubjectsMap(subject, userInfo, subject.Namespace) {
|
||||
if clusterRoleBinding.RoleRef.Kind == clusterroleKind {
|
||||
clusterRoles = append(clusterRoles, clusterRoleBinding.RoleRef.Name)
|
||||
}
|
||||
if matchBindingSubjects(clusterRoleBinding.Subjects, userInfo, "") {
|
||||
if clusterRoleBinding.RoleRef.Kind == clusterroleKind {
|
||||
clusterRoles = append(clusterRoles, clusterRoleBinding.RoleRef.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return clusterRoles
|
||||
}
|
||||
|
||||
// matchSubjectsMap checks if userInfo found in subject
|
||||
// return true directly if found a match
|
||||
// subject.kind can only be ServiceAccount, User and Group
|
||||
func matchSubjectsMap(subject rbacv1.Subject, userInfo authenticationv1.UserInfo, namespace string) bool {
|
||||
if strings.Contains(userInfo.Username, saPrefix) {
|
||||
return matchServiceAccount(subject, userInfo, namespace)
|
||||
}
|
||||
return matchUserOrGroup(subject, userInfo)
|
||||
}
|
||||
|
||||
// matchServiceAccount checks if userInfo sa matche the subject sa
|
||||
// serviceaccount represents as saPrefix:namespace:name in userInfo
|
||||
func matchServiceAccount(subject rbacv1.Subject, userInfo authenticationv1.UserInfo, namespace string) bool {
|
||||
subjectServiceAccount := namespace + ":" + subject.Name
|
||||
if userInfo.Username[len(saPrefix):] != subjectServiceAccount {
|
||||
return false
|
||||
}
|
||||
logging.V(3).Info(fmt.Sprintf("found a matched service account not match: %s", subjectServiceAccount))
|
||||
return true
|
||||
}
|
||||
|
||||
// matchUserOrGroup checks if userInfo contains user or group info in a subject
|
||||
func matchUserOrGroup(subject rbacv1.Subject, userInfo authenticationv1.UserInfo) bool {
|
||||
keys := append(userInfo.Groups, userInfo.Username)
|
||||
for _, key := range keys {
|
||||
if subject.Name == key {
|
||||
logging.V(3).Info(fmt.Sprintf("found a matched user/group '%v' in request userInfo: %v", subject.Name, keys))
|
||||
return true
|
||||
func matchBindingSubjects(subjects []rbacv1.Subject, userInfo authenticationv1.UserInfo, namespace string) bool {
|
||||
for _, subject := range subjects {
|
||||
switch subject.Kind {
|
||||
case rbacv1.ServiceAccountKind:
|
||||
ns := subject.Namespace
|
||||
if ns == "" {
|
||||
ns = namespace
|
||||
}
|
||||
if ns != "" {
|
||||
username := "system:serviceaccount:" + ns + ":" + subject.Name
|
||||
if userInfo.Username == username {
|
||||
return true
|
||||
}
|
||||
}
|
||||
case rbacv1.GroupKind:
|
||||
for _, group := range userInfo.Groups {
|
||||
if group == subject.Name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
case rbacv1.UserKind:
|
||||
if userInfo.Username == subject.Name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
|
|
@ -1,253 +1,409 @@
|
|||
package userinfo
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
authenticationv1 "k8s.io/api/authentication/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func Test_matchServiceAccount_subject_variants(t *testing.T) {
|
||||
userInfo := authenticationv1.UserInfo{
|
||||
Username: "system:serviceaccount:default:saconfig",
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
subject rbacv1.Subject
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
subject: rbacv1.Subject{},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
subject: rbacv1.Subject{
|
||||
Kind: "serviceaccount",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
subject: rbacv1.Subject{
|
||||
Kind: "ServiceAccount",
|
||||
Namespace: "testnamespace",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
subject: rbacv1.Subject{
|
||||
Kind: "ServiceAccount",
|
||||
Namespace: "1",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
subject: rbacv1.Subject{
|
||||
Kind: "ServiceAccount",
|
||||
Namespace: "testnamespace",
|
||||
Name: "",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
subject: rbacv1.Subject{
|
||||
Kind: "ServiceAccount",
|
||||
Namespace: "testnamespace",
|
||||
Name: "testname",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
res := matchServiceAccount(test.subject, userInfo, test.subject.Namespace)
|
||||
assert.Equal(t, test.expected, res)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_matchUserOrGroup(t *testing.T) {
|
||||
group := authenticationv1.UserInfo{
|
||||
Username: "kubernetes-admin",
|
||||
Groups: []string{"system:masters", "system:authenticated"},
|
||||
}
|
||||
|
||||
sa := authenticationv1.UserInfo{
|
||||
Username: "system:serviceaccount:kube-system:deployment-controller",
|
||||
Groups: []string{"system:serviceaccounts", "system:serviceaccounts:kube-system", "system:authenticated"},
|
||||
}
|
||||
|
||||
user := authenticationv1.UserInfo{
|
||||
Username: "system:kube-scheduler",
|
||||
Groups: []string{"system:authenticated"},
|
||||
}
|
||||
|
||||
userContext := rbacv1.Subject{
|
||||
Kind: "User",
|
||||
Name: "system:kube-scheduler",
|
||||
}
|
||||
|
||||
groupContext := rbacv1.Subject{
|
||||
Kind: "Group",
|
||||
Name: "system:masters",
|
||||
}
|
||||
|
||||
fakegroupContext := rbacv1.Subject{
|
||||
Kind: "Group",
|
||||
Name: "fakeGroup",
|
||||
}
|
||||
|
||||
res := matchUserOrGroup(userContext, user)
|
||||
assert.Assert(t, res)
|
||||
|
||||
res = matchUserOrGroup(groupContext, group)
|
||||
assert.Assert(t, res)
|
||||
|
||||
res = matchUserOrGroup(groupContext, sa)
|
||||
assert.Assert(t, !res)
|
||||
|
||||
res = matchUserOrGroup(fakegroupContext, group)
|
||||
assert.Assert(t, !res)
|
||||
}
|
||||
|
||||
func Test_matchSubjectsMap(t *testing.T) {
|
||||
sa := authenticationv1.UserInfo{
|
||||
Username: "system:serviceaccount:default:saconfig",
|
||||
}
|
||||
|
||||
group := authenticationv1.UserInfo{
|
||||
Username: "kubernetes-admin",
|
||||
Groups: []string{"system:masters", "system:authenticated"},
|
||||
}
|
||||
|
||||
sasubject := rbacv1.Subject{
|
||||
Kind: "ServiceAccount",
|
||||
Namespace: "default",
|
||||
Name: "saconfig",
|
||||
}
|
||||
|
||||
groupsubject := rbacv1.Subject{
|
||||
Kind: "Group",
|
||||
Name: "fakeGroup",
|
||||
}
|
||||
|
||||
res := matchSubjectsMap(sasubject, sa, sasubject.Namespace)
|
||||
assert.Assert(t, res)
|
||||
|
||||
res = matchSubjectsMap(groupsubject, group, "")
|
||||
assert.Assert(t, !res)
|
||||
}
|
||||
|
||||
func newRoleBinding(name, ns string, subjects []rbacv1.Subject, roles rbacv1.RoleRef) *rbacv1.RoleBinding {
|
||||
rb := &rbacv1.RoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: ns},
|
||||
Subjects: subjects,
|
||||
RoleRef: roles,
|
||||
}
|
||||
|
||||
rb.Kind = "RoleBinding"
|
||||
rb.APIVersion = "rbac.authorization.k8s.io/v1"
|
||||
return rb
|
||||
}
|
||||
|
||||
func Test_getRoleRefByRoleBindings(t *testing.T) {
|
||||
|
||||
// flag.Parse()
|
||||
// flag.Set("logtostderr", "true")
|
||||
// flag.Set("v", "3")
|
||||
|
||||
list := make([]*rbacv1.RoleBinding, 2)
|
||||
|
||||
list[0] = newRoleBinding("test1", "default",
|
||||
[]rbacv1.Subject{
|
||||
{
|
||||
Kind: "ServiceAccount",
|
||||
Name: "saconfig",
|
||||
Namespace: "default",
|
||||
},
|
||||
}, rbacv1.RoleRef{
|
||||
Kind: roleKind,
|
||||
Name: "myrole",
|
||||
roleInSameNsImplicit := &rbacv1.RoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "same-ns",
|
||||
Namespace: "ns-1",
|
||||
},
|
||||
)
|
||||
|
||||
list[1] = newRoleBinding("test2", "default",
|
||||
[]rbacv1.Subject{
|
||||
{
|
||||
Kind: "ServiceAccount",
|
||||
Name: "saconfig",
|
||||
Namespace: "default",
|
||||
},
|
||||
}, rbacv1.RoleRef{
|
||||
Kind: clusterroleKind,
|
||||
Name: "myclusterrole",
|
||||
Subjects: []rbacv1.Subject{{
|
||||
Kind: "ServiceAccount",
|
||||
Name: "sa",
|
||||
}},
|
||||
RoleRef: rbacv1.RoleRef{
|
||||
Kind: "Role",
|
||||
Name: "role-1",
|
||||
},
|
||||
)
|
||||
|
||||
sa := authenticationv1.UserInfo{
|
||||
Username: "system:serviceaccount:default:saconfig",
|
||||
}
|
||||
|
||||
expectedrole := []string{list[0].Namespace + ":" + "myrole"}
|
||||
expectedClusterRole := []string{"myclusterrole"}
|
||||
roles, clusterroles := getRoleRefByRoleBindings(list, sa)
|
||||
assert.DeepEqual(t, roles, expectedrole)
|
||||
assert.DeepEqual(t, clusterroles, expectedClusterRole)
|
||||
roleInSameNsExplicit := &rbacv1.RoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "same-ns",
|
||||
Namespace: "ns-1",
|
||||
},
|
||||
Subjects: []rbacv1.Subject{{
|
||||
Kind: "ServiceAccount",
|
||||
Name: "sa",
|
||||
Namespace: "ns-1",
|
||||
}},
|
||||
RoleRef: rbacv1.RoleRef{
|
||||
Kind: "Role",
|
||||
Name: "role-1",
|
||||
},
|
||||
}
|
||||
roleInAnotherNs := &rbacv1.RoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "different-ns",
|
||||
Namespace: "ns-2",
|
||||
},
|
||||
Subjects: []rbacv1.Subject{{
|
||||
Kind: "ServiceAccount",
|
||||
Name: "sa",
|
||||
Namespace: "ns-1",
|
||||
}},
|
||||
RoleRef: rbacv1.RoleRef{
|
||||
Kind: "Role",
|
||||
Name: "role-1",
|
||||
},
|
||||
}
|
||||
clusterRole := &rbacv1.RoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "different-ns",
|
||||
Namespace: "ns-2",
|
||||
},
|
||||
Subjects: []rbacv1.Subject{{
|
||||
Kind: "ServiceAccount",
|
||||
Name: "sa",
|
||||
Namespace: "ns-1",
|
||||
}},
|
||||
RoleRef: rbacv1.RoleRef{
|
||||
Kind: "ClusterRole",
|
||||
Name: "role-1",
|
||||
},
|
||||
}
|
||||
userInfo := authenticationv1.UserInfo{
|
||||
Username: "system:serviceaccount:ns-1:sa",
|
||||
}
|
||||
type args struct {
|
||||
roleBindings []*rbacv1.RoleBinding
|
||||
userInfo authenticationv1.UserInfo
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantRoles []string
|
||||
wantClusterRoles []string
|
||||
}{{
|
||||
name: "service account and role binding explicitely in the same namespace",
|
||||
args: args{
|
||||
roleBindings: []*rbacv1.RoleBinding{
|
||||
roleInSameNsExplicit,
|
||||
},
|
||||
userInfo: userInfo,
|
||||
},
|
||||
wantRoles: []string{
|
||||
"ns-1:role-1",
|
||||
},
|
||||
}, {
|
||||
name: "service account and role binding implicitely in the same namespace",
|
||||
args: args{
|
||||
roleBindings: []*rbacv1.RoleBinding{
|
||||
roleInSameNsImplicit,
|
||||
},
|
||||
userInfo: userInfo,
|
||||
},
|
||||
wantRoles: []string{
|
||||
"ns-1:role-1",
|
||||
},
|
||||
}, {
|
||||
name: "service account and role binding in the different namespaces",
|
||||
args: args{
|
||||
roleBindings: []*rbacv1.RoleBinding{
|
||||
roleInAnotherNs,
|
||||
},
|
||||
userInfo: userInfo,
|
||||
},
|
||||
wantRoles: []string{
|
||||
"ns-2:role-1",
|
||||
},
|
||||
}, {
|
||||
name: "cluster role",
|
||||
args: args{
|
||||
roleBindings: []*rbacv1.RoleBinding{
|
||||
clusterRole,
|
||||
},
|
||||
userInfo: userInfo,
|
||||
},
|
||||
wantClusterRoles: []string{
|
||||
"role-1",
|
||||
},
|
||||
}, {
|
||||
name: "all together",
|
||||
args: args{
|
||||
roleBindings: []*rbacv1.RoleBinding{
|
||||
roleInSameNsExplicit,
|
||||
roleInSameNsImplicit,
|
||||
roleInAnotherNs,
|
||||
clusterRole,
|
||||
},
|
||||
userInfo: userInfo,
|
||||
},
|
||||
wantRoles: []string{
|
||||
"ns-1:role-1",
|
||||
"ns-1:role-1",
|
||||
"ns-2:role-1",
|
||||
},
|
||||
wantClusterRoles: []string{
|
||||
"role-1",
|
||||
},
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotRoles, gotClusterRoles := getRoleRefByRoleBindings(tt.args.roleBindings, tt.args.userInfo)
|
||||
if !reflect.DeepEqual(gotRoles, tt.wantRoles) {
|
||||
t.Errorf("getRoleRefByRoleBindings() gotRoles = %v, want %v", gotRoles, tt.wantRoles)
|
||||
}
|
||||
if !reflect.DeepEqual(gotClusterRoles, tt.wantClusterRoles) {
|
||||
t.Errorf("getRoleRefByRoleBindings() gotClusterRoles = %v, want %v", gotClusterRoles, tt.wantClusterRoles)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newClusterRoleBinding(name, ns string, subjects []rbacv1.Subject, roles rbacv1.RoleRef) *rbacv1.ClusterRoleBinding {
|
||||
rb := &rbacv1.ClusterRoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: ns},
|
||||
Subjects: subjects,
|
||||
RoleRef: roles,
|
||||
func Test_matchBindingSubjects(t *testing.T) {
|
||||
type args struct {
|
||||
subjects []rbacv1.Subject
|
||||
userInfo authenticationv1.UserInfo
|
||||
namespace string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
}{{
|
||||
name: "empty subjects",
|
||||
args: args{
|
||||
subjects: []rbacv1.Subject{},
|
||||
userInfo: authenticationv1.UserInfo{
|
||||
Username: "system:serviceaccount:foo:test",
|
||||
},
|
||||
namespace: "",
|
||||
},
|
||||
want: false,
|
||||
}, {
|
||||
name: "nil subjects",
|
||||
args: args{
|
||||
subjects: nil,
|
||||
userInfo: authenticationv1.UserInfo{
|
||||
Username: "system:serviceaccount:foo:test",
|
||||
},
|
||||
namespace: "",
|
||||
},
|
||||
want: false,
|
||||
}, {
|
||||
name: "match service account",
|
||||
args: args{
|
||||
subjects: []rbacv1.Subject{{
|
||||
Kind: rbacv1.ServiceAccountKind,
|
||||
Name: "test",
|
||||
Namespace: "foo",
|
||||
}},
|
||||
userInfo: authenticationv1.UserInfo{
|
||||
Username: "system:serviceaccount:foo:test",
|
||||
},
|
||||
namespace: "",
|
||||
},
|
||||
want: true,
|
||||
}, {
|
||||
name: "match service account with fallback namespace",
|
||||
args: args{
|
||||
subjects: []rbacv1.Subject{{
|
||||
Kind: rbacv1.ServiceAccountKind,
|
||||
Name: "test",
|
||||
}},
|
||||
userInfo: authenticationv1.UserInfo{
|
||||
Username: "system:serviceaccount:foo:test",
|
||||
},
|
||||
namespace: "foo",
|
||||
},
|
||||
want: true,
|
||||
}, {
|
||||
name: "don't match service account",
|
||||
args: args{
|
||||
subjects: []rbacv1.Subject{{
|
||||
Kind: rbacv1.ServiceAccountKind,
|
||||
Name: "test",
|
||||
Namespace: "foo",
|
||||
}},
|
||||
userInfo: authenticationv1.UserInfo{
|
||||
Username: "system:serviceaccount:bar:test",
|
||||
},
|
||||
namespace: "",
|
||||
},
|
||||
want: false,
|
||||
}, {
|
||||
name: "don't match service account with fallback namespace",
|
||||
args: args{
|
||||
subjects: []rbacv1.Subject{{
|
||||
Kind: rbacv1.ServiceAccountKind,
|
||||
Name: "test",
|
||||
}},
|
||||
userInfo: authenticationv1.UserInfo{
|
||||
Username: "system:serviceaccount:bar:test",
|
||||
},
|
||||
namespace: "foo",
|
||||
},
|
||||
want: false,
|
||||
}, {
|
||||
name: "don't match service account with no namespace and no fallback namespace",
|
||||
args: args{
|
||||
subjects: []rbacv1.Subject{{
|
||||
Kind: rbacv1.ServiceAccountKind,
|
||||
Name: "test",
|
||||
}},
|
||||
userInfo: authenticationv1.UserInfo{
|
||||
Username: "system:serviceaccount::test",
|
||||
},
|
||||
namespace: "",
|
||||
},
|
||||
want: false,
|
||||
}, {
|
||||
name: "match user",
|
||||
args: args{
|
||||
subjects: []rbacv1.Subject{{
|
||||
Kind: rbacv1.UserKind,
|
||||
Name: "someone@company.org",
|
||||
}},
|
||||
userInfo: authenticationv1.UserInfo{
|
||||
Username: "someone@company.org",
|
||||
},
|
||||
namespace: "",
|
||||
},
|
||||
want: true,
|
||||
}, {
|
||||
name: "don't match user",
|
||||
args: args{
|
||||
subjects: []rbacv1.Subject{{
|
||||
Kind: rbacv1.UserKind,
|
||||
Name: "someone@company.org",
|
||||
}},
|
||||
userInfo: authenticationv1.UserInfo{
|
||||
Username: "someone-else@company.org",
|
||||
},
|
||||
namespace: "",
|
||||
},
|
||||
want: false,
|
||||
}, {
|
||||
name: "match group",
|
||||
args: args{
|
||||
subjects: []rbacv1.Subject{{
|
||||
Kind: rbacv1.GroupKind,
|
||||
Name: "admin",
|
||||
}},
|
||||
userInfo: authenticationv1.UserInfo{
|
||||
Username: "someone@company.org",
|
||||
Groups: []string{
|
||||
"user",
|
||||
"dev",
|
||||
"admin",
|
||||
},
|
||||
},
|
||||
namespace: "",
|
||||
},
|
||||
want: true,
|
||||
}, {
|
||||
name: "don't match group",
|
||||
args: args{
|
||||
subjects: []rbacv1.Subject{{
|
||||
Kind: rbacv1.GroupKind,
|
||||
Name: "marketing",
|
||||
}},
|
||||
userInfo: authenticationv1.UserInfo{
|
||||
Username: "someone@company.org",
|
||||
Groups: []string{
|
||||
"user",
|
||||
"dev",
|
||||
"admin",
|
||||
},
|
||||
},
|
||||
namespace: "",
|
||||
},
|
||||
want: false,
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := matchBindingSubjects(tt.args.subjects, tt.args.userInfo, tt.args.namespace); got != tt.want {
|
||||
t.Errorf("matchBindingSubjects() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
rb.Kind = "ClusterRoleBinding"
|
||||
rb.APIVersion = "rbac.authorization.k8s.io/v1"
|
||||
return rb
|
||||
}
|
||||
|
||||
func Test_getRoleRefByClusterRoleBindings(t *testing.T) {
|
||||
|
||||
list := make([]*rbacv1.ClusterRoleBinding, 2)
|
||||
|
||||
list[0] = newClusterRoleBinding("test1", "mynamespace",
|
||||
[]rbacv1.Subject{
|
||||
{
|
||||
Kind: "User",
|
||||
Name: "kube-scheduler",
|
||||
},
|
||||
}, rbacv1.RoleRef{
|
||||
Kind: clusterroleKind,
|
||||
Name: "fakeclusterrole",
|
||||
clusterRole1 := &rbacv1.ClusterRoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cluster-role",
|
||||
},
|
||||
)
|
||||
|
||||
list[1] = newClusterRoleBinding("test2", "mynamespace",
|
||||
[]rbacv1.Subject{
|
||||
{
|
||||
Kind: "Group",
|
||||
Name: "system:masters",
|
||||
},
|
||||
}, rbacv1.RoleRef{
|
||||
Kind: clusterroleKind,
|
||||
Name: "myclusterrole",
|
||||
Subjects: []rbacv1.Subject{{
|
||||
Kind: "ServiceAccount",
|
||||
Name: "sa",
|
||||
Namespace: "foo",
|
||||
}},
|
||||
RoleRef: rbacv1.RoleRef{
|
||||
Kind: "ClusterRole",
|
||||
Name: "role-1",
|
||||
},
|
||||
)
|
||||
|
||||
group := authenticationv1.UserInfo{
|
||||
Username: "kubernetes-admin",
|
||||
Groups: []string{"system:masters", "system:authenticated"},
|
||||
}
|
||||
|
||||
user := authenticationv1.UserInfo{
|
||||
Username: "system:kube-scheduler",
|
||||
Groups: []string{"system:authenticated"},
|
||||
clusterRole2 := &rbacv1.ClusterRoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cluster-role",
|
||||
},
|
||||
Subjects: []rbacv1.Subject{{
|
||||
Kind: "ServiceAccount",
|
||||
Name: "sa",
|
||||
Namespace: "bar",
|
||||
}},
|
||||
RoleRef: rbacv1.RoleRef{
|
||||
Kind: "ClusterRole",
|
||||
Name: "role-2",
|
||||
},
|
||||
}
|
||||
userInfo := authenticationv1.UserInfo{
|
||||
Username: "system:serviceaccount:foo:sa",
|
||||
}
|
||||
type args struct {
|
||||
clusterroleBindings []*rbacv1.ClusterRoleBinding
|
||||
userInfo authenticationv1.UserInfo
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantClusterRoles []string
|
||||
}{{
|
||||
name: "match service account",
|
||||
args: args{
|
||||
clusterroleBindings: []*rbacv1.ClusterRoleBinding{
|
||||
clusterRole1,
|
||||
},
|
||||
userInfo: userInfo,
|
||||
},
|
||||
wantClusterRoles: []string{
|
||||
"role-1",
|
||||
},
|
||||
}, {
|
||||
name: "sa in another namespace",
|
||||
args: args{
|
||||
clusterroleBindings: []*rbacv1.ClusterRoleBinding{
|
||||
clusterRole2,
|
||||
},
|
||||
userInfo: userInfo,
|
||||
},
|
||||
}, {
|
||||
name: "match service account",
|
||||
args: args{
|
||||
clusterroleBindings: []*rbacv1.ClusterRoleBinding{
|
||||
clusterRole1,
|
||||
clusterRole2,
|
||||
},
|
||||
userInfo: userInfo,
|
||||
},
|
||||
wantClusterRoles: []string{
|
||||
"role-1",
|
||||
},
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if gotClusterRoles := getRoleRefByClusterRoleBindings(tt.args.clusterroleBindings, tt.args.userInfo); !reflect.DeepEqual(gotClusterRoles, tt.wantClusterRoles) {
|
||||
t.Errorf("getRoleRefByClusterRoleBindings() = %v, want %v", gotClusterRoles, tt.wantClusterRoles)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
clusterroles := getRoleRefByClusterRoleBindings(list, group)
|
||||
assert.DeepEqual(t, clusterroles, []string{"myclusterrole"})
|
||||
|
||||
clusterroles = getRoleRefByClusterRoleBindings(list, user)
|
||||
assert.Equal(t, len(clusterroles), 0)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue