Open-Source Wikis

/

Istio

/

Systems

/

Sidecar injection

istio/istio

Sidecar injection

Active contributors: hzxuzhonghu, ramaraochavali, zirain, keithmattix

Purpose

Sidecar injection is the mutating-admission-webhook flow that adds the istio-proxy container (and supporting init containers, volumes, and probes) to a Pod at admission time. It is how Istio gets Envoy into application pods without requiring users to modify their manifests.

The same library also drives istioctl kube-inject, the offline equivalent used for clusters where webhooks cannot be installed.

Directory layout

pkg/kube/inject/
├── inject.go         # Top-level inject logic; ~1000 lines
├── webhook.go        # The MutatingAdmission HTTP handler (~1500 lines)
├── template.go       # Template rendering (Go text/template + Sprig)
├── validate.go       # Validation of injection requests
├── watcher.go        # ConfigMap + revision watching
├── initializer.go    # Init-container choices (CNI vs istio-init)
├── app_probe.go      # Probe rewriting (k8s probe → agent-mediated)
├── openshift.go      # OpenShift SCC adjustments
└── monitoring.go

manifests/charts/istio-control/istio-discovery/files/
├── injection-template.yaml   # The template the webhook renders
└── ...

The actual istio-proxy template lives in the istio-discovery Helm chart at manifests/charts/istio-control/istio-discovery/files/injection-template.yaml. It is a Go text/template that produces the JSON patch the webhook returns.

Key abstractions

Symbol File Role
Webhook webhook.go The MutatingAdmission HTTP handler
WebhookConfig webhook.go Aggregated config: template, mesh config, valuesConfig, revisions
InjectionConfig inject.go Parsed inject configuration
InjectionParameters inject.go The struct passed to the template
Watcher watcher.go Watches the istio-sidecar-injector ConfigMap
applyAppProberRewrite app_probe.go Probe translation

How it works

sequenceDiagram
    participant API as kube-apiserver
    participant Webhook as Istiod MutatingWebhook
    participant Tpl as Template renderer
    participant Pod as Original Pod
    API->>Webhook: AdmissionReview (Pod create)
    Webhook->>Webhook: validate (annotation, namespace label, revision)
    Webhook->>Tpl: render with InjectionParameters
    Tpl->>Tpl: apply template w/ Sprig + custom funcs
    Tpl-->>Webhook: rendered Pod spec
    Webhook->>Webhook: diff vs original → JSON patch
    Webhook-->>API: AdmissionResponse(patch)
    API->>Pod: Pod created with istio-proxy + istio-init

Selection: who gets injected

Injection is gated by:

  1. The namespace label istio-injection=enabled (legacy default) or the per-namespace istio.io/rev=<revision> label (revision-based, the modern path).
  2. The pod-level sidecar.istio.io/inject annotation overrides namespace-level.
  3. Per-pod istio.io/rev overrides namespace-level revision.
  4. Pods that already have an istio-proxy container (already injected, e.g. by istioctl kube-inject) are skipped.
  5. Pods in the istio-system namespace are not injected.

The selection logic is in webhook.go's injectRequired. The companion command istioctl experimental check-inject pod/<name> walks the same logic offline so users can debug "why didn't this pod get injected".

Revisions and tags

Multiple istiods can run side-by-side, each labeled with a revision (istio.io/rev=<rev>). Each runs a webhook with a namespaceSelector matching that revision. Tags (istioctl tag) let users define stable aliases (default, prod, canary) that point to revisions; switching the tag re-routes new pods to the new control plane without changing namespace labels.

The webhook trees in manifests/charts/istio-control/istio-discovery/templates/mutatingwebhook.yaml define the revision-aware selectors.

Probe rewriting

app_probe.go rewrites Kubernetes-native HTTP/gRPC/TCP probes so they go through the istio-proxy health endpoint (15021) which the agent mediates. Without this, when iptables redirects all traffic, kubelet's probe traffic would be intercepted by Envoy and (for HTTP probes that lack mTLS) rejected.

The rewriter encodes the original probe parameters into agent-readable form via the KUBE_APP_PROBERS env var on the istio-proxy container. The agent (pilot-agent status) decodes that env at startup and translates kubelet's calls back into the original probe.

Init container choice

initializer.go decides what init container to add:

  • If istio-cni is detected (the namespace has the relevant label and the CNI plugin is installed), no init container is needed — CNI handles redirection.
  • Otherwise, an istio-init container with pilot-agent istio-iptables runs. This requires NET_ADMIN/NET_RAW capabilities and is therefore the less secure path.

The detection logic looks at the cluster's CNI install (istio-cni-config ConfigMap) and the namespace label k8s.v1.cni.cncf.io/networks.

Template

The template at manifests/charts/istio-control/istio-discovery/files/injection-template.yaml is what produces the actual Pod patch. It renders:

  • The istio-proxy container (Envoy + pilot-agent), with image, env, volume mounts, resource requests, security context.
  • The istio-init container (when needed).
  • The istio-token projected volume.
  • The istio-data emptyDir for SDS UDS.
  • The istio-podinfo downward API volume.
  • Per-pod annotations like prometheus.io/path for stats merging.

Users can override the template via the istio-sidecar-injector ConfigMap (the watcher in watcher.go picks this up live).

Validating webhook (separate)

The companion validating webhook lives in pkg/webhooks/validation/. It validates Istio CRs (VirtualService, DestinationRule, etc.) on admission so misconfigurations fail fast at apply time rather than producing broken Envoy configs.

Integration points

  • Reads from: the istio-sidecar-injector ConfigMap (template, defaults, neverInjectSelector, etc.); the istio ConfigMap (mesh config); namespace and pod labels at admission time.
  • Writes to: HTTP admission response only; never modifies the cluster directly.
  • Cluster resources: MutatingWebhookConfiguration per revision. The CA bundle in the webhook config is patched by pkg/webhooks/webhookpatch.go so istiod's own CA can sign it.

Entry points for modification

  • New container/volume → edit manifests/charts/istio-control/istio-discovery/files/injection-template.yaml. Goldens live in pkg/kube/inject/testdata/. Regenerate with make refresh-goldens.
  • New annotation → add a known annotation in pkg/config/annotation/ (the schema), then handle it in inject.go or the template.
  • New init-container choice → initializer.go.
  • Probe handling change → app_probe.go plus the agent-side decoder in pilot/cmd/pilot-agent/status/.

Key source files

File Purpose
pkg/kube/inject/webhook.go The HTTP webhook handler
pkg/kube/inject/inject.go The inject library; entry point for istioctl kube-inject
pkg/kube/inject/template.go Template rendering helpers
pkg/kube/inject/app_probe.go Probe rewriter
pkg/kube/inject/watcher.go ConfigMap watcher
pkg/kube/inject/initializer.go Init-container choice
manifests/charts/istio-control/istio-discovery/files/injection-template.yaml The template itself
manifests/charts/istio-control/istio-discovery/templates/mutatingwebhook.yaml The webhook config
pkg/webhooks/validation/server/server.go The companion validating webhook
pkg/webhooks/webhookpatch.go Webhook caBundle patcher

See also

  • istiod — where the webhook is hosted.
  • istio-cni — the alternative to istio-init.
  • istioctlkube-inject and experimental check-inject.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Sidecar injection – Istio wiki | Factory