Skip to content

Commit 7615380

Browse files
Wei WengWei Weng
authored andcommitted
add guard rail test for pod and rs
Signed-off-by: Wei Weng <[email protected]>
1 parent 0da1f98 commit 7615380

File tree

1 file changed

+242
-0
lines changed

1 file changed

+242
-0
lines changed

test/e2e/fleet_guard_rail_test.go

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"k8s.io/apimachinery/pkg/runtime"
3333
"k8s.io/apimachinery/pkg/types"
3434
utilrand "k8s.io/apimachinery/pkg/util/rand"
35+
"k8s.io/utils/ptr"
3536

3637
clusterv1beta1 "github.com/kubefleet-dev/kubefleet/apis/cluster/v1beta1"
3738
placementv1beta1 "github.com/kubefleet-dev/kubefleet/apis/placement/v1beta1"
@@ -915,6 +916,247 @@ var _ = Describe("fleet guard rail networking E2Es", Serial, Ordered, func() {
915916
})
916917
})
917918

919+
var _ = Describe("fleet guard rail for pods and replicasets in fleet/kube namespaces", Serial, Ordered, func() {
920+
var (
921+
podGVK = metav1.GroupVersionKind{Group: corev1.SchemeGroupVersion.Group, Version: corev1.SchemeGroupVersion.Version, Kind: "Pod"}
922+
replicaSetGVK = metav1.GroupVersionKind{Group: appsv1.SchemeGroupVersion.Group, Version: appsv1.SchemeGroupVersion.Version, Kind: "ReplicaSet"}
923+
)
924+
925+
Context("deny pod operations in fleet-system namespace", func() {
926+
It("should deny CREATE operation on pod in fleet-system namespace for user not in system:masters", func() {
927+
pod := corev1.Pod{
928+
ObjectMeta: metav1.ObjectMeta{
929+
Name: "test-pod",
930+
Namespace: "fleet-system",
931+
},
932+
Spec: corev1.PodSpec{
933+
Containers: []corev1.Container{
934+
{
935+
Name: "test-container",
936+
Image: "nginx:latest",
937+
},
938+
},
939+
},
940+
}
941+
Expect(checkIfStatusErrorWithMessage(impersonateHubClient.Create(ctx, &pod), fmt.Sprintf(validation.ResourceDeniedFormat, testUser, utils.GenerateGroupString(testGroups), admissionv1.Create, &podGVK, "", types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}))).Should(Succeed())
942+
})
943+
944+
It("should deny UPDATE operation on pod in fleet-system namespace for user not in system:masters", func() {
945+
// First create a pod as admin
946+
pod := corev1.Pod{
947+
ObjectMeta: metav1.ObjectMeta{
948+
Name: "test-pod-update",
949+
Namespace: "fleet-system",
950+
},
951+
Spec: corev1.PodSpec{
952+
Containers: []corev1.Container{
953+
{
954+
Name: "test-container",
955+
Image: "nginx:latest",
956+
},
957+
},
958+
},
959+
}
960+
Expect(hubClient.Create(ctx, &pod)).Should(Succeed())
961+
962+
// Try to update as non-admin
963+
Eventually(func(g Gomega) error {
964+
var p corev1.Pod
965+
err := hubClient.Get(ctx, types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}, &p)
966+
if err != nil {
967+
return err
968+
}
969+
p.Labels = map[string]string{testKey: testValue}
970+
err = impersonateHubClient.Update(ctx, &p)
971+
if k8sErrors.IsConflict(err) {
972+
return err
973+
}
974+
return checkIfStatusErrorWithMessage(err, fmt.Sprintf(validation.ResourceDeniedFormat, testUser, utils.GenerateGroupString(testGroups), admissionv1.Update, &podGVK, "", types.NamespacedName{Name: p.Name, Namespace: p.Namespace}))
975+
}, eventuallyDuration, eventuallyInterval).Should(Succeed())
976+
977+
// Cleanup
978+
Expect(hubClient.Delete(ctx, &pod)).Should(Succeed())
979+
})
980+
})
981+
982+
Context("deny replicaset operations in fleet-member namespace", func() {
983+
var (
984+
mcName string
985+
imcNamespace string
986+
)
987+
988+
BeforeAll(func() {
989+
mcName = fmt.Sprintf(mcNameTemplate, GinkgoParallelProcess())
990+
imcNamespace = fmt.Sprintf(utils.NamespaceNameFormat, mcName)
991+
createMemberCluster(mcName, testIdentity, nil, map[string]string{fleetClusterResourceIDAnnotationKey: clusterID1})
992+
checkInternalMemberClusterExists(mcName, imcNamespace)
993+
})
994+
995+
AfterAll(func() {
996+
ensureMemberClusterAndRelatedResourcesDeletion(mcName)
997+
})
998+
999+
It("should deny CREATE operation on replicaset in fleet-member namespace for user not in MC identity", func() {
1000+
rs := appsv1.ReplicaSet{
1001+
ObjectMeta: metav1.ObjectMeta{
1002+
Name: "test-replicaset",
1003+
Namespace: imcNamespace,
1004+
},
1005+
Spec: appsv1.ReplicaSetSpec{
1006+
Replicas: ptr.To(int32(1)),
1007+
Selector: &metav1.LabelSelector{
1008+
MatchLabels: map[string]string{"app": "test"},
1009+
},
1010+
Template: corev1.PodTemplateSpec{
1011+
ObjectMeta: metav1.ObjectMeta{
1012+
Labels: map[string]string{"app": "test"},
1013+
},
1014+
Spec: corev1.PodSpec{
1015+
Containers: []corev1.Container{
1016+
{
1017+
Name: "test-container",
1018+
Image: "nginx:latest",
1019+
},
1020+
},
1021+
},
1022+
},
1023+
},
1024+
}
1025+
Expect(checkIfStatusErrorWithMessage(impersonateHubClient.Create(ctx, &rs), fmt.Sprintf(validation.ResourceDeniedFormat, testUser, utils.GenerateGroupString(testGroups), admissionv1.Create, &replicaSetGVK, "", types.NamespacedName{Name: rs.Name, Namespace: rs.Namespace}))).Should(Succeed())
1026+
})
1027+
1028+
It("should deny UPDATE operation on replicaset in fleet-member namespace for user not in MC identity", func() {
1029+
// First create a replicaset as admin
1030+
rs := appsv1.ReplicaSet{
1031+
ObjectMeta: metav1.ObjectMeta{
1032+
Name: "test-replicaset-update",
1033+
Namespace: imcNamespace,
1034+
},
1035+
Spec: appsv1.ReplicaSetSpec{
1036+
Replicas: ptr.To(int32(1)),
1037+
Selector: &metav1.LabelSelector{
1038+
MatchLabels: map[string]string{"app": "test"},
1039+
},
1040+
Template: corev1.PodTemplateSpec{
1041+
ObjectMeta: metav1.ObjectMeta{
1042+
Labels: map[string]string{"app": "test"},
1043+
},
1044+
Spec: corev1.PodSpec{
1045+
Containers: []corev1.Container{
1046+
{
1047+
Name: "test-container",
1048+
Image: "nginx:latest",
1049+
},
1050+
},
1051+
},
1052+
},
1053+
},
1054+
}
1055+
Expect(hubClient.Create(ctx, &rs)).Should(Succeed())
1056+
1057+
// Try to update as non-admin
1058+
Eventually(func(g Gomega) error {
1059+
var r appsv1.ReplicaSet
1060+
err := hubClient.Get(ctx, types.NamespacedName{Name: rs.Name, Namespace: rs.Namespace}, &r)
1061+
if err != nil {
1062+
return err
1063+
}
1064+
r.Labels = map[string]string{testKey: testValue}
1065+
err = impersonateHubClient.Update(ctx, &r)
1066+
if k8sErrors.IsConflict(err) {
1067+
return err
1068+
}
1069+
return checkIfStatusErrorWithMessage(err, fmt.Sprintf(validation.ResourceDeniedFormat, testUser, utils.GenerateGroupString(testGroups), admissionv1.Update, &replicaSetGVK, "", types.NamespacedName{Name: r.Name, Namespace: r.Namespace}))
1070+
}, eventuallyDuration, eventuallyInterval).Should(Succeed())
1071+
1072+
// Cleanup
1073+
Expect(hubClient.Delete(ctx, &rs)).Should(Succeed())
1074+
})
1075+
1076+
It("should deny DELETE operation on pod in fleet-member namespace for user not in MC identity", func() {
1077+
// First create a pod as admin
1078+
pod := corev1.Pod{
1079+
ObjectMeta: metav1.ObjectMeta{
1080+
Name: "test-pod-delete",
1081+
Namespace: imcNamespace,
1082+
},
1083+
Spec: corev1.PodSpec{
1084+
Containers: []corev1.Container{
1085+
{
1086+
Name: "test-container",
1087+
Image: "nginx:latest",
1088+
},
1089+
},
1090+
},
1091+
}
1092+
Expect(hubClient.Create(ctx, &pod)).Should(Succeed())
1093+
1094+
// Try to delete as non-admin
1095+
Eventually(func() error {
1096+
var p corev1.Pod
1097+
err := hubClient.Get(ctx, types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}, &p)
1098+
if err != nil {
1099+
return err
1100+
}
1101+
err = impersonateHubClient.Delete(ctx, &p)
1102+
return checkIfStatusErrorWithMessage(err, fmt.Sprintf(validation.ResourceDeniedFormat, testUser, utils.GenerateGroupString(testGroups), admissionv1.Delete, &podGVK, "", types.NamespacedName{Name: p.Name, Namespace: p.Namespace}))
1103+
}, eventuallyDuration, eventuallyInterval).Should(Succeed())
1104+
1105+
// Cleanup by admin
1106+
Expect(hubClient.Delete(ctx, &pod)).Should(Succeed())
1107+
})
1108+
})
1109+
1110+
Context("deny pod/replicaset operations in kube-system namespace", func() {
1111+
It("should deny CREATE operation on pod in kube-system namespace for user not in system:masters", func() {
1112+
pod := corev1.Pod{
1113+
ObjectMeta: metav1.ObjectMeta{
1114+
Name: "test-pod-kube",
1115+
Namespace: "kube-system",
1116+
},
1117+
Spec: corev1.PodSpec{
1118+
Containers: []corev1.Container{
1119+
{
1120+
Name: "test-container",
1121+
Image: "nginx:latest",
1122+
},
1123+
},
1124+
},
1125+
}
1126+
Expect(checkIfStatusErrorWithMessage(impersonateHubClient.Create(ctx, &pod), fmt.Sprintf(validation.ResourceDeniedFormat, testUser, utils.GenerateGroupString(testGroups), admissionv1.Create, &podGVK, "", types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}))).Should(Succeed())
1127+
})
1128+
1129+
It("should deny CREATE operation on replicaset in kube-system namespace for user not in system:masters", func() {
1130+
rs := appsv1.ReplicaSet{
1131+
ObjectMeta: metav1.ObjectMeta{
1132+
Name: "test-replicaset-kube",
1133+
Namespace: "kube-system",
1134+
},
1135+
Spec: appsv1.ReplicaSetSpec{
1136+
Replicas: ptr.To(int32(1)),
1137+
Selector: &metav1.LabelSelector{
1138+
MatchLabels: map[string]string{"app": "test"},
1139+
},
1140+
Template: corev1.PodTemplateSpec{
1141+
ObjectMeta: metav1.ObjectMeta{
1142+
Labels: map[string]string{"app": "test"},
1143+
},
1144+
Spec: corev1.PodSpec{
1145+
Containers: []corev1.Container{
1146+
{
1147+
Name: "test-container",
1148+
Image: "nginx:latest",
1149+
},
1150+
},
1151+
},
1152+
},
1153+
},
1154+
}
1155+
Expect(checkIfStatusErrorWithMessage(impersonateHubClient.Create(ctx, &rs), fmt.Sprintf(validation.ResourceDeniedFormat, testUser, utils.GenerateGroupString(testGroups), admissionv1.Create, &replicaSetGVK, "", types.NamespacedName{Name: rs.Name, Namespace: rs.Namespace}))).Should(Succeed())
1156+
})
1157+
})
1158+
})
1159+
9181160
var _ = Describe("fleet guard rail restrict internal fleet resources from being created in fleet/kube pre-fixed namespaces", Serial, Ordered, func() {
9191161
Context("deny request to CREATE IMC in fleet-system namespace", func() {
9201162
It("should deny CREATE operation on internal member cluster resource in fleet-system namespace for invalid user", func() {

0 commit comments

Comments
 (0)