mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-15 17:51:20 +00:00
0fb8c723fe
Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
704 lines
16 KiB
Go
704 lines
16 KiB
Go
package userinfo
|
|
|
|
import (
|
|
"errors"
|
|
"reflect"
|
|
"testing"
|
|
|
|
authenticationv1 "k8s.io/api/authentication/v1"
|
|
rbacv1 "k8s.io/api/rbac/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
labels "k8s.io/apimachinery/pkg/labels"
|
|
)
|
|
|
|
func Test_getRoleRefByRoleBindings(t *testing.T) {
|
|
roleInSameNsImplicit := &rbacv1.RoleBinding{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "same-ns",
|
|
Namespace: "ns-1",
|
|
},
|
|
Subjects: []rbacv1.Subject{{
|
|
Kind: "ServiceAccount",
|
|
Name: "sa",
|
|
}},
|
|
RoleRef: rbacv1.RoleRef{
|
|
Kind: "Role",
|
|
Name: "role-1",
|
|
},
|
|
}
|
|
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 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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_getRoleRefByClusterRoleBindings(t *testing.T) {
|
|
clusterRole1 := &rbacv1.ClusterRoleBinding{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cluster-role",
|
|
},
|
|
Subjects: []rbacv1.Subject{{
|
|
Kind: "ServiceAccount",
|
|
Name: "sa",
|
|
Namespace: "foo",
|
|
}},
|
|
RoleRef: rbacv1.RoleRef{
|
|
Kind: "ClusterRole",
|
|
Name: "role-1",
|
|
},
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
type roleBindingLister struct {
|
|
ret []*rbacv1.RoleBinding
|
|
err error
|
|
}
|
|
|
|
func (l roleBindingLister) List(labels.Selector) ([]*rbacv1.RoleBinding, error) {
|
|
return l.ret, l.err
|
|
}
|
|
|
|
type clusterRoleBindingLister struct {
|
|
ret []*rbacv1.ClusterRoleBinding
|
|
err error
|
|
}
|
|
|
|
func (l clusterRoleBindingLister) List(labels.Selector) ([]*rbacv1.ClusterRoleBinding, error) {
|
|
return l.ret, l.err
|
|
}
|
|
|
|
func TestGetRoleRef(t *testing.T) {
|
|
type args struct {
|
|
rbLister RoleBindingLister
|
|
crbLister ClusterRoleBindingLister
|
|
userInfo authenticationv1.UserInfo
|
|
}
|
|
type want struct {
|
|
roles []string
|
|
clusterRoles []string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want want
|
|
wantErr bool
|
|
}{
|
|
{
|
|
args: args{
|
|
rbLister: roleBindingLister{
|
|
ret: []*rbacv1.RoleBinding{{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "same-ns",
|
|
Namespace: "ns-1",
|
|
},
|
|
Subjects: []rbacv1.Subject{{
|
|
Kind: "ServiceAccount",
|
|
Name: "sa",
|
|
}},
|
|
RoleRef: rbacv1.RoleRef{
|
|
Kind: "Role",
|
|
Name: "role-1",
|
|
},
|
|
}, {
|
|
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",
|
|
},
|
|
}, {
|
|
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",
|
|
},
|
|
}, {
|
|
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",
|
|
},
|
|
}},
|
|
},
|
|
crbLister: clusterRoleBindingLister{},
|
|
userInfo: authenticationv1.UserInfo{
|
|
Username: "system:serviceaccount:ns-1:sa",
|
|
},
|
|
},
|
|
want: want{
|
|
roles: []string{"ns-1:role-1", "ns-2:role-1"},
|
|
clusterRoles: []string{"role-1"},
|
|
},
|
|
}, {
|
|
args: args{
|
|
rbLister: roleBindingLister{
|
|
err: errors.New("error"),
|
|
},
|
|
crbLister: clusterRoleBindingLister{},
|
|
userInfo: authenticationv1.UserInfo{
|
|
Username: "system:serviceaccount:ns-1:sa",
|
|
},
|
|
},
|
|
wantErr: true,
|
|
}, {
|
|
args: args{
|
|
rbLister: roleBindingLister{},
|
|
crbLister: clusterRoleBindingLister{
|
|
err: errors.New("error"),
|
|
},
|
|
userInfo: authenticationv1.UserInfo{
|
|
Username: "system:serviceaccount:ns-1:sa",
|
|
},
|
|
},
|
|
wantErr: true,
|
|
}, {
|
|
args: args{
|
|
rbLister: roleBindingLister{
|
|
err: errors.New("error"),
|
|
},
|
|
crbLister: clusterRoleBindingLister{
|
|
err: errors.New("error"),
|
|
},
|
|
userInfo: authenticationv1.UserInfo{
|
|
Username: "system:serviceaccount:ns-1:sa",
|
|
},
|
|
},
|
|
wantErr: true,
|
|
}, {
|
|
args: args{
|
|
rbLister: roleBindingLister{},
|
|
crbLister: clusterRoleBindingLister{
|
|
ret: []*rbacv1.ClusterRoleBinding{{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cluster-role",
|
|
},
|
|
Subjects: []rbacv1.Subject{{
|
|
Kind: "ServiceAccount",
|
|
Name: "sa",
|
|
Namespace: "foo",
|
|
}},
|
|
RoleRef: rbacv1.RoleRef{
|
|
Kind: "ClusterRole",
|
|
Name: "role-1",
|
|
},
|
|
}, {
|
|
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",
|
|
},
|
|
},
|
|
want: want{
|
|
clusterRoles: []string{"role-1"},
|
|
},
|
|
}, {
|
|
args: args{
|
|
rbLister: roleBindingLister{
|
|
ret: []*rbacv1.RoleBinding{{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "same-ns",
|
|
Namespace: "foo",
|
|
},
|
|
Subjects: []rbacv1.Subject{{
|
|
Kind: "ServiceAccount",
|
|
Name: "sa",
|
|
}},
|
|
RoleRef: rbacv1.RoleRef{
|
|
Kind: "Role",
|
|
Name: "role-1",
|
|
},
|
|
}, {
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "same-ns",
|
|
Namespace: "foo",
|
|
},
|
|
Subjects: []rbacv1.Subject{{
|
|
Kind: "ServiceAccount",
|
|
Name: "sa",
|
|
Namespace: "foo",
|
|
}},
|
|
RoleRef: rbacv1.RoleRef{
|
|
Kind: "Role",
|
|
Name: "role-1",
|
|
},
|
|
}, {
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "different-ns",
|
|
Namespace: "ns-2",
|
|
},
|
|
Subjects: []rbacv1.Subject{{
|
|
Kind: "ServiceAccount",
|
|
Name: "sa",
|
|
Namespace: "foo",
|
|
}},
|
|
RoleRef: rbacv1.RoleRef{
|
|
Kind: "Role",
|
|
Name: "role-1",
|
|
},
|
|
}, {
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "different-ns",
|
|
Namespace: "ns-2",
|
|
},
|
|
Subjects: []rbacv1.Subject{{
|
|
Kind: "ServiceAccount",
|
|
Name: "sa",
|
|
Namespace: "foo",
|
|
}},
|
|
RoleRef: rbacv1.RoleRef{
|
|
Kind: "ClusterRole",
|
|
Name: "role-1",
|
|
},
|
|
}},
|
|
},
|
|
crbLister: clusterRoleBindingLister{
|
|
ret: []*rbacv1.ClusterRoleBinding{{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cluster-role",
|
|
},
|
|
Subjects: []rbacv1.Subject{{
|
|
Kind: "ServiceAccount",
|
|
Name: "sa",
|
|
Namespace: "foo",
|
|
}},
|
|
RoleRef: rbacv1.RoleRef{
|
|
Kind: "ClusterRole",
|
|
Name: "role-1",
|
|
},
|
|
}, {
|
|
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",
|
|
},
|
|
},
|
|
want: want{
|
|
roles: []string{"foo:role-1", "ns-2:role-1"},
|
|
clusterRoles: []string{"role-1"},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
roles, clusterRoles, err := GetRoleRef(tt.args.rbLister, tt.args.crbLister, tt.args.userInfo)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("GetRoleRef() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(roles, tt.want.roles) {
|
|
t.Errorf("GetRoleRef() roles = %v, want %v", roles, tt.want.roles)
|
|
}
|
|
if !reflect.DeepEqual(clusterRoles, tt.want.clusterRoles) {
|
|
t.Errorf("GetRoleRef() clusterRoles = %v, want %v", clusterRoles, tt.want.clusterRoles)
|
|
}
|
|
})
|
|
}
|
|
}
|