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 optionalwaypointproxies. 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 versionreports 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/2is the signal that injection worked: container one is your application, container two is theistio-proxy(Envoy) sidecar. If you see1/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
--purgeremoves 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-injectis also useful to see exactly what gets added to your pod — pipe it to a pager instead ofkubectl applyto 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 prefixedISTIOCTL_(for example,ISTIOCTL_ISTIONAMESPACE=custom-system). Runistioctl optionsto 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 authzreminds you to useistioctl experimental authz. Useistioctl <command> --helpfor 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 analyzeuses 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 secretis 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
DestinationRulesubsets before aVirtualServicereferences them, or requests to the unknown subset will fail.istioctl analyzecatches 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
STRICTonly after confirming all clients are in the mesh. InSTRICTmode, plaintext requests from non-mesh clients are rejected. Start with the defaultPERMISSIVEmode 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, and15090are 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-nodeztunnel(L4) plus optionalwaypointproxies (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
STRICTmTLS.
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. |