Skip to content

Commit ad12179

Browse files
authored
fix: use fleet-/kube- prefix checks in fleet guard rail (#1102)
1 parent 4c3b5b5 commit ad12179

3 files changed

Lines changed: 92 additions & 31 deletions

File tree

pkg/utils/common.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,16 @@ import (
4747
)
4848

4949
const (
50-
kubePrefix = "kube-"
51-
fleetPrefix = "fleet-"
52-
FleetSystemNamespace = fleetPrefix + "system"
53-
NamespaceNameFormat = fleetPrefix + "member-%s"
54-
RoleNameFormat = fleetPrefix + "role-%s"
55-
RoleBindingNameFormat = fleetPrefix + "rolebinding-%s"
56-
ValidationPathFmt = "/validate-%s-%s-%s"
57-
lessGroupsStringFormat = "groups: %v"
58-
moreGroupsStringFormat = "groups: [%s, %s, %s,......]"
50+
kubePrefix = "kube-"
51+
fleetPrefix = "fleet-"
52+
fleetMemberNamespacePrefix = fleetPrefix + "member-"
53+
FleetSystemNamespace = fleetPrefix + "system"
54+
NamespaceNameFormat = fleetMemberNamespacePrefix + "%s"
55+
RoleNameFormat = fleetPrefix + "role-%s"
56+
RoleBindingNameFormat = fleetPrefix + "rolebinding-%s"
57+
ValidationPathFmt = "/validate-%s-%s-%s"
58+
lessGroupsStringFormat = "groups: %v"
59+
moreGroupsStringFormat = "groups: [%s, %s, %s,......]"
5960
)
6061

6162
const (
@@ -592,6 +593,11 @@ func IsReservedNamespace(namespace string) bool {
592593
return strings.HasPrefix(namespace, fleetPrefix) || strings.HasPrefix(namespace, kubePrefix)
593594
}
594595

596+
// IsFleetMemberNamespace indicates if an argued namespace is a fleet member namespace.
597+
func IsFleetMemberNamespace(namespace string) bool {
598+
return strings.HasPrefix(namespace, fleetMemberNamespacePrefix)
599+
}
600+
595601
// ShouldPropagateNamespace decides if we should propagate the resources in the namespace.
596602
func ShouldPropagateNamespace(namespace string, skippedNamespaces map[string]bool) bool {
597603
if IsReservedNamespace(namespace) {

pkg/webhook/fleetresourcehandler/fleetresourcehandler_webhook.go

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"net/http"
77
"regexp"
8-
"strings"
98

109
admissionv1 "k8s.io/api/admission/v1"
1110
"k8s.io/apimachinery/pkg/runtime"
@@ -24,11 +23,15 @@ import (
2423

2524
const (
2625
// ValidationPath is the webhook service path which admission requests are routed to for validating custom resource definition resources.
27-
ValidationPath = "/validate-fleetresourcehandler"
28-
groupMatch = `^[^.]*\.(.*)`
29-
fleetMemberNamespacePrefix = "fleet-member"
30-
fleetNamespacePrefix = "fleet"
31-
kubeNamespacePrefix = "kube"
26+
ValidationPath = "/validate-fleetresourcehandler"
27+
groupMatch = `^[^.]*\.(.*)`
28+
)
29+
30+
const (
31+
// allowed messages.
32+
allowedMessageMemberCluster = "upstream member cluster resource is allowed to be created/deleted by any user"
33+
allowedMessageNonReservedNamespace = "namespace name doesn't begin with fleet-/kube- prefix so we allow all operations on this namespace"
34+
allowedMessageFleetReservedNamespacedResource = "namespace name of resource object doesn't begin with fleet-/kube- prefix so we allow all operations on request objects in these namespace"
3235
)
3336

3437
// Add registers the webhook for K8s built-in object types.
@@ -138,15 +141,15 @@ func (v *fleetResourceValidator) handleMemberCluster(req admission.Request) admi
138141
if isFleetMC {
139142
return validation.ValidateUserForResource(req, v.whiteListedUsers)
140143
}
141-
klog.V(3).InfoS("upstream member cluster resource is allowed to be created/deleted by any user",
144+
klog.V(3).InfoS(allowedMessageMemberCluster,
142145
"user", req.UserInfo.Username, "groups", req.UserInfo.Groups, "operation", req.Operation, "kind", req.RequestKind.Kind, "subResource", req.SubResource, "namespacedName", types.NamespacedName{Name: req.Name, Namespace: req.Namespace})
143-
return admission.Allowed("upstream member cluster resource is allowed to be created/deleted by any user")
146+
return admission.Allowed(allowedMessageMemberCluster)
144147
}
145148

146149
// handleFleetReservedNamespacedResource allows/denies the request to modify object after validation.
147150
func (v *fleetResourceValidator) handleFleetReservedNamespacedResource(ctx context.Context, req admission.Request) admission.Response {
148151
var response admission.Response
149-
if strings.HasPrefix(req.Namespace, fleetMemberNamespacePrefix) {
152+
if utils.IsFleetMemberNamespace(req.Namespace) {
150153
// check to see if valid users other than member agent is making the request.
151154
response = validation.ValidateUserForResource(req, v.whiteListedUsers)
152155
// check to see if member agent is making the request only on Update.
@@ -156,12 +159,12 @@ func (v *fleetResourceValidator) handleFleetReservedNamespacedResource(ctx conte
156159
return validation.ValidateMCIdentity(ctx, v.client, req, mcName, v.isFleetV1Beta1API)
157160
}
158161
return response
159-
} else if strings.HasPrefix(req.Namespace, fleetNamespacePrefix) || strings.HasPrefix(req.Namespace, kubeNamespacePrefix) {
162+
} else if utils.IsReservedNamespace(req.Namespace) {
160163
return validation.ValidateUserForResource(req, v.whiteListedUsers)
161164
}
162-
klog.V(3).InfoS("namespace name doesn't begin with fleet/kube prefix so we allow all operations on these namespaces",
165+
klog.V(3).InfoS(allowedMessageFleetReservedNamespacedResource,
163166
"user", req.UserInfo.Username, "groups", req.UserInfo.Groups, "operation", req.Operation, "kind", req.RequestKind.Kind, "subResource", req.SubResource, "namespacedName", types.NamespacedName{Name: req.Name, Namespace: req.Namespace})
164-
return admission.Allowed("namespace name doesn't begin with fleet/kube prefix so we allow all operations on these namespaces for the request object")
167+
return admission.Allowed(allowedMessageFleetReservedNamespacedResource)
165168
}
166169

167170
// handleEvent allows/denies request to modify event after validation.
@@ -172,13 +175,12 @@ func (v *fleetResourceValidator) handleEvent(_ context.Context, _ admission.Requ
172175

173176
// handlerNamespace allows/denies request to modify namespace after validation.
174177
func (v *fleetResourceValidator) handleNamespace(req admission.Request) admission.Response {
175-
fleetMatchResult := strings.HasPrefix(req.Name, fleetNamespacePrefix)
176-
kubeMatchResult := strings.HasPrefix(req.Name, kubeNamespacePrefix)
177-
if fleetMatchResult || kubeMatchResult {
178+
if utils.IsReservedNamespace(req.Name) {
178179
return validation.ValidateUserForResource(req, v.whiteListedUsers)
179180
}
180-
// only handling reserved namespaces with prefix fleet/kube.
181-
return admission.Allowed("namespace name doesn't begin with fleet/kube prefix so we allow all operations on these namespaces")
181+
klog.V(3).InfoS(allowedMessageNonReservedNamespace,
182+
"user", req.UserInfo.Username, "groups", req.UserInfo.Groups, "operation", req.Operation, "kind", req.RequestKind.Kind, "subResource", req.SubResource, "namespacedName", types.NamespacedName{Name: req.Name, Namespace: req.Namespace})
183+
return admission.Allowed(allowedMessageNonReservedNamespace)
182184
}
183185

184186
// decodeRequestObject decodes the request object into the passed runtime object.

pkg/webhook/fleetresourcehandler/fleetresourcehandler_webhook_test.go

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,26 @@ func TestHandleMemberCluster(t *testing.T) {
518518
resourceValidator fleetResourceValidator
519519
wantResponse admission.Response
520520
}{
521+
"allow create upstream fleet MC by any user": {
522+
req: admission.Request{
523+
AdmissionRequest: admissionv1.AdmissionRequest{
524+
Name: "test-mc",
525+
Object: runtime.RawExtension{
526+
Raw: mcObjectBytes,
527+
},
528+
UserInfo: authenticationv1.UserInfo{
529+
Username: "test-user",
530+
Groups: []string{"test-group"},
531+
},
532+
RequestKind: &utils.MCMetaGVK,
533+
Operation: admissionv1.Create,
534+
},
535+
},
536+
resourceValidator: fleetResourceValidator{
537+
decoder: decoder,
538+
},
539+
wantResponse: admission.Allowed(allowedMessageMemberCluster),
540+
},
521541
"deny update of fleet MC spec by non whitelisted user": {
522542
req: admission.Request{
523543
AdmissionRequest: admissionv1.AdmissionRequest{
@@ -681,7 +701,7 @@ func TestHandleFleetReservedNamespacedResource(t *testing.T) {
681701
Operation: admissionv1.Create,
682702
},
683703
},
684-
wantResponse: admission.Allowed("namespace name doesn't begin with fleet/kube prefix so we allow all operations on these namespaces for the request object"),
704+
wantResponse: admission.Allowed(allowedMessageFleetReservedNamespacedResource),
685705
},
686706
"allow hub-agent-sa in MC identity with create with v1alpha1 IMC": {
687707
req: admission.Request{
@@ -953,14 +973,47 @@ func TestHandleNamespace(t *testing.T) {
953973
resourceValidator fleetResourceValidator
954974
wantResponse admission.Response
955975
}{
956-
"allow user to modify non-reserved namespace": {
976+
"allow any user to modify non-reserved namespace": {
957977
req: admission.Request{
958978
AdmissionRequest: admissionv1.AdmissionRequest{
959-
Name: "test-namespace",
960-
Operation: admissionv1.Create,
979+
Name: "test-namespace",
980+
UserInfo: authenticationv1.UserInfo{
981+
Username: "testUser",
982+
Groups: []string{"testGroup"},
983+
},
984+
RequestKind: &utils.NamespaceMetaGVK,
985+
Operation: admissionv1.Create,
986+
},
987+
},
988+
wantResponse: admission.Allowed(allowedMessageNonReservedNamespace),
989+
},
990+
"allow any user to modify non-reserved namespace without fleet- prefix": {
991+
req: admission.Request{
992+
AdmissionRequest: admissionv1.AdmissionRequest{
993+
Name: "fleettest",
994+
UserInfo: authenticationv1.UserInfo{
995+
Username: "testUser",
996+
Groups: []string{"testGroup"},
997+
},
998+
RequestKind: &utils.NamespaceMetaGVK,
999+
Operation: admissionv1.Update,
1000+
},
1001+
},
1002+
wantResponse: admission.Allowed(allowedMessageNonReservedNamespace),
1003+
},
1004+
"allow any user to modify non-reserved namespace without kube- prefix": {
1005+
req: admission.Request{
1006+
AdmissionRequest: admissionv1.AdmissionRequest{
1007+
Name: "kubetest",
1008+
UserInfo: authenticationv1.UserInfo{
1009+
Username: "testUser",
1010+
Groups: []string{"testGroup"},
1011+
},
1012+
RequestKind: &utils.NamespaceMetaGVK,
1013+
Operation: admissionv1.Delete,
9611014
},
9621015
},
963-
wantResponse: admission.Allowed("namespace name doesn't begin with fleet/kube prefix so we allow all operations on these namespaces"),
1016+
wantResponse: admission.Allowed(allowedMessageNonReservedNamespace),
9641017
},
9651018
"deny user not in system:masters group to modify fleet namespace": {
9661019
req: admission.Request{

0 commit comments

Comments
 (0)