Skip to content

Commit 687e545

Browse files
authored
Merge pull request kubernetes-retired#51 from RealHarshThakur/webhook-tree-labels
Deny requests adding tree labels
2 parents a4fe5ce + 04df75b commit 687e545

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

internal/namespace/validator.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package namespaces
33
import (
44
"context"
55
"fmt"
6+
"strings"
67

78
"github.com/go-logr/logr"
89
k8sadm "k8s.io/api/admission/v1"
@@ -86,6 +87,11 @@ func (v *Validator) handle(req *nsRequest) admission.Response {
8687
if rsp := v.nameExistsInExternalHierarchy(req); !rsp.Allowed {
8788
return rsp
8889
}
90+
91+
if rsp := v.illegalTreeLabel(req); !rsp.Allowed {
92+
return rsp
93+
}
94+
8995
case k8sadm.Update:
9096
if rsp := v.illegalIncludedNamespaceLabel(req); !rsp.Allowed {
9197
return rsp
@@ -96,6 +102,11 @@ func (v *Validator) handle(req *nsRequest) admission.Response {
96102
if rsp := v.conflictBetweenParentAndExternalManager(req, ns); !rsp.Allowed {
97103
return rsp
98104
}
105+
106+
if rsp := v.illegalTreeLabel(req); !rsp.Allowed {
107+
return rsp
108+
}
109+
99110
case k8sadm.Delete:
100111
if rsp := v.cannotDeleteSubnamespace(req); !rsp.Allowed {
101112
return rsp
@@ -108,6 +119,40 @@ func (v *Validator) handle(req *nsRequest) admission.Response {
108119
return webhooks.Allow("")
109120
}
110121

122+
// illegalTreeLabel checks if tree labels are being created or modified
123+
// by any user or service account since only HNC service account is
124+
// allowed to do so
125+
func (v *Validator) illegalTreeLabel(req *nsRequest) admission.Response {
126+
msg := "Cannot set or modify tree label %q in namespace %q; these can only be modified by HNC."
127+
128+
oldLabels := map[string]string{}
129+
if req.oldns != nil {
130+
oldLabels = req.oldns.Labels
131+
}
132+
// Ensure the users hasn't added or changed any tree labels
133+
for key, val := range req.ns.Labels {
134+
if !strings.Contains(key, api.LabelTreeDepthSuffix) {
135+
continue
136+
}
137+
138+
// Check if new HNC label tree key isn't being added
139+
if oldLabels[key] != val {
140+
return webhooks.Deny(metav1.StatusReasonForbidden, fmt.Sprintf(msg, key, req.ns.Name))
141+
}
142+
}
143+
144+
for key := range oldLabels {
145+
// Make sure nothing's been deleted
146+
if strings.Contains(key, api.LabelTreeDepthSuffix) {
147+
if _, ok := req.ns.Labels[key]; !ok {
148+
return webhooks.Deny(metav1.StatusReasonForbidden, fmt.Sprintf(msg, key, req.ns.Name))
149+
}
150+
}
151+
}
152+
153+
return webhooks.Allow("")
154+
}
155+
111156
// illegalIncludedNamespaceLabel checks if there's any illegal use of the
112157
// included-namespace label on namespaces. It only checks a Create or an Update
113158
// request.

internal/namespace/validator_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,3 +339,50 @@ func TestIllegalIncludedNamespaceNamespace(t *testing.T) {
339339
func logResult(t *testing.T, result *metav1.Status) {
340340
t.Logf("Got reason %q, code %d, msg %q", result.Reason, result.Code, result.Message)
341341
}
342+
func TestIllegalTreeOperations(t *testing.T) {
343+
f := foresttest.Create("-")
344+
vns := &Validator{Forest: f}
345+
346+
ns := &corev1.Namespace{}
347+
oldNs := &corev1.Namespace{}
348+
ns.Name = "a"
349+
350+
ns.SetLabels(map[string]string{api.LabelTreeDepthSuffix: "1"})
351+
// Change tree label value
352+
oldNs.SetLabels(map[string]string{api.LabelTreeDepthSuffix: "2"})
353+
354+
tests := []struct {
355+
name string
356+
op k8sadm.Operation
357+
allowed bool
358+
oldNs *corev1.Namespace
359+
}{
360+
{name: "Creation of namespace with tree label in it", op: k8sadm.Create, allowed: false},
361+
{name: "Update namespace with tree label in it", op: k8sadm.Update, allowed: false},
362+
{name: "Update value of a tree in existing namespace", op: k8sadm.Update, allowed: false, oldNs: oldNs},
363+
{name: "No tree label updates to namespace", op: k8sadm.Update, allowed: true, oldNs: ns},
364+
}
365+
for _, tc := range tests {
366+
g := NewWithT(t)
367+
368+
var req *nsRequest
369+
if tc.op == k8sadm.Create {
370+
req = &nsRequest{
371+
ns: ns,
372+
op: tc.op,
373+
}
374+
} else {
375+
req = &nsRequest{
376+
ns: ns,
377+
op: tc.op,
378+
oldns: tc.oldNs,
379+
}
380+
}
381+
382+
got := vns.illegalTreeLabel(req)
383+
384+
logResult(t, got.AdmissionResponse.Result)
385+
g.Expect(got.AdmissionResponse.Allowed).Should(Equal(tc.allowed))
386+
}
387+
388+
}

0 commit comments

Comments
 (0)