istio/istio · critical

KUBERNETES_SERVICE_HOST not set. Is this not running within

Error message

KUBERNETES_SERVICE_HOST not set. Is this not running within a pod?

What it means

istio-cni-node builds its kubeconfig from in-pod environment variables and found KUBERNETES_SERVICE_HOST empty. In Kubernetes, the kubelet always injects KUBERNETES_SERVICE_HOST/PORT into pods; the error text asks whether the process is running outside a pod. The value comes from cfg.K8sServiceHost, populated from the env var.

Source

Thrown at cni/pkg/install/kubeconfig.go:42

	"k8s.io/client-go/tools/clientcmd/api/latest"
	"sigs.k8s.io/yaml"

	"istio.io/istio/cni/pkg/config"
	"istio.io/istio/cni/pkg/constants"
	"istio.io/istio/pilot/pkg/model"
	"istio.io/istio/pkg/file"
)

type kubeconfig struct {
	// The full kubeconfig
	Full string
	// Kubeconfig with confidential data redacted.
	Redacted string
}

func createKubeConfig(cfg *config.InstallConfig) (kubeconfig, error) {
	if len(cfg.K8sServiceHost) == 0 {
		return kubeconfig{}, fmt.Errorf("KUBERNETES_SERVICE_HOST not set. Is this not running within a pod?")
	}

	if len(cfg.K8sServicePort) == 0 {
		return kubeconfig{}, fmt.Errorf("KUBERNETES_SERVICE_PORT not set. Is this not running within a pod?")
	}

	protocol := model.GetOrDefault(cfg.K8sServiceProtocol, "https")
	cluster := &api.Cluster{
		Server: fmt.Sprintf("%s://%s", protocol, net.JoinHostPort(cfg.K8sServiceHost, cfg.K8sServicePort)),
	}

	if cfg.SkipTLSVerify {
		// User explicitly opted into insecure.
		cluster.InsecureSkipTLSVerify = true
	} else {
		caFile := model.GetOrDefault(cfg.KubeCAFile, cfg.K8sServiceAccountPath+"/ca.crt")
		caContents, err := os.ReadFile(caFile)
		if err != nil {

View on GitHub (pinned to 8dc789c5cf)

Solutions

  1. If running in Kubernetes, check the pod spec was not modified to remove the service env vars and recreate the pod.
  2. If running outside a pod (debug/test), set KUBERNETES_SERVICE_HOST explicitly, e.g. KUBERNETES_SERVICE_HOST=<api-server-ip> ./install-cni.
  3. Set the host via the pod spec env block with an explicit value if the default link is missing (unusual setups with disabled service links).
  4. Verify with: kubectl -n istio-system exec istio-cni-node-xxxx -- env | grep KUBERNETES_SERVICE.

Example fix

# before
$ ./install-cni   # fails: KUBERNETES_SERVICE_HOST not set
# after (manual run)
$ KUBERNETES_SERVICE_HOST=10.96.0.1 KUBERNETES_SERVICE_PORT=443 ./install-cni
Defensive patterns

Strategy: validation

Validate before calling

# Verify before deploying the pod spec / running manually.
kubectl -n istio-system exec ds/istio-cni-node -- sh -c 'test -n "$KUBERNETES_SERVICE_HOST" && echo ok || echo missing'

Prevention

When it happens

Trigger: createKubeConfig is called during install and cfg.K8sServiceHost is empty — i.e. KUBERNETES_SERVICE_HOST was not in the environment. Typical when running the install binary manually on a node, in docker without pod env, or when the env var is explicitly unset/emptied in the pod spec.

Common situations: Debugging the CNI binary by exec'ing it in a plain docker container; a mutated istio-cni-node pod spec that clears env vars; running install tests outside a pod without setting the variable explicitly; security scanners that strip service env vars.

Related errors


AI-assisted analysis of istio/istio@8dc789c5cf (2026-08-15). Data as JSON: /api/errors/f4540f9ed4465da2. Report an issue: GitHub.