Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Istio User Guide

Generated June 2026 from istio/istio at b80c113

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Istio is an open-source service mesh that layers transparently onto distributed applications running on Kubernetes. It gives you uniform traffic management, security (mutual TLS, authentication, authorization), and observability without changing your application code. You deploy your services as usual; Istio injects a data-plane proxy (or routes through a shared per-node proxy) that intercepts traffic and enforces the policies you declare with Kubernetes custom resources.

This guide is task-oriented: it walks you from a first install to deploying an app, shaping its traffic, securing it with mTLS, and debugging it with istioctl. Deep architecture, the complete configuration reference, and operational hardening live in the Istio Admin Guide — this guide links there where appropriate.

Note

Istio supports two data-plane modes. Sidecar mode injects an Envoy proxy container into every workload pod. Ambient mode removes the per-pod sidecar and instead uses a per-node proxy (ztunnel) plus optional waypoint proxies. Both are covered below; you choose one when you install.


1. Quick Start

This is the fastest path from nothing to a working mesh with a sample application. It assumes you already have a running Kubernetes cluster and kubectl configured to talk to it.

1.1 Install the istioctl CLI

istioctl is the primary command-line tool for installing, configuring, and debugging Istio. Download a release and place the binary on your PATH.

# Download the latest release bundle and add istioctl to PATH
curl -L https://istio.io/downloadIstio | sh -
cd istio-*
export PATH="$PWD/bin:$PATH"

Verify the client is available:

istioctl version
client version: 1.x.x
control plane version: <none — not installed yet>

Tip

istioctl version reports both the client version and the control plane version running in your cluster. Before installation only the client version is shown.

1.2 Install Istio into the cluster

Install the control plane using a built-in configuration profile. The demo profile is intentionally feature-rich and is ideal for evaluation; use default for production.

istioctl install --set profile=demo -y
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
✔ Egress gateways installed
✔ Installation complete

This deploys the control plane (istiod) and the configured gateways into the istio-system namespace.

1.3 Enable sidecar injection for a namespace

Label a namespace so that any pod scheduled into it automatically receives an Istio sidecar proxy:

kubectl label namespace default istio-injection=enabled
namespace/default labeled

1.4 Deploy the Bookinfo sample and send traffic

Istio ships a multi-service demo application called Bookinfo. Deploy it, then expose it through the ingress gateway:

kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml

Confirm every workload has the expected 2/2 containers (your app container + the injected istio-proxy):

kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
productpage-v1-...                2/2     Running   0          60s
reviews-v1-...                    2/2     Running   0          60s
ratings-v1-...                    2/2     Running   0          60s
details-v1-...                    2/2     Running   0          60s

Important

The 2/2 is the signal that injection worked: container one is your application, container two is the istio-proxy (Envoy) sidecar. If you see 1/1, the namespace label was missing when the pod started — see Troubleshooting.

You now have a mesh. The next sections show how to use it.


2. Installation

Istio can be installed three ways. All three install the same control plane; pick the one that fits your tooling.

istioctl (recommended)

The istioctl install command renders and applies the control plane in one step.

istioctl install --set profile=default -y

Helm

Istio publishes Helm charts (base, istiod, gateways, cni, ztunnel). Install the cluster-wide resources first, then the discovery component.

helm install istio-base istio/base -n istio-system --create-namespace
helm install istiod istio/istiod -n istio-system --wait

IstioOperator manifest

Render a manifest from an IstioOperator resource and apply it with kubectl. This is useful for GitOps pipelines that want the YAML checked in.

istioctl manifest generate -f my-istio.yaml > istio-manifest.yaml
kubectl apply -f istio-manifest.yaml

2.1 Choosing an installation profile

A profile is a named, opinionated bundle of components and values. Istio ships the following profiles (each is a small IstioOperator overlay):

Profile Components enabled Use it for
default base, pilot (istiod), ingress gateway Production. Recommended starting point.
demo base, pilot, ingress and egress gateways Evaluation and tutorials — high visibility, not tuned for performance.
minimal base, pilot only (no gateways) Control plane only; add gateways separately.
empty nothing A base for fully custom configurations.
preview preview/experimental features Trying features not yet stable.
ambient CNI + ztunnel, ingress gateway disabled Ambient mode (sidecar-less) meshes.
remote injector webhook only, no local control plane Remote clusters that use an external control plane.
stable conservative feature set Maximum stability.
openshift / openshift-ambient platform tweaks, CNI in kube-system OpenShift clusters.

Inspect exactly what a profile renders before installing it:

istioctl manifest generate --set profile=demo

Tip

Override any value at install time with --set, e.g. istioctl install --set profile=default --set values.global.proxy.resources.requests.cpu=200m. For the complete value reference, see the Admin Guide → Configuration Mastery.

2.2 Verify the installation

Confirm the control plane pod is healthy and check the negotiated versions:

kubectl get pods -n istio-system
istioctl version

Then confirm every proxy is in sync with the control plane:

istioctl proxy-status
NAME                      READY   STATUS    RESTARTS   AGE
istiod-...                1/1     Running   0          2m
istio-ingressgateway-...  1/1     Running   0          2m

2.3 Install ambient mode (sidecar-less)

If you prefer the ambient data plane, install the ambient profile. This enables the Istio CNI plugin and the per-node ztunnel DaemonSet instead of per-pod sidecars.

istioctl install --set profile=ambient -y

Enroll a namespace into ambient by labeling it (no pod restart or sidecar required):

kubectl label namespace default istio.io/dataplane-mode=ambient

Note

In ambient mode, workloads get L4 mutual TLS and identity through ztunnel with zero per-pod overhead. For L7 features (HTTP routing, rich authorization), you add a waypoint proxy — see §6.3.

2.4 Uninstall

istioctl uninstall --purge -y
kubectl delete namespace istio-system

Caution

--purge removes all Istio resources, including cluster-scoped CRDs. Any custom resources (Gateways, VirtualServices, policies) become orphaned. Back up your configuration first.


3. Enabling the Mesh for Your Workloads

Adding a workload to the mesh means giving it an Istio proxy. How you do that depends on the data-plane mode.

3.1 Sidecar injection (automatic)

Label the namespace, then (re)deploy your workloads. New pods are injected by the mutating admission webhook as they are created.

kubectl label namespace my-app istio-injection=enabled
kubectl rollout restart deployment -n my-app   # restart existing pods to inject them

To opt a single pod out of injection in an enabled namespace, add this annotation to the pod template:

metadata:
  annotations:
    sidecar.istio.io/inject: "false"

3.2 Sidecar injection (manual)

When you cannot rely on the webhook (for example, generating manifests offline), inject the sidecar into a manifest yourself with istioctl kube-inject:

istioctl kube-inject -f deployment.yaml | kubectl apply -f -
deployment.apps/my-app created

Tip

istioctl kube-inject is also useful to see exactly what gets added to your pod — pipe it to a pager instead of kubectl apply to review the injected container, init container, and volumes.

3.3 Ambient enrollment

In ambient mode there is no injection. Enroll a namespace (or an individual pod) by labeling it; traffic is captured by the node's ztunnel immediately.

kubectl label namespace my-app istio.io/dataplane-mode=ambient   # enroll
kubectl label namespace my-app istio.io/dataplane-mode=none      # explicitly exclude

3.4 Revisions and canary control-plane upgrades

Istio supports running multiple control-plane revisions side by side using the istio.io/rev label, which lets you upgrade the control plane like a canary. Pin a namespace to a specific revision instead of the floating istio-injection label:

kubectl label namespace my-app istio.io/rev=1-22 --overwrite

Manage which revision is the default with the tag command:

istioctl tag set default --revision 1-22
istioctl tag list

See the Admin Guide → Operations for the full canary upgrade workflow.


4. Everyday Usage with istioctl

istioctl is how you operate and debug the mesh day to day. Every command accepts a set of global flags.

4.1 Global flags

These flags can be passed to (almost) any istioctl command:

Flag Short Default Purpose
--kubeconfig -c (kube default) Path to the kubeconfig file.
--context current context Kubernetes context to use.
--namespace -n (all/none) Target Kubernetes namespace.
--istioNamespace -i istio-system Namespace where Istio is installed.
--as Username to impersonate for the operation.
--as-uid UID to impersonate.
--as-group Group to impersonate (repeatable).
--kubeclient-timeout 15s Kubernetes client timeout (a Go duration string).

Note

Defaults can be persisted in $HOME/.istioctl/config.yaml, and any setting can be overridden with environment variables prefixed ISTIOCTL_ (for example, ISTIOCTL_ISTIONAMESPACE=custom-system). Run istioctl options to list the global options.

4.2 Command map

istioctl groups its functionality into stable top-level commands and an experimental (alias x) group for commands that may still change.

Command What it does
istioctl install Install or update the Istio control plane.
istioctl manifest generate Render the install YAML without applying it.
istioctl upgrade Upgrade an existing control plane.
istioctl uninstall Remove Istio.
istioctl kube-inject Inject the sidecar into a manifest manually.
istioctl analyze Statically analyze configuration for problems.
istioctl proxy-status Show sync status of every proxy against istiod.
istioctl proxy-config Inspect the live Envoy config of a proxy.
istioctl ztunnel-config Inspect ztunnel configuration (ambient).
istioctl waypoint Manage waypoint proxies (ambient).
istioctl dashboard Open built-in dashboards (Envoy, Kiali, Grafana, etc.).
istioctl bug-report Collect a diagnostic bundle for support.
istioctl tag Manage revision tags for canary upgrades.
istioctl validate Validate configuration files.
istioctl version Show client and control-plane versions.
istioctl create-remote-secret Generate a secret for multi-cluster access.
istioctl admin Control-plane administration (e.g. log levels).
istioctl experimental authz Authorization policy debugging.
istioctl experimental describe Describe how config affects a pod.
istioctl experimental metrics Show workload metrics.
istioctl experimental config Manage istioctl defaults.
istioctl experimental workload Manage VM/non-Kubernetes workloads.
istioctl experimental precheck Pre-flight checks before install/upgrade.
istioctl experimental check-inject Explain whether a pod will be injected.

Tip

Commands that have graduated still leave a hint behind: running istioctl authz reminds you to use istioctl experimental authz. Use istioctl <command> --help for the authoritative flag list of any command in your installed version.

4.3 Analyze your configuration

istioctl analyze runs a battery of static checks against your live cluster (or local files) and reports misconfigurations before they cause outages.

istioctl analyze -n default
✔ No validation issues found when analyzing namespace: default.

Analyze local files without a cluster:

istioctl analyze gateway.yaml virtual-service.yaml

Important

istioctl analyze uses deliberate exit codes so it can gate CI/CD pipelines: 0 = clean, 79 = analyzer found issues, 65 = input data/parse error, 64 = incorrect usage. Check $? in scripts rather than parsing the text output.

4.4 Check proxy sync status

proxy-status (also istioctl ps) shows whether each proxy has the latest configuration pushed from istiod. This is the first command to run when "my change isn't taking effect".

istioctl proxy-status
NAME                          CLUSTER     CDS        LDS        EDS        RDS        ECDS
productpage-v1-...default     Kubernetes  SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT
reviews-v1-...default         Kubernetes  SYNCED     SYNCED     SYNCED     STALE      NOT SENT

SYNCED means the proxy has istiod's latest config. STALE means a push is in flight or the proxy is not acknowledging. NOT SENT means istiod has nothing of that type to send.

4.5 Inspect a proxy's live configuration

proxy-config dumps the actual Envoy configuration of a running proxy — clusters, listeners, routes, endpoints, secrets, and bootstrap.

istioctl proxy-config clusters productpage-v1-xxxx.default
istioctl proxy-config listeners productpage-v1-xxxx.default --port 9080
istioctl proxy-config routes productpage-v1-xxxx.default -o json
istioctl proxy-config secret productpage-v1-xxxx.default   # check mTLS certs

Tip

proxy-config secret is the quickest way to confirm a workload has a valid mTLS certificate and to read its expiry and SPIFFE identity.

4.6 Describe what config applies to a pod

istioctl experimental describe pod summarizes, in plain language, which policies, routes, and mTLS settings actually apply to a given pod:

istioctl experimental describe pod productpage-v1-xxxx

5. Traffic Management

Istio's traffic features are driven by Kubernetes custom resources in the networking.istio.io API group. You write YAML; the mesh enforces it. The core resources are summarized here; the Admin Guide documents every field.

Resource Purpose
Gateway Configure a load balancer for inbound/outbound mesh traffic (ports, hosts, TLS).
VirtualService Define routing rules — match requests and route them to destinations.
DestinationRule Define policies applied after routing — subsets, load balancing, connection pools, outlier detection.
ServiceEntry Add external services to the mesh's service registry.
Sidecar Scope which services a workload's proxy knows about.

Istio also supports the Kubernetes Gateway API (gateway.networking.k8s.io) as a first-class alternative to the Gateway/VirtualService pair.

5.1 Expose a service through an ingress gateway

A Gateway configures the shared istio-ingressgateway load balancer; a VirtualService binds your service's routes to that gateway. This example (from the shipped httpbin sample) exposes the httpbin service on port 80:

apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: httpbin-gateway
spec:
  selector:
    istio: ingressgateway        # use the built-in ingress gateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: httpbin
spec:
  hosts:
  - "*"
  gateways:
  - httpbin-gateway
  http:
  - route:
    - destination:
        host: httpbin
        port:
          number: 8000
kubectl apply -f samples/httpbin/httpbin.yaml
kubectl apply -f samples/httpbin/httpbin-gateway.yaml

Find the gateway's external address and send a request:

kubectl get svc istio-ingressgateway -n istio-system
curl -s http://<EXTERNAL-IP>/get

5.2 Split traffic between versions

A VirtualService with weighted routes is the canonical way to do canary releases and A/B tests. Send 90% of traffic to v1 and 10% to v2:

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 90
    - destination:
        host: reviews
        subset: v2
      weight: 10

The subset names are defined in a DestinationRule:

apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2

Tip

Always define DestinationRule subsets before a VirtualService references them, or requests to the unknown subset will fail. istioctl analyze catches this.

5.3 Match on request properties

Route based on headers, URI, method, and more:

http:
- match:
  - headers:
      end-user:
        exact: tester
  route:
  - destination:
      host: reviews
      subset: v2
- route:                 # default route for everyone else
  - destination:
      host: reviews
      subset: v1

5.4 Reach external services

By default the mesh can be configured to block egress to unknown hosts. Register an external dependency with a ServiceEntry so mesh policies and telemetry apply to it:

apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
  name: external-api
spec:
  hosts:
  - api.example.com
  ports:
  - number: 443
    name: https
    protocol: TLS
  resolution: DNS
  location: MESH_EXTERNAL

6. Security

Istio provides workload identity, encryption in transit, and access control. Most of it is on by default or enabled with a short policy.

6.1 Mutual TLS between workloads

Every meshed workload is issued a SPIFFE identity certificate automatically, and the mesh uses mutual TLS between proxies by default (permissive mode, which accepts both mTLS and plaintext). To require mTLS for a namespace, apply a PeerAuthentication:

apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: default
  namespace: my-app
spec:
  mtls:
    mode: STRICT

Confirm a proxy actually has its certificate:

istioctl proxy-config secret <pod>.<namespace>

Important

Switch to STRICT only after confirming all clients are in the mesh. In STRICT mode, plaintext requests from non-mesh clients are rejected. Start with the default PERMISSIVE mode and migrate gradually.

6.2 Authorization policies

AuthorizationPolicy controls which identities may call which workloads. This policy allows only the bookinfo-productpage service account to call the reviews workload:

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: reviews-viewer
  namespace: default
spec:
  selector:
    matchLabels:
      app: reviews
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/default/sa/bookinfo-productpage"]

Debug authorization decisions with:

istioctl experimental authz check <pod>.<namespace>

6.3 Ambient mode waypoints

In ambient mode, L4 mTLS is provided by ztunnel automatically. To enforce L7 policy (HTTP-aware authorization, routing), deploy a waypoint proxy for a namespace or service account:

istioctl waypoint apply -n my-app --enroll-namespace
istioctl waypoint list -n my-app
NAME       REVISION   PROGRAMMED
waypoint   default    True

Inspect ztunnel's view of workloads and certificates:

istioctl ztunnel-config workloads
istioctl ztunnel-config certificates

6.4 Testing with JWTs

The repository ships a helper, security/tools/jwt/samples/gen-jwt.py, to mint test JWTs for RequestAuthentication / JWT-based authorization rules:

python security/tools/jwt/samples/gen-jwt.py key.pem --expire 3600 \
  --iss [email removed] --aud my-audience

Key flags of gen-jwt.py:

Flag Default Meaning
--iss [email removed] iss (issuer) claim.
--aud aud (audience) claim — comma-separated list.
--sub (same as iss) sub (subject) claim.
--claims name:value,... Additional string claims.
--expire 3600 Expiry in seconds (default 1 hour).
--jwks Path to write the matching JWKS file.

7. Observability

Istio generates metrics, distributed traces, and access logs for all mesh traffic without application changes.

7.1 Install the telemetry addons

The repository bundles sample addon manifests for Prometheus, Grafana, Kiali, and Jaeger:

kubectl apply -f samples/addons/
kubectl rollout status deployment/kiali -n istio-system

Note

The bundled addons are samples for demos, not production deployments. For production, run your own hardened observability stack — see the Admin Guide.

7.2 Open dashboards

istioctl dashboard port-forwards and opens the built-in UIs:

istioctl dashboard kiali
istioctl dashboard grafana
istioctl dashboard prometheus
istioctl dashboard envoy <pod>.<namespace>     # raw Envoy admin UI
istioctl dashboard controlz <istiod-pod>       # istiod's ControlZ introspection UI

7.3 Scrape proxy metrics directly

Each proxy exposes a merged Prometheus endpoint (its own metrics plus the application's) on port 15020:

kubectl exec <pod> -c istio-proxy -- curl -s localhost:15020/stats/prometheus | head

Caution

Do not point a Prometheus scrape target at an Istio-reserved data-plane port. Ports 15000, 15001, 15004, 15006, 15008, 15020, 15021, 15053, and 15090 are owned by the sidecar; scraping them either hits a non-application surface or creates a recursive scrape loop. The agent rejects such scrape configurations at startup.


8. Common Tasks (Recipes)

Short, copy-pasteable solutions to frequent needs.

Restart all workloads in a namespace to (re)inject sidecars:

kubectl rollout restart deployment -n my-app

See the effective Envoy config for a single port:

istioctl proxy-config listeners <pod>.<ns> --port 8080 -o yaml

Confirm a pod will be injected before deploying:

istioctl experimental check-inject <pod>.<ns>

Set the istiod log level at runtime (no restart):

istioctl admin log --level all:debug
istioctl admin log                      # show current levels

Collect a full diagnostic bundle for a support request:

istioctl bug-report
Target cluster context: my-cluster
Running with the following config: ...
Cluster resource information collected; archive at bug-report.tar.gz

Generate the install YAML for review/GitOps instead of applying:

istioctl manifest generate --set profile=default > istio.yaml

Diff what an upgrade would change:

istioctl manifest generate -f current.yaml > current-manifest.yaml
istioctl manifest generate -f new.yaml > new-manifest.yaml
diff current-manifest.yaml new-manifest.yaml

9. How Istio Works (Concepts)

You can use Istio productively from the sections above; this section explains what is happening under the hood. The full architecture is in the Admin Guide.

9.1 Control plane and data plane

  • Control plane — istiod. A single binary (pilot-discovery) that watches Kubernetes for your configuration (Gateways, VirtualServices, policies) and the service registry, translates them into Envoy xDS configuration, pushes that config to every proxy, acts as the certificate authority issuing workload identities, and runs the sidecar-injection and validation webhooks.
  • Data plane — the proxies. In sidecar mode this is an Envoy proxy plus a management agent (pilot-agent) inside each pod. In ambient mode it is a per-node ztunnel (L4) plus optional waypoint proxies (L7). The data plane carries all the actual traffic and enforces policy.

9.2 What the sidecar agent does

pilot-agent (the istio-proxy container) bootstraps and supervises Envoy. It:

  • fetches configuration from istiod over the secure xDS channel,
  • obtains and rotates the workload's mTLS certificate (via in-process SDS),
  • runs a local DNS proxy,
  • serves health probes and a merged metrics endpoint on port 15020, and
  • proxies application Kubernetes liveness/readiness probes so they work with STRICT mTLS.

9.3 Traffic capture

Application traffic is transparently redirected into the proxy. In sidecar mode this is done with istio-iptables (or native nftables) rules installed by an init container or by the Istio CNI plugin. In ambient mode the Istio CNI node agent programs redirection to the node's ztunnel. Either way, your application opens normal sockets — capture is invisible to it.

9.4 Identity

Every workload receives a SPIFFE identity of the form spiffe://<trust-domain>/ns/<namespace>/sa/<service-account> (trust domain defaults to cluster.local). This identity is the subject of the workload's mTLS certificate and is what AuthorizationPolicy principals match against.

9.5 Sidecar vs. ambient at a glance

Sidecar mode Ambient mode
Proxy placement One Envoy per pod One ztunnel per node (+ optional waypoints)
Enablement istio-injection=enabled + pod restart istio.io/dataplane-mode=ambient (no restart)
L4 mTLS Yes Yes (via ztunnel)
L7 features Always available in the sidecar Require a waypoint proxy
Per-pod overhead Higher (sidecar per pod) Lower (shared node proxy)

10. Troubleshooting

Each entry gives the exact symptom, the cause, the fix, and how to prevent it. Many of these reflect real, community-reported behaviors.

Error: pods show 1/1 instead of 2/2 (no sidecar injected)

Cause: The namespace was not labeled istio-injection=enabled (or istio.io/rev) when the pod was created, or the pod opts out via sidecar.istio.io/inject: "false".

Solution:

kubectl label namespace my-app istio-injection=enabled --overwrite
kubectl rollout restart deployment -n my-app
istioctl experimental check-inject <pod>.<ns>   # explains the decision

Prevention: Label namespaces as part of their creation manifest, and run istioctl analyze in CI.

Error: configuration change has no effect

Cause: The proxy has not received the new config from istiod, or the config is invalid and was rejected.

Solution:

istioctl proxy-status                # look for STALE / NOT SENT
istioctl analyze -n my-app           # surface validation errors
istioctl proxy-config routes <pod>.<ns>   # confirm the route is actually present

Prevention: Gate merges on istioctl analyze (exit code 79 means issues found).

Error: 503 / upstream connect error after enabling STRICT mTLS

Cause: A client that is not in the mesh (or a port that is not mTLS-capable) is calling a workload now requiring mTLS.

Solution: Move the client into the mesh, or scope the PeerAuthentication to specific ports, or revert to PERMISSIVE while migrating.

Prevention: Roll out PERMISSIVE first, verify with proxy-config secret, then go STRICT namespace by namespace.

Error: identity verification error — "peer did not present the expected SAN"

Cause: The destination's certificate identity does not match what the client expects (for example, wrong service account, or a DestinationRule/ServiceEntry host mismatch).

Solution: Verify the workload's SPIFFE identity with istioctl proxy-config secret <pod>.<ns> and confirm AuthorizationPolicy principals and any subjectAltNames you configured match it exactly.

Prevention: Derive principals from the actual cluster.local/ns/<ns>/sa/<service-account> rather than hand-writing them.

Error: a JWT without a sub claim is rejected by AuthorizationPolicy

Cause: Rules that match on request.auth.principal (request principals) require a subject; a token with no sub claim yields no request principal and is denied.

Solution: Issue tokens that include a sub claim (the bundled gen-jwt.py sets sub to the iss value when not provided), or match on requestPrincipals: ["*"] plus other claims.

Prevention: Validate token claims with RequestAuthentication and test with gen-jwt.py before enforcing.

Error (ambient): nftables failures on the CNI node agent

Cause: A known interaction between ambient-mode CNI and certain kernels can cause failures in nft list/delete operations.

Solution: Check the istio-cni node-agent logs (kubectl logs -n istio-system ds/istio-cni-node). If the native nftables path is implicated, the CNI also supports forcing the iptables binary via the FORCE_IPTABLES_BINARY environment variable.

Prevention: Test ambient mode on a representative kernel before production rollout and track the upstream issue for your version.

Error: increased configuration pushes / istiod CPU after upgrade

Cause: More frequent xDS pushes than expected, often driven by churn in watched resources.

Solution: Use istioctl proxy-status to see push activity, and scope each workload's visibility with a Sidecar resource so istiod pushes less to each proxy.

Prevention: Apply Sidecar resources in large meshes to bound the config each proxy receives (see Admin Guide → Performance).

Error: istioctl analyze exits non-zero in CI

Cause: This is by design — analyze returns 79 when it finds configuration issues.

Solution: Read the reported messages and fix the flagged resources; rerun until exit code is 0.

Prevention: Treat analyze as a required pre-merge check.


11. FAQ

Q: Do I have to change my application code to use Istio? No. Istio works at the network layer through proxies. Your application makes ordinary network calls; the mesh intercepts and manages them.

Q: Sidecar or ambient — which should I choose? Sidecar mode is the mature, full-featured default and gives every workload L7 features inline. Ambient mode lowers per-pod overhead and avoids pod restarts to join the mesh, at the cost of needing waypoint proxies for L7 features. Start with sidecar unless per-pod overhead or "no restart to enroll" is a hard requirement.

Q: Is mTLS on by default? Workload certificates are issued automatically and proxies use mTLS in PERMISSIVE mode by default (accepting both mTLS and plaintext). Enforce it with a STRICT PeerAuthentication.

Q: What namespace does Istio install into? istio-system by default. Override with the -i/--istioNamespace flag or the ISTIOCTL_ISTIONAMESPACE environment variable.

Q: How do I upgrade without downtime? Use revision-based canary upgrades: install a new revision, move namespaces to it with the istio.io/rev label and istioctl tag, verify, then retire the old revision. See the Admin Guide.

Q: Can I use the Kubernetes Gateway API instead of Istio's Gateway/VirtualService? Yes. Istio implements the Kubernetes Gateway API (gateway.networking.k8s.io) and it is the recommended API for new ingress configurations.

Q: How do I add a non-Kubernetes workload (a VM) to the mesh? Use istioctl experimental workload group create and workload entry configure to generate the identity and bootstrap files the VM needs.

Q: Why is my proxy STALE in proxy-status? A push is in flight or the proxy isn't acknowledging. Persistent staleness points to istiod load, a network issue to port 15012, or an invalid config — check istiod logs and istioctl analyze.

Q: Where do I see exactly what config applies to a pod? istioctl experimental describe pod <pod> for a human summary, or istioctl proxy-config all <pod>.<ns> for the raw Envoy config.

Q: How do I completely remove Istio? istioctl uninstall --purge -y then delete the istio-system namespace. Remember this also removes CRDs and orphans your custom resources.

Q: My config has a typo — will Istio tell me? Yes. The validation webhook rejects invalid resources at apply time, and istioctl analyze catches semantic problems (like a VirtualService referencing a missing subset) that pass schema validation.


12. Quick Reference

Essential commands

Task Command
Install (production) istioctl install --set profile=default -y
Install (ambient) istioctl install --set profile=ambient -y
Enable injection kubectl label ns <ns> istio-injection=enabled
Enroll in ambient kubectl label ns <ns> istio.io/dataplane-mode=ambient
Manual inject istioctl kube-inject -f app.yaml | kubectl apply -f -
Analyze config istioctl analyze -n <ns>
Proxy sync status istioctl proxy-status
Inspect Envoy config istioctl proxy-config <type> <pod>.<ns>
Inspect ztunnel istioctl ztunnel-config workloads
Manage waypoints istioctl waypoint apply -n <ns> --enroll-namespace
Open a dashboard istioctl dashboard kiali
Diagnostic bundle istioctl bug-report
Versions istioctl version
Uninstall istioctl uninstall --purge -y

Reserved data-plane ports

Port Purpose
15000 Envoy admin interface
15001 Outbound traffic capture
15004 Pilot debug (via agent)
15006 Inbound traffic capture
15008 HBONE tunnel (ambient)
15020 Agent status + merged Prometheus metrics
15021 Envoy health checking
15053 DNS proxy
15090 Envoy Prometheus telemetry

Control-plane ports (istiod)

Port Purpose
8080 Discovery debug (HTTP)
15010 xDS (plaintext, debugging only)
15012 xDS + CA (secure, mTLS) — proxies connect here
15014 Control-plane monitoring/metrics
15017 Injection & validation webhook (HTTPS)

Key labels and annotations

Key Applied to Effect
istio-injection=enabled namespace Auto-inject sidecars.
istio.io/rev=<rev> namespace Pin to a control-plane revision.
sidecar.istio.io/inject: "false" pod Opt a pod out of injection.
istio.io/dataplane-mode=ambient namespace/pod Enroll into ambient mode.
istio.io/dataplane-mode=none namespace/pod Explicitly exclude from ambient.

Agent status endpoints (port 15020)

Path Purpose
/healthz/ready Proxy readiness probe.
/stats/prometheus, /metrics Merged Envoy + app metrics.
/quitquitquit Trigger graceful shutdown (localhost only).
/drain Begin connection draining (localhost only).
/app-health/<container>/{livez,readyz,startupz} Rewritten application probes.