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=waypoint

To activate a waypoint for a specific Service only:

$ kubectl label service <service-name> -n <namespace> istio.io/use-waypoint=waypoint

Verify 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=ambient

Verify 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:

StepRollback 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:

Was this information useful?
Do you have any suggestions for improvement?

Thanks for your feedback!