For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.
Using the untaint controller
Prevent pods from starting before Istio CNI is ready by using Kubernetes node taints managed by the Istio untaint controller.
When Kubernetes starts pods on a node before the istio-cni agent configures node networking, those pods do not have traffic redirection configured. The missing configuration creates a window where traffic is not controlled by Istio and can bypass any configured policy.
To avoid this race condition, use node taints. New pods cannot be scheduled until Istio’s untaint controller removes the taint.
Configure Istio
To enable the untaint controller, set pilot.taint.enabled=true when installing or upgrading the istiod Helm chart.
helm upgrade istiod istio/istiod -n istio-system \
--set pilot.taint.enabled=true \
--waitSome environments require istio-cni in a different namespace than istiod. If needed, specify the namespace to watch with the pilot.taint.namespace setting.
helm upgrade istiod istio/istiod -n istio-system \
--set pilot.taint.enabled=true \
--set pilot.taint.namespace=kube-system \
--waitCreate your nodes
Configure your node deployment, such as a node pool, auto-scaling group, or CI template, to add the cni.istio.io/not-ready startup taint to nodes when they are created. The following example uses a Karpenter NodePool.
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
template:
metadata:
labels:
billing-team: my-team
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
startupTaints:
- key: cni.istio.io/not-ready
effect: NoScheduleIn Google Kubernetes Engine, you can specify node taints with the --node-taints flag when you create the cluster or node pool.
The cni.istio.io/not-ready taint prevents pods from being scheduled onto the node unless they tolerate it. System add-ons, such as the istio-cni agent, are usually configured to tolerate all taints. When the istio-cni agent starts, the untaint controller removes the taint and pods can be scheduled.
Debug the untaint controller
You can use the following steps to verify that the untaint controller is running, or to diagnose issues with node taint removal.
-
Connect to the debug page on the istiod instance, as the untaint controller runs as part of istiod.
kubectl port-forward deployment/istiod -n istio-system 8080:8080 -
Navigate to http://localhost:8080/debug/krtz?pretty. The page shows whether the untaint controller is running and its current state. The
node-untaint/nodesfield shows the status of nodes, andnode-untaint/ready-cni-nodesshows the CNI agents that are ready. -
View the untaint controller logs at the default
infolevel.kubectl logs -f deployment/istiod -n istio-systemExample output:
2025-07-18T01:23:00.952072Z info krt node-untaint/nodes synced owner=node-untaint/nodes 2025-07-18T01:23:00.952085Z info krt node-untaint/pods synced owner=node-untaint/pods 2025-07-18T01:23:00.954215Z info krt node-untaint/cni-pods synced owner=node-untaint/cni-pods 2025-07-18T01:23:00.956745Z info controllers starting controller=untaint nodes 2025-07-18T01:23:00.956785Z info krt node-untaint/ready-cni-nodes synced owner=node-untaint/ready-cni-nodes -
To see events as nodes are created, set the untaint controller log level to
debug.istioctl admin log --level untaint:debug -
Add a taint to a node to confirm that the untaint controller detects and removes it.
kubectl taint nodes ambient-worker2 cni.istio.io/not-ready:NoScheduleExample output:
2025-07-18T01:35:11.698525Z debug untaint adding node to queue event: ambient-worker2 2025-07-18T01:35:11.698838Z debug untaint reconciling node ambient-worker2 2025-07-18T01:35:11.698855Z debug untaint removing readiness taint from node ambient-worker2 2025-07-18T01:35:11.705994Z debug untaint removed readiness taint from node ambient-worker2 -
Restore the log level to the default
infosetting.istioctl admin log --level untaint:info