← Policy catalog
</> ValidatingAdmissionPolicy · Apache-2.0

Lacks a Control Plane NoSchedule Taint

node-control-plane-schedulable

severityModerate resourceNodes productKubernetes bundles1

An untainted control-plane node accepts ordinary workloads alongside etcd and the API server, putting tenant containers on the one host where control-plane certificates and static pod manifests sit on disk.

Rejects unless

!variables.controlPlaneLabel || (
  has(object.spec.taints) &&
  object.spec.taints.exists(t,
    (t.key in ["node-role.kubernetes.io/control-plane","node-role.kubernetes.io/master"]) &&
    (t.effect == "NoSchedule" || t.effect == "NoExecute")
  )
)

Control-plane nodes must carry a NoSchedule/NoExecute taint to prevent workload scheduling.

Variables

controlPlaneLabel

has(object.metadata.labels) &&
(
  "node-role.kubernetes.io/control-plane" in object.metadata.labels ||
  "node-role.kubernetes.io/master" in object.metadata.labels
)

Remediation

Add a taint with key node-role.kubernetes.io/control-plane (or node-role.kubernetes.io/master) and effect NoSchedule or NoExecute to the node. Field: spec.taints.

Applies to

  • nodes · v1 · CREATE, UPDATE

Manifest

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: node-control-plane-schedulable
  annotations:
    kubeapt.io/uuid: "b0cfc6a8-e466-4436-b2a8-a7d94fbab61a"
    security.kubeapt.io/displayName: "Lacks a Control Plane NoSchedule Taint"
    security.kubeapt.io/description: "An untainted control-plane node accepts ordinary workloads alongside etcd and the API server, putting tenant containers on the one host where control-plane certificates and static pod manifests sit on disk."
    security.kubeapt.io/resource: "Nodes"
    security.kubeapt.io/severity: "Moderate"
    security.kubeapt.io/remediation: "Add a taint with key node-role.kubernetes.io/control-plane (or node-role.kubernetes.io/master) and effect NoSchedule or NoExecute to the node. Field: spec.taints."
    security.kubeapt.io/product: "Kubernetes"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:
      - ''
      apiVersions:
      - v1
      operations:
      - CREATE
      - UPDATE
      resources:
      - nodes
  variables:
  - name: controlPlaneLabel
    expression: |
      has(object.metadata.labels) &&
      (
        "node-role.kubernetes.io/control-plane" in object.metadata.labels ||
        "node-role.kubernetes.io/master" in object.metadata.labels
      )
  validations:
  - expression: |
      !variables.controlPlaneLabel || (
        has(object.spec.taints) &&
        object.spec.taints.exists(t,
          (t.key in ["node-role.kubernetes.io/control-plane","node-role.kubernetes.io/master"]) &&
          (t.effect == "NoSchedule" || t.effect == "NoExecute")
        )
      )
    message: |
      Control-plane nodes must carry a NoSchedule/NoExecute taint to prevent workload scheduling.

Save it as node-control-plane-schedulable.yaml — the commands below assume that name.

Validate with kubeapt

Check a workload against this one policy, before anything is installed on a cluster.

$ kubeapt validate -p ./node-control-plane-schedulable.yaml -r ./workload.yaml

Or without the file, from the published policy set — -r takes a directory too:

$ kubeapt policies download && kubeapt validate --policy-name node-control-plane-schedulable -r ./manifests

Or against every namespace in the cluster your kubeconfig points at:

$ kubeapt validate --policy-name node-control-plane-schedulable -A