@@ -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+
9181160var _ = 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