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 (
cacertssecret), 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_SIDECARSdefaults totrue, so on Kubernetes versions with native sidecar support the proxy is injected as an init container withrestartPolicy: Always, which fixes start-up and Job-termination ordering problems. Per pod,sidecar.istio.io/nativeSidecaroverrides the global setting - istio-init container -- configures iptables (or native nftables since 1.27) to intercept inbound and outbound traffic; it needs
NET_ADMINandNET_RAW - Istio CNI node agent (optional for sidecars) -- replaces the privileged
istio-initcontainer 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)¶
- The application container sends traffic to a Kubernetes Service.
- iptables/nftables rules in the pod redirect outbound traffic to the Envoy sidecar (port 15001).
- Envoy applies routing rules (
VirtualServiceorHTTPRoute) and load-balancing policy (DestinationRule). - Envoy opens an mTLS connection to the destination pod's sidecar.
- 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
GatewaywithgatewayClassName: 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-forlabel on the waypoint selectsservice(default),workload,allornone - Handles HTTP routing, retries, timeouts, fault injection, L7 authorization,
RequestAuthenticationand 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=trueis set (1.25+) - Waypoints scale like any Deployment; many replicas of a workload share one waypoint instead of each having its own sidecar
EnvoyFilteris not supported on waypoints; extensions use Wasm through theTrafficExtensionAPI (1.30+)- 1.31 adds weighted waypoint canaries (
istio.io/use-waypoint-canaryplus 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:
This identity is encoded in the X.509 certificate SAN and is used for:
- mTLS peer authentication between sidecars, ztunnels and waypoints
AuthorizationPolicyrules that restrict access by source identity (written without thespiffe://prefix, for examplecluster.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:
- The pod is created (or its namespace is labelled
istio.io/dataplane-mode=ambient). - 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.
- The agent sends ztunnel a file descriptor for the pod's network namespace over a Unix domain socket.
- ztunnel opens listening sockets on 15001/15006/15008 inside that namespace, even though the ztunnel process runs in its own pod.
- 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:
- HTTP CONNECT establishes a tunnel for each application connection.
- Mutual TLS secures the underlying connection, using SPIFFE certificates of the source and destination identities.
- 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 precheckand the per-release upgrade notes catch breaking changes (for example 1.30 requires Gateway API v1.5.x CRDs, otherwiseTLSRouteandReferenceGrantbecome invisible to istiod).- The
compatibilityVersionvalue (for example1.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, andghcr.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 (
TLSRouteandReferenceGrantread 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
VirtualServicehost 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-agentgatewayclass,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¶
- The CA in istiod acts as the mesh CA.
- pilot-agent (sidecar) or ztunnel (ambient) generates a key and sends a CSR to istiod, authenticated with the Kubernetes service account token.
- istiod validates the token and identity.
- istiod issues a short-lived X.509 certificate (default 24 hours).
- The proxy rotates the certificate before expiry.
- 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 (
cacertssecret, common for multicluster so that clusters share a root), and external signers (Kubernetes CSR API, cert-manageristio-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: truepasses the raw token to the backend- Token claims usable in
AuthorizationPolicywhenconditions (request.auth.claims[...]) - Tokens read from headers (
fromHeaders), query parameters (fromParams) or cookies (fromCookies) - In ambient mode,
RequestAuthenticationis 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:
- Plugged-in CA certificates: create the
cacertssecret inistio-systemwith an intermediate signed by your root (ca-cert.pem,ca-key.pem,root-cert.pem,cert-chain.pem); istiod signs workload certificates with it. - 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. - Multicluster: every cluster's intermediate must chain to a shared root for cross-cluster mTLS.
7. Security Policy Evaluation Order¶
Authentication happens before authorization:
- PeerAuthentication decides whether the connection must be mTLS and establishes the peer identity.
- RequestAuthentication validates any JWT and sets the request principal (invalid tokens are rejected).
- AuthorizationPolicy is evaluated in layers:
CUSTOMfirst, thenDENY, thenALLOW.AUDITpolicies 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 orAuthorizationPolicy. Prefer Gateway API plus RBAC. EnvoyFilteris a control-plane risk: an oversizedproxyVersionregex could exhaust istiod (ISTIO-SECURITY-2026-006) and, because the validating webhook fails closed, block config changes mesh-wide. KeepEnvoyFilteradmin-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¶
- Istio architecture
- Sidecar or ambient?
- Ambient architecture and HBONE
- Ambient traffic redirection
- Use a waypoint
- Istio CNI node agent
- Canary upgrades and revision tags
- Security concepts
- Plug in CA certificates
- Performance and scalability
- ztunnel ARCHITECTURE.md
- Release announcements: 1.22, 1.24, 1.27, 1.29, 1.30, 1.31
- CNCF: Istio graduation (2023-07-12)