Skip to content

Istio Explanation

What this page covers

How Istio works and why it is built this way: the istiod control plane, the two data plane modes (Envoy sidecars and ambient mode with ztunnel and waypoints), the Istio CNI node agent, HBONE, xDS distribution, SPIFFE identity, the revision-based upgrade model, Gateway API adoption, and the security model. Version-specific statements refer to Istio 1.31 (latest patch 1.31.1, 2026-09-21) unless noted. Look-up tables (ports, versions, labels, benchmark figures) live in Reference; step-by-step tasks live in How-to Guides.

Overview

Istio is a service mesh that provides traffic management, security, and observability for microservices. It supports two data plane modes: the traditional sidecar model, where an Envoy proxy runs next to every application container, and ambient mode, where a per-node L4 proxy (ztunnel) secures all traffic and optional Envoy-based waypoint proxies add L7 features. Both modes can coexist in one mesh. The control plane is a single binary called istiod, which merged the formerly separate Pilot, Citadel, and Galley components in Istio 1.5 (2020).

See also: Istio hub, Reference, How-to Guides

Architecture at a Glance

The diagram shows istiod programming both data plane modes; the Istio CNI node agent is required for ambient and optional for sidecars.

flowchart TB
    subgraph CP["Control plane (istio-system)"]
        ISTIOD["istiod<br/>xDS server + CA + webhooks"]
    end

    subgraph K8S["Kubernetes API"]
        CRDS["Istio CRDs + Gateway API<br/>Service, EndpointSlice, Pod"]
    end

    subgraph SIDE["Sidecar mode"]
        APP1["app container"] --- ENVOY1["istio-proxy<br/>(Envoy + pilot-agent)"]
    end

    subgraph AMB["Ambient mode"]
        CNI["istio-cni node agent<br/>(DaemonSet)"]
        ZT["ztunnel<br/>(DaemonSet, Rust, L4)"]
        WP["waypoint<br/>(Envoy Deployment, L7)"]
        APP2["ambient pod"]
    end

    GW["Ingress gateway<br/>(Envoy, Gateway API)"]

    CRDS -->|"watch"| ISTIOD
    ISTIOD -->|"LDS/RDS/CDS/EDS + certs"| ENVOY1
    ISTIOD -->|"LDS/RDS/CDS/EDS"| WP
    ISTIOD -->|"LDS/RDS/CDS/EDS"| GW
    ISTIOD -->|"WDS + authz + certs"| ZT
    CNI -->|"netns fd over UDS"| ZT
    CNI -.->|"in-pod iptables/nftables"| APP2
    ZT -->|"HBONE :15008"| WP

1. Control Plane -- Istiod

Istiod is one Deployment that watches the Kubernetes API, translates configuration into proxy config, signs workload certificates, and serves the injection and validation webhooks.

graph TB
    subgraph ISTIOD_BOX["istiod (single binary)"]
        PILOT["Pilot subsystem<br/>Traffic management and xDS"]
        CITADEL["Citadel subsystem<br/>Certificate authority"]
        GALLEY["Galley functions<br/>Config validation webhook"]
    end

    subgraph INPUT["Configuration input"]
        K8s["Kubernetes API Server"]
        K8sCRDs["Istio CRDs and Gateway API<br/>(VirtualService, DestinationRule, HTTPRoute,<br/>AuthorizationPolicy, PeerAuthentication)"]
    end

    K8s -->|watches| PILOT
    K8sCRDs -->|watches| PILOT
    K8sCRDs -->|"validates on admission"| GALLEY
    PILOT -->|xDS gRPC| SIDECARS
    PILOT -->|"xDS gRPC (WDS)"| ZTUNNEL
    CITADEL -->|SPIFFE certs| SIDECARS
    CITADEL -->|SPIFFE certs| ZTUNNEL

    subgraph DP_SIDE["Data plane (sidecar mode)"]
        SIDECARS["Envoy sidecar proxies"]
    end

    subgraph DP_AMB["Data plane (ambient mode)"]
        ZTUNNEL["ztunnel<br/>(node-level DaemonSet)"]
        WP["Waypoint proxies<br/>(Envoy, per namespace or service)"]
        ZTUNNEL -->|HBONE tunnel| WP
    end

Pilot (Traffic Management)

Pilot is the traffic management subsystem of istiod:

  • Watches Kubernetes Service/EndpointSlice resources, Istio CRDs (VirtualService, DestinationRule, Gateway, ServiceEntry, Sidecar) and Gateway API resources (Gateway, HTTPRoute, GRPCRoute, TLSRoute, ListenerSet, BackendTLSPolicy)
  • Translates routing rules, load-balancing policies, and failover configuration into Envoy xDS resources (LDS, RDS, CDS, EDS) and into Istio's simplified workload resources for ztunnel
  • Streams configuration to sidecars, gateways and waypoints over gRPC; certificates are delivered to Envoy through SDS served by the local pilot-agent

Citadel (Certificate Authority)

Citadel is the certificate authority inside istiod:

  • Issues SPIFFE-format X.509 certificates to every workload identity in the mesh
  • Identity format: spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>
  • Workload certificates default to a 24-hour lifetime and are rotated automatically before expiry
  • Uses a self-signed root by default, or plugged-in intermediate certificates (cacerts secret), or an external signer through the Kubernetes CSR API

Galley (Configuration Validation)

Galley was formerly a separate component for validating and transforming Istio configuration. Since Istio 1.5 its functions live in istiod: the validating admission webhook rejects malformed Istio resources, and istioctl analyze provides offline and in-cluster analysis (for example IST0176 in 1.31 flags Gateway API CRDs below the version Istio requires).

Component names are historical

Current documentation rarely uses Pilot, Citadel, and Galley as names. They survive in environment variable prefixes (PILOT_*) and in the pilot-discovery and pilot-agent binaries.

2. Data Plane -- Sidecar Mode

The sequence shows how a pod joins the mesh in sidecar mode.

sequenceDiagram
    participant K8s as Kubernetes API
    participant Hook as istiod injection webhook
    participant Pod as Application pod
    participant Init as istio-init or istio-cni
    participant Proxy as istio-proxy (Envoy + pilot-agent)
    participant Istiod as istiod
    participant App as Application container

    K8s->>Hook: Pod CREATE admission request
    Hook-->>K8s: Patched spec with istio-proxy (native sidecar init container since 1.27)
    K8s->>Pod: Schedule pod
    Pod->>Init: Program pod iptables or nftables redirect
    Pod->>Proxy: Start istio-proxy before the app
    Proxy->>Istiod: Open xDS stream and send CSR
    Istiod-->>Proxy: Listeners, routes, clusters, endpoints and signed certificate
    App->>Proxy: Outbound traffic redirected to port 15001
    Proxy->>Proxy: Apply routing, load balancing, mTLS

Sidecar Injection

Istio uses a Kubernetes mutating admission webhook to inject the istio-proxy container (Envoy plus pilot-agent) into application pods:

  • Automatic injection -- enabled by labeling a namespace with istio-injection=enabled
  • Revision-based injection -- istio.io/rev=<revision-or-tag> selects a specific control plane revision, which is the basis of canary upgrades
  • Native sidecars -- since Istio 1.27 ENABLE_NATIVE_SIDECARS defaults to true, so on Kubernetes versions with native sidecar support the proxy is injected as an init container with restartPolicy: Always, which fixes start-up and Job-termination ordering problems. Per pod, sidecar.istio.io/nativeSidecar overrides the global setting
  • istio-init container -- configures iptables (or native nftables since 1.27) to intercept inbound and outbound traffic; it needs NET_ADMIN and NET_RAW
  • Istio CNI node agent (optional for sidecars) -- replaces the privileged istio-init container with a chained CNI plugin that runs once per node, which removes the need for elevated capabilities in every workload
  • pilot-agent -- manages the Envoy lifecycle, bootstrap config, SDS certificate delivery, DNS proxying and health-check rewriting

Traffic Flow (Sidecar Mode)

  1. The application container sends traffic to a Kubernetes Service.
  2. iptables/nftables rules in the pod redirect outbound traffic to the Envoy sidecar (port 15001).
  3. Envoy applies routing rules (VirtualService or HTTPRoute) and load-balancing policy (DestinationRule).
  4. Envoy opens an mTLS connection to the destination pod's sidecar.
  5. The destination sidecar (port 15006) terminates mTLS, applies authorization, and forwards to the application container.

3. Data Plane -- Ambient Mesh

In ambient mode the per-pod proxy disappears. The diagram shows the node-level path, with the optional waypoint hop when L7 policy is needed.

graph TB
    subgraph NODE_A["Node A"]
        PodA["Pod A<br/>(istio.io/dataplane-mode=ambient)"]
        ZT_A["ztunnel<br/>(node DaemonSet)"]
        CNI_A["istio-cni agent"]
    end

    subgraph NODE_B["Node B"]
        PodB["Pod B<br/>(istio.io/dataplane-mode=ambient)"]
        ZT_B["ztunnel<br/>(node DaemonSet)"]
    end

    subgraph NS_WP["Namespace waypoint"]
        WP["Waypoint proxy<br/>(Envoy, gatewayClassName istio-waypoint)"]
    end

    CNI_A -.->|"in-pod redirect rules"| PodA
    PodA -->|"captured in pod netns :15001"| ZT_A
    ZT_A -->|"HBONE mTLS :15008"| ZT_B
    ZT_B -->|"plaintext inside pod netns"| PodB

    ZT_A -.->|"HBONE when use-waypoint set"| WP
    WP -.->|"HBONE after L7 policy"| ZT_B

    style ZT_A fill:#2d5a8a,color:#fff
    style ZT_B fill:#2d5a8a,color:#fff
    style WP fill:#8a2d5a,color:#fff

Workload Categories in Ambient Mode

Category Label Behavior
Out of mesh (none), or istio.io/dataplane-mode=none on a pod Standard pod, no mesh features
In mesh (L4) istio.io/dataplane-mode=ambient Traffic captured by ztunnel; mTLS, L4 authorization and L4 telemetry
In mesh (L7) istio.io/dataplane-mode=ambient + istio.io/use-waypoint=<name> L4 by ztunnel plus L7 routing, policy and telemetry in the waypoint

Enrolling a namespace requires only a label; unlike sidecar mode no pod restart is needed.

ztunnel (Node Proxy)

ztunnel ("zero-trust tunnel") is a purpose-built node proxy written in Rust:

  • Runs as a DaemonSet on every node
  • Implements L4 functions only: mTLS, L4 authorization policy, L4 telemetry, and HBONE tunnelling
  • Receives a simplified, Istio-specific set of xDS resources (workloads/addresses and authorization policies, called WDS) rather than the full Envoy listener/route/cluster model; this keeps istiod-to-ztunnel traffic small
  • Is multi-tenant: a single ztunnel holds certificates for every service account with pods on its node, and requests them from istiod on their behalf
  • Listens on ports 15001, 15006 and 15008 inside each enrolled pod's network namespace (see In-Pod Traffic Redirection)

Waypoint Proxies (L7)

Waypoint proxies provide L7 capabilities in ambient mode:

  • A waypoint is a Kubernetes Gateway API Gateway with gatewayClassName: istio-waypoint; istiod deploys an Envoy Deployment for it
  • Commonly deployed per namespace, but a waypoint can serve a single service or workload; the istio.io/waypoint-for label on the waypoint selects service (default), workload, all or none
  • Handles HTTP routing, retries, timeouts, fault injection, L7 authorization, RequestAuthentication and L7 telemetry
  • Traffic goes through a waypoint only when the destination namespace, service or pod carries istio.io/use-waypoint; a service label wins over a namespace label
  • Ingress gateway traffic skips the destination waypoint unless istio.io/ingress-use-waypoint=true is set (1.25+)
  • Waypoints scale like any Deployment; many replicas of a workload share one waypoint instead of each having its own sidecar
  • EnvoyFilter is not supported on waypoints; extensions use Wasm through the TrafficExtension API (1.30+)
  • 1.31 adds weighted waypoint canaries (istio.io/use-waypoint-canary plus a weight annotation) and, experimentally, agentgateway as a waypoint implementation

Istio CNI Node Agent

The istio-cni DaemonSet is required in ambient mode and optional in sidecar mode. It does not replace the cluster CNI (Calico, Cilium, cloud VPC CNIs); it installs a chained CNI plugin that runs after the primary plugin. In ambient mode it also enrolls pods: it enters each ambient pod's network namespace, installs redirect rules, and hands ztunnel a file descriptor for that namespace. Since 1.29 the agent reconciles iptables rules in existing pods automatically when it is upgraded, and since 1.30 it respects excludeNamespaces (un-enrolling pods in excluded namespaces). Native nftables rules are available in ambient mode since 1.28.

Ambient vs Sidecar

Ambient mode removes per-pod proxy overhead. ztunnel provides L4 security (mTLS) at node level; L7 features are opt-in via waypoint proxies. This reduces resource consumption and operational coupling (no restarts to enrol, proxies upgraded by the platform team) for workloads that mainly need encryption and identity-based L4 policy.

4. xDS API Usage

Istio uses the Envoy xDS protocol to distribute configuration. Envoy-based proxies (sidecars, gateways, waypoints) receive the classic Listener, Route, Cluster and Endpoint resources, with certificates over SDS. ztunnel receives a smaller Istio-specific workload model. The full resource table is in Reference: xDS Resources.

Delta (incremental) xDS has been the default since Istio 1.22: istiod sends only changed resources rather than a full snapshot. Push scope can be narrowed further with the Sidecar resource, exportTo, and discovery selectors; in 1.30.3+ and 1.31, pushes caused by ambient address changes are scoped to the affected waypoints (AMBIENT_SCOPED_ADDRESS_PUSHES, on by default).

5. SPIFFE Identity

Every workload in the mesh receives a SPIFFE identity derived from its Kubernetes service account:

spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>

This identity is encoded in the X.509 certificate SAN and is used for:

  • mTLS peer authentication between sidecars, ztunnels and waypoints
  • AuthorizationPolicy rules that restrict access by source identity (written without the spiffe:// prefix, for example cluster.local/ns/default/sa/curl)
  • Audit logging and telemetry with source and destination identity fields

Example ztunnel log showing identity:

src.identity="spiffe://cluster.local/ns/default/sa/curl"
dst.identity="spiffe://cluster.local/ns/default/sa/bookinfo-details"

6. Component Comparison

Aspect Sidecar mode Ambient mode
Proxy location Per pod (istio-proxy) Per node (ztunnel) + optional waypoint Deployment
Measured proxy cost (Istio 1.24, 1000 RPS, 1 KB) ~0.20 vCPU, ~60 MB per sidecar ztunnel ~0.06 vCPU, ~12 MB; waypoint ~0.25 vCPU, ~60 MB
L4 security Full mTLS Full mTLS via ztunnel
L7 features Full (routing, retries, fault injection, EnvoyFilter) Full via waypoint; no EnvoyFilter
Traffic capture iptables/nftables in pod (istio-init or istio-cni) iptables/nftables in pod netns, installed by istio-cni, served by node ztunnel
Enrolment Label namespace and restart pods Label namespace, no restart
Upgrades Restart every workload to pick up a new proxy Upgrade ztunnel/waypoints centrally
VM workloads Supported Not yet supported
Suitable for Per-pod L7 customization, VMs, EnvoyFilter users Large-scale mTLS-first deployments, gradual L7 adoption

Source for resource figures: Istio performance and scalability.

Choosing Sidecar or Ambient

Istio's docs recommend ambient for most new meshes that start with zero-trust L4 and add L7 selectively; the flowchart captures the documented exceptions.

flowchart TD
    START["New workload or namespace"] --> VM{"Runs on VMs or needs<br/>sidecar-to-waypoint interop?"}
    VM -->|Yes| SIDECAR["Sidecar mode"]
    VM -->|No| EF{"Depends on EnvoyFilter<br/>or per-pod proxy tuning?"}
    EF -->|Yes| SIDECAR
    EF -->|No| MC{"Multicluster topology?"}
    MC -->|"Primary-remote or single-network"| SIDECAR
    MC -->|"Multi-primary, multi-network"| AMBMC["Ambient (multicluster beta)"]
    MC -->|"Single cluster"| L7{"Needs L7 policy or routing?"}
    L7 -->|No| AMBL4["Ambient, ztunnel only"]
    L7 -->|Yes| AMBL7["Ambient + waypoint for that namespace or service"]

Both modes can coexist

Sidecar and ambient workloads interoperate at L4 in the same mesh, and the sidecar-to-ambient migration guide (added with 1.30) describes a gradual, reversible, per-namespace migration.


How It Works

Ambient mode data path, in-pod redirection, HBONE, xDS configuration distribution, and mTLS identity.

Ambient Mode Data Path

The sequence shows one TCP connection from Pod A to Pod B on another node. L4 authorization is enforced by the destination ztunnel; L7 authorization by the waypoint.

sequenceDiagram
    participant PodA as Pod A
    participant ZT_A as ztunnel (node A)
    participant WP as Waypoint (optional L7)
    participant ZT_B as ztunnel (node B)
    participant PodB as Pod B

    PodA->>ZT_A: TCP connect, captured in pod netns on 15001
    ZT_A->>ZT_A: Resolve destination workload and waypoint from WDS
    alt Destination uses a waypoint
        ZT_A->>WP: HBONE CONNECT on 15008 with Pod A SPIFFE cert
        WP->>WP: HTTP routing, retries, L7 AuthorizationPolicy
        WP->>ZT_B: HBONE CONNECT on 15008 with waypoint identity
    else L4 only
        ZT_A->>ZT_B: HBONE CONNECT on 15008 with Pod A SPIFFE cert
    end
    ZT_B->>ZT_B: Verify peer identity, apply L4 AuthorizationPolicy
    ZT_B->>PodB: Plaintext inside Pod B netns

In-Pod Traffic Redirection

Early ambient builds redirected traffic at node level; since Istio 1.21 (per its release announcement and the in-pod redirection blog) ambient uses an in-pod model that works with any primary CNI:

  1. The pod is created (or its namespace is labelled istio.io/dataplane-mode=ambient).
  2. The istio-cni node agent enters the pod's network namespace and installs redirect rules: outbound TCP to 15001, inbound plaintext to 15006, inbound HBONE to 15008.
  3. The agent sends ztunnel a file descriptor for the pod's network namespace over a Unix domain socket.
  4. ztunnel opens listening sockets on 15001/15006/15008 inside that namespace, even though the ztunnel process runs in its own pod.
  5. Traffic now leaves and enters the pod encrypted, while the application sees plain TCP.

Because redirection happens inside the pod namespace, node-level CNI features and Kubernetes NetworkPolicy continue to work; policies must allow port 15008.

HBONE Tunnel

HBONE (HTTP-Based Overlay Network Environment) is Istio's tunnel protocol between ztunnels, waypoints and HBONE-aware gateways. It composes three standards:

  1. HTTP CONNECT establishes a tunnel for each application connection.
  2. Mutual TLS secures the underlying connection, using SPIFFE certificates of the source and destination identities.
  3. HTTP/2 multiplexes many application connections as streams over one mTLS connection per source/destination identity pair, and carries stream-level metadata without modifying application bytes.

HBONE listeners use TCP port 15008 by convention. Window sizes are tunable since 1.30 (PILOT_HBONE_INITIAL_STREAM_WINDOW_SIZE, PILOT_HBONE_INITIAL_CONNECTION_WINDOW_SIZE).

istiod Configuration Distribution

istiod translates Kubernetes resources (Service, EndpointSlice, Pod, Istio CRDs, Gateway API) into proxy configuration:

flowchart TB
    subgraph istiod_I["istiod"]
        K8S_Watcher["Kubernetes informers<br/>(watch API server)"]
        Config_Analysis["Validation and<br/>push debouncing"]
        XDS_Generator["xDS generators<br/>(Envoy and WDS)"]
        CA["CA (Citadel)<br/>certificate signing"]
    end

    subgraph Data_Plane["Data plane"]
        ENV["Envoy: sidecars,<br/>gateways, waypoints"]
        ZT["ztunnel"]
    end

    K8S_Watcher --> Config_Analysis
    Config_Analysis --> XDS_Generator
    XDS_Generator -->|"delta xDS (LDS/RDS/CDS/EDS)"| ENV
    XDS_Generator -->|"delta xDS (WDS, authz)"| ZT
    CA -->|"sign CSR via pilot-agent"| ENV
    CA -->|"sign CSR per service account"| ZT

    style istiod_I fill:#5f6caf,color:#fff

Istiod debounces bursts of changes and pushes delta xDS updates only to affected proxies. Since 1.29 istiod sets GOMEMLIMIT to 90% of its memory limit automatically.

mTLS Identity (SPIFFE)

flowchart LR
    Istiod_C["istiod<br/>(CA)"] -->|"sign cert"| ZT["ztunnel or<br/>Envoy sidecar"]
    ZT -->|"present SPIFFE<br/>SVID"| Peer["Peer ztunnel<br/>or sidecar"]
    Peer -->|"verify cert<br/>chain"| Trust["Trust bundle<br/>(root CA)"]

    style Istiod_C fill:#5f6caf,color:#fff

Workload certificates default to a 24-hour lifetime and are rotated automatically before expiry; root and intermediate lifetimes depend on the CA setup (see Reference: Certificate Defaults).

Sidecar Mode Status

Sidecar mode is not deprecated. It is the original, battle-tested mode (since 2017), it can process L4 and L7 in every proxy, and it is still required for VM workloads, EnvoyFilter-based customization, and some multicluster topologies. Its cost is one Envoy per pod, provisioned for each pod's worst case, and a restart of every workload for proxy upgrades.


Upgrades and Revisions

Istio's upgrade model is built around revisions: several istiod control planes (for example 1-30-5 and 1-31-1) run side by side, each with its own injection webhook. Namespaces point at a revision through istio.io/rev. Revision tags (istioctl tag set prod-stable --revision 1-30-5) add an indirection, so namespaces reference a stable name and operators move the tag instead of relabelling namespaces. Sidecar workloads pick up a new proxy only when their pods restart.

stateDiagram-v2
    [*] --> OldOnly: istiod 1-30 serves tag prod-stable
    OldOnly --> BothRunning: install istiod 1-31 as a revision
    BothRunning --> CanaryTested: tag prod-canary to 1-31 and restart test namespaces
    CanaryTested --> Promoted: istioctl tag set prod-stable --revision 1-31 --overwrite
    Promoted --> Cleaned: restart workloads, then uninstall 1-30
    CanaryTested --> OldOnly: rollback by moving tag back
    Cleaned --> [*]

Key rules:

  • The control plane may be one minor version ahead of the data plane, never behind; Istio recommends revision upgrades so that there is no skew.
  • istioctl x precheck and the per-release upgrade notes catch breaking changes (for example 1.30 requires Gateway API v1.5.x CRDs, otherwise TLSRoute and ReferenceGrant become invisible to istiod).
  • The compatibilityVersion value (for example 1.28) restores a previous release's defaults when a new release changes behaviour.
  • In ambient mode, ztunnel and istio-cni are node-level DaemonSets; upgrading them affects every pod on the node, so istio-cni reconciles in-pod rules automatically (1.29+) and ztunnel upgrades are rolled node by node.

Release Model and Governance

  • Origins: announced in 2017 by Google, IBM and Lyft; Envoy (Lyft) is the data plane.
  • CNCF: accepted as Incubating on 2022-09-30, Graduated on 2023-07-12.
  • License: Apache 2.0; no relicensing.
  • Cadence: roughly one minor release per quarter (1.29 Feb 2026, 1.30 May 2026, 1.31 Aug 2026), each supported until six weeks after the N+2 minor. Release managers come from several vendors (for 1.31: Red Hat, Microsoft, Tetrate).
  • Infrastructure: starting with 1.31, artifacts move off Google Cloud hosting (gcr.io/istio-release, registry.istio.io, GCS) to Docker Hub, blob.istio.io, and ghcr.io.

Gateway API and Istio APIs

Istio supports two configuration APIs. The classic Istio APIs (VirtualService, DestinationRule, Gateway, ServiceEntry) predate Kubernetes namespace-based RBAC conventions; a VirtualService in one namespace can affect a hostname mesh-wide. The Kubernetes Gateway API (Gateway, HTTPRoute, GRPCRoute, TLSRoute, ListenerSet, BackendTLSPolicy) uses explicit parentRefs and ReferenceGrant for cross-namespace references and is the recommended API for new work, for ingress, waypoints, and mesh routing (GAMMA, parentRefs to a Service).

  • Istio 1.29 builds against Gateway API v1.4.1, 1.30 against v1.5.1 (TLSRoute and ReferenceGrant read from the Standard channel), and 1.31 against v1.6.0.
  • The Gateway API CRDs are not installed by Istio; they must be installed (and upgraded) separately.
  • ISTIO-SECURITY-2026-002 formalized the multi-tenancy trade-off: Istio considers mesh-wide VirtualService host hijacking expected behaviour, and recommends Gateway API (or extra RBAC hardening) for namespace-based multi-tenancy.

AI and Agent Traffic

  • Gateway API Inference Extension: InferencePool-based routing for self-hosted model servers, beta since 1.29 (ENABLE_GATEWAY_API_INFERENCE_EXTENSION).
  • agentgateway: a separate data plane proxy for AI agent and MCP traffic. Istio 1.30 added it experimentally as a Gateway API gateway (istio-agentgateway class, PILOT_ENABLE_AGENTGATEWAY=true), replacing Envoy in the gateway pod; 1.31 added it as a waypoint (istio-agentgateway-waypoint). Treat both as early access.

Benchmarks

Scope

How to read Istio performance numbers. The raw tables (official figures and older vault estimates) are in Reference: Resource and Performance Figures.

What the official numbers say

The Istio project publishes per-proxy resource figures and latency charts from its load tests (Istio 1.24: 1000 services, 2000 pods, 70,000 mesh-wide RPS). At 1000 RPS with 1 KB payloads, a sidecar used about 0.20 vCPU and 60 MB, a waypoint about 0.25 vCPU and 60 MB, and ztunnel about 0.06 vCPU and 12 MB. The key architectural consequence is multiplicative: sidecar cost scales with pod count, ztunnel cost scales with node count, and waypoint cost scales with the number of namespaces or services that need L7.

Latency trade-offs

In sidecar mode a request crosses two Envoys (client and server sidecar). In ambient L4 it crosses two ztunnels, which do no HTTP parsing. Ambient with a waypoint adds one Envoy hop between the ztunnels, so ambient L4+L7 is comparable to one Envoy hop rather than two. Telemetry filters (metrics, logging, tracing) add worker time that affects tail latency under load even though it runs after the response is sent.

Control plane scaling

istiod CPU scales with the rate of deployment changes, the rate of configuration changes, and the number of connected proxies. It is horizontally scalable; at large scale Istio recommends configuration scoping (Sidecar, exportTo, discovery selectors). In very large ambient meshes, 1.31 upgrade notes warn that ztunnel reconnect requests can exceed istiod's 4 MiB gRPC limit at about 40,000 workloads.

Unsourced performance data

The older vault figures in the reference tables were estimated from vendor docs, community benchmarks, and judgment, without recorded hardware, versions, or methodology. For capacity planning, benchmark your own workload.


Security Model

Istio provides layered security: service-to-service authentication (mTLS), end-user authentication (JWT), and fine-grained authorization. Envoy sidecars, ztunnels, and waypoints enforce it in the data plane; the CA inside istiod manages certificate lifecycle and trust.

1. Mutual TLS (mTLS)

Identity Model

Istio uses SPIFFE for workload identity (spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>), encoded in the X.509 certificate SAN.

Certificate Lifecycle

  1. The CA in istiod acts as the mesh CA.
  2. pilot-agent (sidecar) or ztunnel (ambient) generates a key and sends a CSR to istiod, authenticated with the Kubernetes service account token.
  3. istiod validates the token and identity.
  4. istiod issues a short-lived X.509 certificate (default 24 hours).
  5. The proxy rotates the certificate before expiry.
  6. Envoy receives certificates from pilot-agent through SDS; ztunnel keeps them in memory.

PeerAuthentication Modes

PeerAuthentication sets the mTLS mode (STRICT, PERMISSIVE, DISABLE, UNSET; mesh default PERMISSIVE), see Reference: Security API Values. Scope resolves workload over namespace over mesh (a policy in the root namespace, usually istio-system). Example: namespace PERMISSIVE with one workload STRICT:

apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: default
  namespace: foo
spec:
  mtls:
    mode: PERMISSIVE
---
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: finance
  namespace: foo
spec:
  selector:
    matchLabels:
      app: finance
  mtls:
    mode: STRICT

Migration path

Use PERMISSIVE during onboarding to allow gradual migration of services into the mesh. Switch to STRICT once all clients are meshed. In ambient mode, traffic between ambient workloads is always mTLS via HBONE; PeerAuthentication controls whether plaintext from outside the mesh is still accepted.

2. Certificate Rotation and CA Management

  • Workload certificates have a default 24-hour lifetime and are rotated before expiry without application downtime.
  • Root CA options: istiod self-signed root (default), plugged-in intermediate CA (cacerts secret, common for multicluster so that clusters share a root), and external signers (Kubernetes CSR API, cert-manager istio-csr).
  • Certificate revocation lists (CRL) are supported for plugged-in CAs (1.27) and in ztunnel (1.29).
Root CA (long-lived, offline or self-signed by istiod)
  └── Intermediate CA (optional, per cluster via cacerts)
        └── Workload certificate (24h, per service account)

3. AuthorizationPolicy

AuthorizationPolicy provides L4 and L7 access control based on identity, namespace, IP, and request attributes. ztunnel can enforce the L4 subset (principals, namespaces, IPs, ports); anything that needs HTTP attributes must be enforced by a waypoint or sidecar.

graph LR
    SRC["Source workload<br/>cluster.local/ns/frontend/sa/frontend"] -->|request| DST["Destination proxy<br/>(sidecar, ztunnel or waypoint)"]
    DST --> C{"CUSTOM policy?"}
    C -->|"ext authz denies"| REJECT["Rejected"]
    C -->|"allowed or none"| D{"DENY matches?"}
    D -->|yes| REJECT
    D -->|no| A{"Any ALLOW policy<br/>for workload?"}
    A -->|none| PASS["Forwarded"]
    A -->|"yes and matches"| PASS
    A -->|"yes, no match"| REJECT

Example (principals omit the spiffe:// prefix):

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: backend-policy
  namespace: production
spec:
  selector:
    matchLabels:
      app: backend
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/frontend/sa/frontend-sa"]
    to:
    - operation:
        methods: ["GET", "POST"]
        paths: ["/api/*"]

Matching criteria:

  • source: principals, requestPrincipals, namespaces, ipBlocks, remoteIpBlocks, and since 1.31 (backported to 1.30.2) trustDomains / notTrustDomains
  • operation: hosts, methods, paths, ports
  • when: conditions on request attributes (headers, JWT claims, and more)

Service-account matching fixed in 2026

CVE-2026-39350 (ISTIO-SECURITY-2026-003) showed that dots in serviceAccounts were interpreted as regex wildcards, enabling ALLOW/DENY bypass. Fixed in 1.29.2 and 1.28.6.

4. RequestAuthentication (JWT)

RequestAuthentication validates JSON Web Tokens against JWKS endpoints (OpenID Connect providers or custom issuers). It rejects invalid tokens but does not by itself require a token; pair it with an AuthorizationPolicy.

apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata:
  name: jwt-auth
  namespace: production
spec:
  selector:
    matchLabels:
      app: backend
  jwtRules:
  - issuer: "https://auth.example.com"
    jwksUri: "https://auth.example.com/.well-known/jwks.json"
    audiences:
    - "api-backend"
    forwardOriginalToken: true

Key features:

  • Multiple JWT issuers per workload
  • forwardOriginalToken: true passes the raw token to the backend
  • Token claims usable in AuthorizationPolicy when conditions (request.auth.claims[...])
  • Tokens read from headers (fromHeaders), query parameters (fromParams) or cookies (fromCookies)
  • In ambient mode, RequestAuthentication is enforced by waypoints, not ztunnel

JWT + AuthorizationPolicy Integration

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: require-jwt
  namespace: production
spec:
  selector:
    matchLabels:
      app: backend
  action: ALLOW
  rules:
  - from:
    - source:
        requestPrincipals: ["https://auth.example.com/*"]

requestPrincipals values have the form <iss>/<sub>; ["*"] means "any request with a valid JWT", and notRequestPrincipals: ["*"] matches requests without one. Without such a rule, requests with no token are allowed through RequestAuthentication.

JWKS fetching hardening

CVE-2026-31837 (JWKS resolver failure could allow auth bypass with known default keys, fixed via ISTIO-SECURITY-2026-001) and CVE-2026-41413 (SSRF via jwksUri, fixed in 1.29.2/1.28.6) both concern how istiod fetches JWKS. Restrict who can create RequestAuthentication resources.

5. Ambient Mesh Security

Layer Component Security
L4 ztunnel Automatic mTLS via HBONE; L4 AuthorizationPolicy
L7 Waypoint proxy L7 AuthorizationPolicy, RequestAuthentication (JWT)
Node ztunnel Multi-tenant: holds certificates for all service accounts on its node
Node istio-cni Privileged DaemonSet that manipulates pod network namespaces

ztunnel enforces mTLS by default in ambient mode. Because one ztunnel holds keys for every identity on a node, node compromise exposes all local identities (the same blast radius as compromising any node-level component such as the kubelet). Istio commissioned an independent security assessment of ztunnel in 2025 (blog).

6. External CA Integration

For enterprises with existing PKI:

  1. Plugged-in CA certificates: create the cacerts secret in istio-system with an intermediate signed by your root (ca-cert.pem, ca-key.pem, root-cert.pem, cert-chain.pem); istiod signs workload certificates with it.
  2. External signer: istiod acts as a registration authority and forwards CSRs through the Kubernetes CSR API (for example cert-manager with istio-csr), so the external CA controls issuance policy and audit.
  3. Multicluster: every cluster's intermediate must chain to a shared root for cross-cluster mTLS.

7. Security Policy Evaluation Order

Authentication happens before authorization:

  1. PeerAuthentication decides whether the connection must be mTLS and establishes the peer identity.
  2. RequestAuthentication validates any JWT and sets the request principal (invalid tokens are rejected).
  3. AuthorizationPolicy is evaluated in layers: CUSTOM first, then DENY, then ALLOW. AUDIT policies only mark requests for logging and never change the decision.

8. Threat Model Notes

  • Namespace-based multi-tenancy: classic Istio APIs (VirtualService, DestinationRule, ServiceEntry) act mesh-wide by hostname; a tenant who can create them can redirect other tenants' traffic (ISTIO-SECURITY-2026-002), though not bypass destination mTLS or AuthorizationPolicy. Prefer Gateway API plus RBAC.
  • EnvoyFilter is a control-plane risk: an oversized proxyVersion regex could exhaust istiod (ISTIO-SECURITY-2026-006) and, because the validating webhook fails closed, block config changes mesh-wide. Keep EnvoyFilter admin-only.
  • Debug endpoints: istiod debug endpoints on 15014 are namespace-authorized by default since 1.29, and XDS debug endpoints on 15010 require authentication since 1.30.
  • Envoy CVEs dominate patch releases: most 2026 bulletins are Envoy data plane fixes; staying on the latest patch of a supported minor is the main control.

Key insight

Istio's security model is defense in depth: PeerAuthentication provides transport encryption and identity, RequestAuthentication validates end-user identity, and AuthorizationPolicy enforces access at L4 and L7. In ambient mode, ztunnel gives L4 security with zero application changes; L7 policies need a waypoint.

Sources