Enable ambient mode
Enable ambient mode one namespace at a time. This lets you validate each namespace before moving on, and roll back a single namespace if something goes wrong.
Migrating a namespace
Ordering requirements
Failing to follow this sequence can result in traffic being processed by neither sidecar nor ztunnel, causing disruption in your workloads.
Step 1: Activate waypoints
Activate waypoints deployed in the previous step
by adding the istio.io/use-waypoint label.
To activate a waypoint for an entire namespace:
$ kubectl label namespace <namespace> istio.io/use-waypoint=waypointTo activate a waypoint for a specific Service only:
$ kubectl label service <service-name> -n <namespace> istio.io/use-waypoint=waypointVerify the waypoint is ready:
$ kubectl get gateway waypoint -n <namespace>The READY column should show True.
Step 2: Enable ambient mode for the namespace
Add the istio.io/dataplane-mode=ambient label to the namespace. This tells the CNI
plugin that new and restarted pods in this namespace should use ztunnel instead of
(or alongside) a sidecar:
$ kubectl label namespace <namespace> istio.io/dataplane-mode=ambientVerify that the namespace is now enrolled in the ambient mesh:
$ istioctl ztunnel-config workloads -n istio-system | grep <namespace>Workloads in the namespace will appear with HBONE as their protocol. The pods still
have their sidecars at this point. The sidecar takes precedence over ztunnel for pods
that have both.
Step 3: Remove sidecar injection
Remove the sidecar injection label from the namespace:
If you use the default injection label:
$ kubectl label namespace <namespace> istio-injection-If you use a revision label:
$ kubectl label namespace <namespace> istio.io/rev-Step 4: Restart pods
Restart the workloads in the namespace. As pods restart, they will come up without sidecar containers and will use ztunnel (and waypoint, if configured) instead:
$ kubectl rollout restart deployment -n <namespace>
$ kubectl rollout status deployment -n <namespace>Step 5: Remove old sidecar policies
Delete any AuthorizationPolicy resources that used a workload selector with L7 rules,
now that they have been replaced by targetRefs-based equivalents:
$ kubectl delete authorizationpolicy <sidecar-policy-name> -n <namespace>Also remove VirtualService and DestinationRule resources replaced by HTTPRoute:
$ kubectl delete virtualservice <name> -n <namespace>
$ kubectl delete destinationrule <name> -n <namespace>L4 AuthorizationPolicy resources using selector (with no L7 rules) are safe to keep,
ztunnel enforces them correctly.
Step 6: Validate
Verify that pods are running without sidecar containers:
$ kubectl get pods -n <namespace>Confirm that ztunnel is managing the workloads:
$ istioctl ztunnel-config workloads -n istio-system | grep <namespace>If you deployed waypoints, verify that L7 policy and routing rules are being enforced by
testing the specific behaviors (header-based routing, HTTP method restrictions, etc.) that
your HTTPRoute and AuthorizationPolicy resources define.
Repeat for each namespace
Repeat the Migrating a namespace steps for each namespace you
want to migrate. Namespaces not labeled with istio.io/dataplane-mode=ambient continue to
use their sidecars and are not affected.
Rollback
Each step is independently reversible. Use the rollback procedure that matches how far you have progressed:
| Step | Rollback action |
|---|---|
| After Step 1 (waypoints activated) | kubectl label namespace <ns> istio.io/use-waypoint- |
| After Step 2 (ambient enabled) | kubectl label namespace <ns> istio.io/dataplane-mode- |
| After Step 3 (injection removed) | Re-add injection label: kubectl label namespace <ns> istio-injection=enabled |
| After Step 4 (pods restarted) | Re-add injection label, then kubectl rollout restart deployment -n <ns> |
| After Step 5 (old policies deleted) | kubectl apply -f istio-config-backup.yaml to restore from backup |
After any rollback that involves pod restarts, verify that pods show 2/2 containers (indicating the sidecar has been re-injected) and confirm traffic is flowing before proceeding.
Post-migration observability changes
After migrating to ambient mode, be aware of the following changes to telemetry:
Metrics: In sidecar mode, metrics are reported with reporter="source" and
reporter="destination". In ambient mode, metrics from ztunnel use reporter="source",
while metrics from waypoint proxies use reporter="waypoint". Update any dashboards or
alerting rules that rely on the reporter label.
Metrics merging: In sidecar mode, the proxy agent supports
metrics merging, which
combines Istio and application metrics into a single scrape target using the standard
prometheus.io annotations. This feature is not available in ambient mode. After
migration, you must configure Prometheus to scrape Istio components (ztunnel and waypoint
pods) and your application pods as separate targets. Update any PodMonitor or
ServiceMonitor resources that relied on a single merged endpoint.
Tracing: In sidecar mode, each hop generates two spans (one from the source sidecar, one from the destination sidecar). In ambient mode with waypoints, one span is generated per waypoint. Update trace-based SLOs accordingly.
istioctl proxy-status: This command does not show ztunnel workloads. Use
istioctl ztunnel-config workloads instead to inspect ambient proxy state.
For more information, see: