Skip to content

Commit 16e3557

Browse files
committed
Improve node authorizer and noderestriction forbidden messages
1 parent 7098f1a commit 16e3557

File tree

3 files changed

+28
-28
lines changed

3 files changed

+28
-28
lines changed

plugin/pkg/admission/noderestriction/admission.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ func (c *nodePlugin) Admit(a admission.Attributes) error {
124124
case "eviction":
125125
return c.admitPodEviction(nodeName, a)
126126
default:
127-
return admission.NewForbidden(a, fmt.Errorf("unexpected pod subresource %q", a.GetSubresource()))
127+
return admission.NewForbidden(a, fmt.Errorf("unexpected pod subresource %q, only 'status' and 'eviction' are allowed", a.GetSubresource()))
128128
}
129129

130130
case nodeResource:
@@ -218,7 +218,7 @@ func (c *nodePlugin) admitPod(nodeName string, a admission.Attributes) error {
218218
return nil
219219

220220
default:
221-
return admission.NewForbidden(a, fmt.Errorf("unexpected operation %q", a.GetOperation()))
221+
return admission.NewForbidden(a, fmt.Errorf("unexpected operation %q, node %q can only create and delete mirror pods", a.GetOperation(), nodeName))
222222
}
223223
}
224224

@@ -280,7 +280,7 @@ func (c *nodePlugin) admitPVCStatus(nodeName string, a admission.Attributes) err
280280
switch a.GetOperation() {
281281
case admission.Update:
282282
if !c.features.Enabled(features.ExpandPersistentVolumes) {
283-
return admission.NewForbidden(a, fmt.Errorf("node %q may not update persistentvolumeclaim metadata", nodeName))
283+
return admission.NewForbidden(a, fmt.Errorf("node %q is not allowed to update persistentvolumeclaim metadata", nodeName))
284284
}
285285

286286
oldPVC, ok := a.GetOldObject().(*api.PersistentVolumeClaim)
@@ -310,7 +310,7 @@ func (c *nodePlugin) admitPVCStatus(nodeName string, a admission.Attributes) err
310310

311311
// ensure no metadata changed. nodes should not be able to relabel, add finalizers/owners, etc
312312
if !apiequality.Semantic.DeepEqual(oldPVC, newPVC) {
313-
return admission.NewForbidden(a, fmt.Errorf("node %q may not update fields other than status.capacity and status.conditions: %v", nodeName, diff.ObjectReflectDiff(oldPVC, newPVC)))
313+
return admission.NewForbidden(a, fmt.Errorf("node %q is not allowed to update fields other than status.capacity and status.conditions: %v", nodeName, diff.ObjectReflectDiff(oldPVC, newPVC)))
314314
}
315315

316316
return nil
@@ -331,14 +331,14 @@ func (c *nodePlugin) admitNode(nodeName string, a admission.Attributes) error {
331331
// Don't allow a node to create its Node API object with the config source set.
332332
// We scope node access to things listed in the Node.Spec, so allowing this would allow a view escalation.
333333
if node.Spec.ConfigSource != nil {
334-
return admission.NewForbidden(a, fmt.Errorf("cannot create with non-nil configSource"))
334+
return admission.NewForbidden(a, fmt.Errorf("node %q is not allowed to create pods with a non-nil configSource", nodeName))
335335
}
336336

337337
// Don't allow a node to register with labels outside the allowed set.
338338
// This would allow a node to add or modify its labels in a way that would let it steer privileged workloads to itself.
339339
modifiedLabels := getModifiedLabels(node.Labels, nil)
340340
if forbiddenLabels := c.getForbiddenCreateLabels(modifiedLabels); len(forbiddenLabels) > 0 {
341-
return admission.NewForbidden(a, fmt.Errorf("cannot set labels: %s", strings.Join(forbiddenLabels.List(), ", ")))
341+
return admission.NewForbidden(a, fmt.Errorf("node %q is not allowed to set the following labels: %s", nodeName, strings.Join(forbiddenLabels.List(), ", ")))
342342
}
343343
// check and warn if nodes set labels on create that would have been forbidden on update
344344
// TODO(liggitt): in 1.17, expand getForbiddenCreateLabels to match getForbiddenUpdateLabels and drop this
@@ -352,7 +352,7 @@ func (c *nodePlugin) admitNode(nodeName string, a admission.Attributes) error {
352352
}
353353
}
354354
if requestedName != nodeName {
355-
return admission.NewForbidden(a, fmt.Errorf("node %q cannot modify node %q", nodeName, requestedName))
355+
return admission.NewForbidden(a, fmt.Errorf("node %q is not allowed to modify node %q", nodeName, requestedName))
356356
}
357357

358358
if a.GetOperation() == admission.Update {
@@ -369,20 +369,20 @@ func (c *nodePlugin) admitNode(nodeName string, a admission.Attributes) error {
369369
// We scope node access to things listed in the Node.Spec, so allowing this would allow a view escalation.
370370
// We only do the check if the new node's configSource is non-nil; old kubelets might drop the field during a status update.
371371
if node.Spec.ConfigSource != nil && !apiequality.Semantic.DeepEqual(node.Spec.ConfigSource, oldNode.Spec.ConfigSource) {
372-
return admission.NewForbidden(a, fmt.Errorf("node %q cannot update configSource to a new non-nil configSource", nodeName))
372+
return admission.NewForbidden(a, fmt.Errorf("node %q is not allowed to update configSource to a new non-nil configSource", nodeName))
373373
}
374374

375375
// Don't allow a node to update its own taints. This would allow a node to remove or modify its
376376
// taints in a way that would let it steer disallowed workloads to itself.
377377
if !apiequality.Semantic.DeepEqual(node.Spec.Taints, oldNode.Spec.Taints) {
378-
return admission.NewForbidden(a, fmt.Errorf("node %q cannot modify taints", nodeName))
378+
return admission.NewForbidden(a, fmt.Errorf("node %q is not allowed to modify taints", nodeName))
379379
}
380380

381381
// Don't allow a node to update labels outside the allowed set.
382382
// This would allow a node to add or modify its labels in a way that would let it steer privileged workloads to itself.
383383
modifiedLabels := getModifiedLabels(node.Labels, oldNode.Labels)
384384
if forbiddenUpdateLabels := c.getForbiddenUpdateLabels(modifiedLabels); len(forbiddenUpdateLabels) > 0 {
385-
return admission.NewForbidden(a, fmt.Errorf("cannot modify labels: %s", strings.Join(forbiddenUpdateLabels.List(), ", ")))
385+
return admission.NewForbidden(a, fmt.Errorf("is not allowed to modify labels: %s", strings.Join(forbiddenUpdateLabels.List(), ", ")))
386386
}
387387
}
388388

plugin/pkg/admission/noderestriction/admission_test.go

+13-13
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,7 @@ func Test_nodePlugin_Admit(t *testing.T) {
868868
name: "forbid create of my node with forbidden labels",
869869
podsGetter: noExistingPods,
870870
attributes: admission.NewAttributesRecord(setForbiddenCreateLabels(mynodeObj, ""), nil, nodeKind, mynodeObj.Namespace, "", nodeResource, "", admission.Create, false, mynode),
871-
err: `cannot set labels: foo.node-restriction.kubernetes.io/foo, node-restriction.kubernetes.io/foo`,
871+
err: `is not allowed to set the following labels: foo.node-restriction.kubernetes.io/foo, node-restriction.kubernetes.io/foo`,
872872
},
873873
{
874874
name: "allow update of my node",
@@ -892,7 +892,7 @@ func Test_nodePlugin_Admit(t *testing.T) {
892892
name: "forbid create of my node with non-nil configSource",
893893
podsGetter: noExistingPods,
894894
attributes: admission.NewAttributesRecord(mynodeObjConfigA, nil, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Create, false, mynode),
895-
err: "create with non-nil configSource",
895+
err: "is not allowed to create pods with a non-nil configSource",
896896
},
897897
{
898898
name: "forbid update of my node: nil configSource to new non-nil configSource",
@@ -964,69 +964,69 @@ func Test_nodePlugin_Admit(t *testing.T) {
964964
name: "forbid update of my node: add taints",
965965
podsGetter: existingPods,
966966
attributes: admission.NewAttributesRecord(mynodeObjTaintA, mynodeObj, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode),
967-
err: "cannot modify taints",
967+
err: "is not allowed to modify taints",
968968
},
969969
{
970970
name: "forbid update of my node: remove taints",
971971
podsGetter: existingPods,
972972
attributes: admission.NewAttributesRecord(mynodeObj, mynodeObjTaintA, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode),
973-
err: "cannot modify taints",
973+
err: "is not allowed to modify taints",
974974
},
975975
{
976976
name: "forbid update of my node: change taints",
977977
podsGetter: existingPods,
978978
attributes: admission.NewAttributesRecord(mynodeObjTaintA, mynodeObjTaintB, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode),
979-
err: "cannot modify taints",
979+
err: "is not allowed to modify taints",
980980
},
981981
{
982982
name: "forbid update of my node: add labels",
983983
podsGetter: existingPods,
984984
attributes: admission.NewAttributesRecord(setForbiddenUpdateLabels(mynodeObj, ""), mynodeObj, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode),
985-
err: `cannot modify labels: foo.node-restriction.kubernetes.io/foo, node-restriction.kubernetes.io/foo, other.k8s.io/foo, other.kubernetes.io/foo`,
985+
err: `is not allowed to modify labels: foo.node-restriction.kubernetes.io/foo, node-restriction.kubernetes.io/foo, other.k8s.io/foo, other.kubernetes.io/foo`,
986986
},
987987
{
988988
name: "forbid update of my node: remove labels",
989989
podsGetter: existingPods,
990990
attributes: admission.NewAttributesRecord(mynodeObj, setForbiddenUpdateLabels(mynodeObj, ""), nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode),
991-
err: `cannot modify labels: foo.node-restriction.kubernetes.io/foo, node-restriction.kubernetes.io/foo, other.k8s.io/foo, other.kubernetes.io/foo`,
991+
err: `is not allowed to modify labels: foo.node-restriction.kubernetes.io/foo, node-restriction.kubernetes.io/foo, other.k8s.io/foo, other.kubernetes.io/foo`,
992992
},
993993
{
994994
name: "forbid update of my node: change labels",
995995
podsGetter: existingPods,
996996
attributes: admission.NewAttributesRecord(setForbiddenUpdateLabels(mynodeObj, "new"), setForbiddenUpdateLabels(mynodeObj, "old"), nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, false, mynode),
997-
err: `cannot modify labels: foo.node-restriction.kubernetes.io/foo, node-restriction.kubernetes.io/foo, other.k8s.io/foo, other.kubernetes.io/foo`,
997+
err: `is not allowed to modify labels: foo.node-restriction.kubernetes.io/foo, node-restriction.kubernetes.io/foo, other.k8s.io/foo, other.kubernetes.io/foo`,
998998
},
999999

10001000
// Other node object
10011001
{
10021002
name: "forbid create of other node",
10031003
podsGetter: noExistingPods,
10041004
attributes: admission.NewAttributesRecord(othernodeObj, nil, nodeKind, othernodeObj.Namespace, othernodeObj.Name, nodeResource, "", admission.Create, false, mynode),
1005-
err: "cannot modify node",
1005+
err: "is not allowed to modify node",
10061006
},
10071007
{
10081008
name: "forbid create of other node pulling name from object",
10091009
podsGetter: noExistingPods,
10101010
attributes: admission.NewAttributesRecord(othernodeObj, nil, nodeKind, othernodeObj.Namespace, "", nodeResource, "", admission.Create, false, mynode),
1011-
err: "cannot modify node",
1011+
err: "is not allowed to modify node",
10121012
},
10131013
{
10141014
name: "forbid update of other node",
10151015
podsGetter: existingPods,
10161016
attributes: admission.NewAttributesRecord(othernodeObj, othernodeObj, nodeKind, othernodeObj.Namespace, othernodeObj.Name, nodeResource, "", admission.Update, false, mynode),
1017-
err: "cannot modify node",
1017+
err: "is not allowed to modify node",
10181018
},
10191019
{
10201020
name: "forbid delete of other node",
10211021
podsGetter: existingPods,
10221022
attributes: admission.NewAttributesRecord(nil, nil, nodeKind, othernodeObj.Namespace, othernodeObj.Name, nodeResource, "", admission.Delete, false, mynode),
1023-
err: "cannot modify node",
1023+
err: "is not allowed to modify node",
10241024
},
10251025
{
10261026
name: "forbid update of other node status",
10271027
podsGetter: existingPods,
10281028
attributes: admission.NewAttributesRecord(othernodeObj, othernodeObj, nodeKind, othernodeObj.Namespace, othernodeObj.Name, nodeResource, "status", admission.Update, false, mynode),
1029-
err: "cannot modify node",
1029+
err: "is not allowed to modify node",
10301030
},
10311031

10321032
// Service accounts

plugin/pkg/auth/authorizer/node/node_authorizer.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,11 @@ func (r *NodeAuthorizer) authorize(nodeName string, startingType vertexType, att
196196
ok, err := r.hasPathFrom(nodeName, startingType, attrs.GetNamespace(), attrs.GetName())
197197
if err != nil {
198198
klog.V(2).Infof("NODE DENY: %v", err)
199-
return authorizer.DecisionNoOpinion, "no path found to object", nil
199+
return authorizer.DecisionNoOpinion, fmt.Sprintf("no relationship found between node %q and this object", nodeName), nil
200200
}
201201
if !ok {
202202
klog.V(2).Infof("NODE DENY: %q %#v", nodeName, attrs)
203-
return authorizer.DecisionNoOpinion, "no path found to object", nil
203+
return authorizer.DecisionNoOpinion, fmt.Sprintf("no relationship found between node %q and this object", nodeName), nil
204204
}
205205
return authorizer.DecisionAllow, "", nil
206206
}
@@ -221,11 +221,11 @@ func (r *NodeAuthorizer) authorizeCreateToken(nodeName string, startingType vert
221221
ok, err := r.hasPathFrom(nodeName, startingType, attrs.GetNamespace(), attrs.GetName())
222222
if err != nil {
223223
klog.V(2).Infof("NODE DENY: %v", err)
224-
return authorizer.DecisionNoOpinion, "no path found to object", nil
224+
return authorizer.DecisionNoOpinion, fmt.Sprintf("no relationship found between node %q and this object", nodeName), nil
225225
}
226226
if !ok {
227227
klog.V(2).Infof("NODE DENY: %q %#v", nodeName, attrs)
228-
return authorizer.DecisionNoOpinion, "no path found to object", nil
228+
return authorizer.DecisionNoOpinion, fmt.Sprintf("no relationship found between node %q and this object", nodeName), nil
229229
}
230230
return authorizer.DecisionAllow, "", nil
231231
}
@@ -333,7 +333,7 @@ func (r *NodeAuthorizer) hasPathFrom(nodeName string, startingType vertexType, s
333333
return found
334334
})
335335
if !found {
336-
return false, fmt.Errorf("node %q cannot get %s %s/%s, no path was found", nodeName, vertexTypes[startingType], startingNamespace, startingName)
336+
return false, fmt.Errorf("node %q cannot get %s %s/%s, no relationship to this object was found in the node authorizer graph", nodeName, vertexTypes[startingType], startingNamespace, startingName)
337337
}
338338
return true, nil
339339
}

0 commit comments

Comments
 (0)