Secure Status Reporting
By default, a readiness reporter’s ServiceAccount is granted broad permissions to update the status of any Node in the cluster. If a node is compromised, an attacker can manipulate the readiness status of every other node.
Constrained Impersonation (KEP-5284) solves this by allowing the reporter to impersonate only the Node it runs on. The API server enforces this at the authorization layer, so that no other node’s status can be touched.
This guide walks through a CNI readiness example that uses constrained impersonation instead of broad RBAC. It is a hardened variant of the CNI Readiness example.
Prerequisites: Kubernetes v1.35+ with the
ConstrainedImpersonationfeature gate enabled, or v1.36+ where it is Beta and enabled by default.
Note: You can find all the manifests used in this guide in the
examples/constrained-impersonationdirectory.
Step-by-Step Guide
1. Create a Kind Cluster
Create a cluster with the ConstrainedImpersonation feature gate enabled and worker nodes that join with a startup taint:
kind create cluster \
--config config/testing/kind/kind-constrained-impersonation-config.yaml \
--image kindest/node:v1.35.0
2. Install the CRDs and Controller
make install
make deploy
3. Deploy the Example
cd examples/constrained-impersonation
kubectl apply -f .
4. RBAC Explained
The RBAC consists of two ClusterRoles:
Impersonation role — allows the reporter to impersonate its own Node:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-readiness-impersonator
rules:
- apiGroups: ["authentication.k8s.io"]
resources: ["nodes"]
verbs: ["impersonate:associated-node"]
Constrained action role — restricts what the impersonated identity can do:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-status-patcher-constrained
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["impersonate-on:associated-node:get"]
- apiGroups: [""]
resources: ["nodes/status"]
verbs: ["impersonate-on:associated-node:update"]
5. Verification
Check that the reporter is running:
kubectl -n kube-system get pods -l app=cni-reporter
Check node conditions:
kubectl get nodes -o custom-columns='NAME:.metadata.name,CALICO_READY:.status.conditions[?(@.type=="projectcalico.org/CalicoReady")].status'
6. Security Verification
Verify the ServiceAccount has no direct permissions:
kubectl auth can-i get nodes --as=system:serviceaccount:kube-system:cni-reporter
# no
kubectl auth can-i update nodes/status --as=system:serviceaccount:kube-system:cni-reporter
# no
The SA cannot read or update any node directly; all access goes through constrained impersonation.
Verify the reporter can still update its own node (via impersonation):
kubectl get nodes -o custom-columns='NAME:.metadata.name,CALICO_READY:.status.conditions[?(@.type=="projectcalico.org/CalicoReady")].status'
The CalicoReady condition should appear on every node.
This proves the reporter is successfully impersonating its local node identity and writing status.
Comparison with Broad RBAC
For a deeper discussion, see Security.