diff --git a/calico-enterprise/compliance/istio/migrate-from-sidecar.mdx b/calico-enterprise/compliance/istio/migrate-from-sidecar.mdx new file mode 100644 index 0000000000..6084161f4d --- /dev/null +++ b/calico-enterprise/compliance/istio/migrate-from-sidecar.mdx @@ -0,0 +1,560 @@ +--- +description: Migrate an existing Istio sidecar mesh to the Calico-managed Istio Ambient Mode service mesh, one namespace at a time. Without Waypoints, your network policies need no rewrite. +--- + +# Migrate from Istio sidecar mode to Istio Ambient Mode + +If you already run Istio in sidecar mode, you can move to the version of Istio that $[prodname] bundles and manages, which runs in ambient mode. +This page describes the supported migration path: what to check before you start, how the cutover is sequenced, how to verify each namespace, and how to roll back. + +:::note + +Istio Ambient Mode is a tech preview feature. +Tech preview features are subject to significant changes before they become GA. + +::: + +## Why migrate + +Sidecar meshes put an Envoy proxy next to every pod. That proxy consumes memory and CPU per workload, has to be restarted with the application to pick up new configuration, and it terminates connections in a way that hides the original destination port from the host network. + +Istio Ambient Mode replaces per-pod sidecars with a per-node zTunnel proxy for Layer 4 mTLS, and optional Waypoint proxies for Layer 7 features. +On $[prodname], that comes with three additional benefits: + +* **Your network policies keep working.** $[prodname] ships an [enhanced zTunnel](about-istio-ambient.mdx#the-enhanced-ztunnel-proxy) that preserves the original destination port, so existing $[prodname] and Kubernetes network policies continue to match traffic exactly as they did before the traffic was encrypted. To make this work, $[prodname] sets DSCP 23 on the first packet of each new connection between two mesh pods. You can change the value with `dscpMark` in the `Istio` custom resource. In upstream Istio Ambient Mode, all mesh traffic appears as port 15008 and policies have to be rewritten. +* **The mesh lifecycle is managed for you.** The Tigera Operator installs and upgrades istiod, the Istio CNI plugin, and zTunnel, and CVEs are addressed on the regular $[prodname] patch release cadence. +* **Flow visibility is unchanged.** Because ports and workload identity are preserved, $[prodname] flow logs and the flow visualizations in the web console keep showing service-to-service traffic the way they did before you enabled mTLS. + +## What changes when you migrate + +| Sidecar mode | After migrating to Istio Ambient Mode | +| --- | --- | +| Envoy sidecar in every pod | zTunnel DaemonSet in `calico-system`, one proxy per node | +| Istio control plane in `istio-system`, self-managed | istiod in `calico-system`, installed and upgraded by the Tigera Operator | +| `VirtualService` | `HTTPRoute` (Gateway API), attached to a Waypoint | +| `DestinationRule` traffic policy (connection pool, outlier detection, TLS) | No change. The Waypoint applies it | +| `DestinationRule` subsets used for routing | One Kubernetes `Service` per version, used as a `backendRef` in the `HTTPRoute` | +| `AuthorizationPolicy` with L4 rules only | No change. zTunnel enforces these directly | +| `AuthorizationPolicy` with L7 rules | Must target a Waypoint with `targetRefs` instead of selecting pods | +| `RequestAuthentication` | Must target a Waypoint with `targetRefs` | +| `EnvoyFilter` | Not supported on Waypoints | +| `Gateway` (ingress) | No change | +| `PeerAuthentication` with `mode: DISABLE` | Not supported. Remove before migrating | +| $[prodname] network policy | No change, as long as you do not deploy Waypoints. See [Network policy during and after migration](#network-policy-during-and-after-migration) | +| DSCP field on new connections between mesh pods | Set to 23 by $[prodname]. Change it with `dscpMark` in the `Istio` custom resource | + +## Before you begin + +### Supported starting point + +This procedure assumes: + +* $[prodname] is installed and managed by the Tigera Operator. +* Istio is installed in sidecar mode and you manage it yourself, with Helm or `istioctl`. +* Your workloads are pods. Virtual machine workloads cannot join an ambient mesh. + +### Unsupported configurations + +Migration is blocked if your mesh uses any of the following. Resolve these before you start. + +* Virtual machine workloads in the mesh. +* SPIRE as the certificate provider. +* `PeerAuthentication` resources with `mode: DISABLE`. +* Primary-remote multicluster topologies. + +Istio Ambient Mode on $[prodname] also has its own limitations, which apply after migration: + +* [Application layer network policies](../../network-policy/application-layer-policies/alp.mdx) are not compatible with the Istio service mesh. +* [Workload-based web application firewalls](../../threat/web-application-firewall.mdx) are not compatible with Istio Ambient Mode. +* Clusters that are part of a [cluster mesh](../../multicluster/index.mdx) are not supported. +* Connect-time load balancing is not compatible with Istio Ambient Mode. +* Destination ports are preserved only when Istio is deployed without Waypoint. If you deploy Waypoint, traffic through the Waypoint shows port 15008 as its destination port. + +### Layer 7 policy causes a gap in enforcement + +:::warning + +If your mesh enforces Layer 7 `AuthorizationPolicy` rules, there is no zero-downtime migration path. + +While a namespace is partly migrated, traffic that originates from a workload that still has a sidecar is sent straight to the destination zTunnel and bypasses the Waypoint, so Layer 7 rules attached to that Waypoint are not enforced for it. +If you need continuous Layer 7 enforcement, migrate the affected namespaces inside a maintenance window. + +::: + +Layer 4 enforcement is not affected. zTunnel enforces L4 `AuthorizationPolicy` rules for every migrated workload, and $[prodname] network policy is enforced throughout. + +### Inventory your mesh + +1. Record the Istio version and the namespaces that have injection enabled: + + ```bash + istioctl version + kubectl get namespace -L istio-injection -L istio.io/rev + ``` + +1. Back up every Istio resource you have. You need this to roll back. + + ```bash + kubectl get virtualservices,destinationrules,authorizationpolicies,peerauthentications,requestauthentications,\ + telemetries,sidecars,serviceentries,envoyfilters,wasmplugins,proxyconfigs,workloadentries,workloadgroups,\ + gateways.networking.istio.io \ + --all-namespaces -o yaml > istio-config-backup.yaml + ``` + + If your cluster has the Gateway API CRDs, back up those resources too: + + ```bash + kubectl get gateways.gateway.networking.k8s.io,httproutes \ + --all-namespaces -o yaml > gateway-api-backup.yaml + ``` + + Write `gateways.networking.istio.io` in full. On a cluster that has the Gateway API CRDs, a plain `gateway` returns Gateway API resources instead of Istio ones. + Check that the backup files are not empty. + +1. Find the policies that need a Waypoint. Any `AuthorizationPolicy` that matches on `paths`, `methods`, `hosts`, `requestPrincipals`, or a `when` key that starts with `request.` (headers and JWT claims) is a Layer 7 policy: + + ```bash + kubectl get authorizationpolicy --all-namespaces -o yaml | grep -i -E 'paths|methods|hosts|requestPrincipals|key: request\.' + ``` + + A `when` condition on `source.ip`, `source.namespace`, `source.principal`, `destination.ip`, or `destination.port` is Layer 4. zTunnel enforces those without a Waypoint. + +1. Confirm that no `PeerAuthentication` resource disables mTLS: + + ```bash + kubectl get peerauthentication --all-namespaces -o yaml | grep -B5 'mode: DISABLE' + ``` + +1. Confirm that the Istio fields in your `FelixConfiguration` are empty. The Tigera Operator sets them itself. If you set either one by hand, the install stops with `felixconfig IstioAmbientMode modified by user` or `felixconfig IstioDSCPMark modified by user`. + + ```bash + kubectl get felixconfiguration default -o jsonpath='{.spec.istioAmbientMode}{"\n"}{.spec.istioDSCPMark}{"\n"}' + ``` + + Both lines must be empty. If they are not, remove the fields before Step 2. + +:::note + +Waypoints and `HTTPRoute` need the Gateway API CRDs. +You do not need to install them yourself: the Tigera Operator creates them when you create the `Istio` custom resource. +If your cluster already has them, the operator leaves them in place. + +::: + +## Plan your cutover + +The Tigera Operator installs istiod, the Istio CNI plugin, and zTunnel into the `calico-system` namespace. +It cannot run alongside a self-managed Istio control plane. +Both installations use a validating webhook named `istiod-default-validator`, both add an Istio CNI plugin to the same CNI configuration on every node, and both control planes manage the same built-in `GatewayClass` resources. + +**You must remove your self-managed Istio control plane before you create the `Istio` custom resource.** + +The operator creates the Istio CRDs only if they do not exist yet. +It does not change CRDs that your self-managed installation created. + +### Keep your root certificate authority + +If you gave your self-managed Istio your own certificate authority, it is stored in the `cacerts` secret in `istio-system`. +The $[prodname]-managed istiod reads a `cacerts` secret from `calico-system` instead. +Copy yours across before Step 1: + +```bash +kubectl get secret cacerts -n istio-system -o json \ + | jq 'del(.metadata.resourceVersion,.metadata.uid,.metadata.creationTimestamp,.metadata.managedFields,.metadata.ownerReferences) | .metadata.namespace="calico-system"' \ + | kubectl apply -f - +kubectl get secret cacerts -n calico-system +``` + +With the same root, sidecars and zTunnel trust each other's certificates, so migrated and not-yet-migrated workloads keep talking over mTLS during the migration. + +If `istio-system` has no `cacerts` secret, your self-managed istiod generated its own root. +The $[prodname]-managed istiod generates a new one, and the two roots do not trust each other. + +:::warning + +Copy the secret before you create the `Istio` custom resource. +Changing the root under a running $[prodname]-managed istiod splits the mesh: existing pods keep working, but new pods get no certificate and zTunnel loses its connection to istiod. + +::: + +### Move your mesh-wide policies + +A policy in Istio's root namespace applies to the whole mesh. +Your self-managed Istio uses `istio-system` as its root namespace. The $[prodname]-managed Istio uses `calico-system`. + +After Step 2, policies in `istio-system` apply only to `istio-system`. They are not deleted, and nothing reports the change. Some of them fail open: + +* A mesh-wide `AuthorizationPolicy` that denies traffic stops denying it in your other namespaces. +* A mesh-wide `AuthorizationPolicy` that allows traffic no longer denies everything else by default. +* A mesh-wide `PeerAuthentication` with `mode: STRICT` stops applying. Namespaces without their own `PeerAuthentication` accept plaintext. + +List the policies in your root namespace: + +```bash +kubectl get authorizationpolicy,peerauthentication,requestauthentication,telemetry,wasmplugin,envoyfilter -n istio-system +``` + +Before Step 2, re-create each one in `calico-system`. +Until Step 2, `calico-system` is not the root namespace and has no meshed workloads, so the copies have no effect yet. + +### Check your mesh config + +Your self-managed Istio keeps its mesh-wide settings in the `mesh` key of the `istio` config map: + +```bash +kubectl get configmap istio -n istio-system -o jsonpath='{.data.mesh}' +``` + +The `Istio` custom resource has no field for these settings. +The $[prodname]-managed istiod starts with the Istio defaults, and your settings are not carried over. +Compare every key in the output against the defaults. These cause the most trouble: + +* `trustDomain`: every workload identity changes, and `AuthorizationPolicy` rules that name a principal deny traffic they used to allow. +* `outboundTrafficPolicy: REGISTRY_ONLY`: goes back to `ALLOW_ANY`, so workloads can reach external hosts that were blocked. +* `extensionProviders`: `AuthorizationPolicy` resources with `action: CUSTOM` lose their external authorization provider. +* `accessLogFile`: mesh access logs stop. Traffic through a Waypoint still shows up in $[prodname] L7 logs. + +If you depend on any of these settings, resolve that before you migrate. + +These constraints shape the two supported cutover patterns. + +### Pattern 1: single maintenance window (recommended) + +Remove the self-managed control plane, install the $[prodname]-managed one, and migrate every namespace in one window. +This is the recommended pattern for most clusters, because sidecar and migrated workloads only have to talk to each other for the length of the window. +If you could not copy a `cacerts` secret, traffic between them fails TLS verification until the last namespace is migrated. + +Choose this pattern if your cluster has a small number of meshed namespaces, or if you enforce Layer 7 policy. + +### Pattern 2: phased, namespace by namespace + +Remove the self-managed control plane, install the $[prodname]-managed one, then migrate namespaces in batches over a longer period. + +Pods that still have sidecars keep forwarding traffic using their cached configuration, but be aware of three constraints: + +* **Restarted pods lose their sidecar.** The $[prodname]-managed istiod does not inject sidecars. A pod that restarts in a namespace you have not migrated yet, for example after an eviction or a scale-up, starts with no sidecar and outside the ambient mesh. Its traffic is plaintext, and workloads that require `STRICT` mTLS refuse it. + +* **Certificates are not rotated.** After the self-managed istiod is gone, sidecars can no longer refresh their workload certificates. Istio's default certificate lifetime is 24 hours, so plan to finish the migration well inside that window. +* **mTLS between sidecar and migrated workloads fails without a shared root.** If you did not copy a `cacerts` secret, sidecars trust the root CA of your old control plane, and zTunnel presents a certificate from the new one. Traffic between a not-yet-migrated workload and a migrated workload fails TLS verification unless you temporarily disable mTLS for those service pairs with a `DestinationRule`. + +Choose this pattern only if you copied your `cacerts` secret, or if you can group namespaces so that services that talk to each other migrate together. + +## Network policy during and after migration + +This is the part of the migration that does not change, and it is worth verifying rather than assuming. + +* **Without Waypoints**, the enhanced zTunnel preserves the original destination port. Your existing $[prodname] and Kubernetes network policies match the same traffic before and after migration. No rewrite, no exception for port 15008. +* **With Waypoints**, traffic that goes through a Waypoint reports port 15008 as its destination port. Policies that select those workloads by destination port need to be updated to allow 15008. +* **Do not label $[prodname] namespaces or pods into the mesh.** Labeling $[prodname] components can interrupt cluster networking. To secure $[prodname] components, see [Secure Calico component communications](../../operations/comms/index.mdx). + +Before you start, snapshot the policies that apply to a representative workload so you can compare after the cutover: + +```bash +kubectl get networkpolicies.projectcalico.org,globalnetworkpolicies.projectcalico.org \ + --all-namespaces -o yaml > calico-policy-snapshot.yaml +``` + +## Step 1: Remove the self-managed Istio control plane + +Remove the control plane components only. Leave the injected sidecars and your Istio configuration resources (`VirtualService`, `AuthorizationPolicy`, and so on) in place for now: existing pods continue to serve traffic with their cached configuration, and you still need those resources for rollback. +From this step on, no new pod in any namespace gets a sidecar. + +1. Remove sidecar injection from the namespaces you are about to migrate, so that no new pod comes up with a sidecar: + + ```bash + kubectl label namespace istio-injection- + ``` + + If you use revision labels: + + ```bash + kubectl label namespace istio.io/rev- + ``` + +1. Uninstall the self-managed control plane, including the Istio CNI plugin. Keep the Istio CRDs: they hold your `VirtualService`, `AuthorizationPolicy`, and other resources, and your rollback path needs them. + + With Helm, keep the `istio-base` release: + + ```bash + helm uninstall istio-cni -n istio-system + helm uninstall istiod -n istio-system + ``` + + With `istioctl`, pass the options you installed with: + + ```bash + istioctl uninstall + ``` + + :::warning + Do not use `istioctl uninstall --purge`. It removes the Istio CRDs, and every Istio resource in the cluster is deleted with them. Keep `istio-base` installed until you are sure you will not roll back. + ::: + +1. Confirm that no Istio control plane components or CNI plugin remain: + + ```bash + kubectl get pods -n istio-system + kubectl get daemonset --all-namespaces | grep istio + ``` + +## Step 2: Install the $[prodname]-managed Istio + +1. Apply the `Istio` custom resource: + + ```bash + cat < + ``` + +1. Verify that it is ready: + + ```bash + kubectl get gateway waypoint -n + ``` + + The `READY` column must show `True`. + +1. Update your $[prodname] network policies to allow traffic to port 15008 for the workloads behind the Waypoint. See [Network policy during and after migration](#network-policy-during-and-after-migration). + +By default, $[prodname] adds an `l7-collector` container to each Waypoint pod, so traffic through a Waypoint shows up in $[prodname] L7 logs. +To turn this off, set `waypointLogging: Disabled` in the `Istio` custom resource. +See [Collect L7 logs using the Waypoint collector](../../observability/elastic/l7/enable-waypoint-collector.mdx). + +## Step 4: Enable ambient mode, namespace by namespace + +Follow this order. Doing it out of order can leave traffic handled by neither a sidecar nor zTunnel. + +1. **Attach workloads to the Waypoint**, if you deployed one: + + ```bash + kubectl label namespace istio.io/use-waypoint=waypoint + ``` + + To scope a Waypoint to a single service instead: + + ```bash + kubectl label service -n istio.io/use-waypoint=waypoint + ``` + +1. **Add the namespace to the mesh**: + + ```bash + kubectl label namespace istio.io/dataplane-mode=ambient + ``` + + The Istio CNI plugin redirects new and restarted pods in this namespace through zTunnel. Pods that still have a sidecar continue to use it: a sidecar takes precedence over ambient mode. + +1. **Confirm that sidecar injection is off** for the namespace. You did this in Step 1, but verify, because a re-injected sidecar silently keeps the workload out of ambient mode: + + ```bash + kubectl get namespace -L istio-injection -L istio.io/rev + ``` + +1. **Restart the workloads** to drop the sidecars: + + ```bash + kubectl rollout restart deployment -n + kubectl rollout status deployment -n + ``` + +1. **Remove the Layer 7 policies that only a sidecar could enforce.** Do this immediately after the restart, before you validate. + + :::warning + + Once the sidecars are gone, zTunnel enforces the remaining `AuthorizationPolicy` resources, but it only understands Layer 4 attributes. A policy with Layer 7 rules does not get ignored. It fails safe by becoming a `DENY` policy. An `ALLOW` policy with Layer 7 rules denies the traffic it used to allow, and a `DENY` policy with Layer 7 rules can deny more traffic than you intended. + + ::: + + Delete the selector-based policies that contain Layer 7 rules, which you have already replaced with Waypoint-targeted equivalents: + + ```bash + kubectl delete authorizationpolicy -n + ``` + + Delete the `VirtualService` resources you replaced with `HTTPRoute`: + + ```bash + kubectl delete virtualservice -n + ``` + + Keep your `DestinationRule` resources. The Waypoint still applies their traffic policies. Delete one only if it defines nothing but subsets that you replaced with per-version services: + + ```bash + kubectl delete destinationrule -n + ``` + + Keep every `AuthorizationPolicy` that uses only Layer 4 rules. zTunnel enforces those correctly. + +1. **Validate the namespace** before you move to the next one. See [Verify the migration](#verify-the-migration). + +Repeat for each namespace. Namespaces you have not labeled are unaffected, subject to the certificate and mTLS constraints described in [Pattern 2](#pattern-2-phased-namespace-by-namespace). + +## Verify the migration + +1. Pods no longer have a sidecar container. The ready count drops by one, for example from `2/2` to `1/1`: + + ```bash + kubectl get pods -n + ``` + +1. The workloads are known to zTunnel: + + ```bash + istioctl ztunnel-config workloads -n calico-system | grep + ``` + + The protocol column shows `HBONE` for migrated workloads. + +1. Your $[prodname] policies still match the same traffic. Because the enhanced zTunnel preserves the original destination port, flows for a migrated workload should appear with their application ports, not 15008. + + In the web console, select **Service Graph**, **Default**, and double-click the namespace. The flow logs panel at the bottom filters to that namespace. See [Network visualization](../../observability/visualize-traffic.mdx). + + In Kibana, search the `tigera_secure_ee_flows*` index for `dest_namespace: ` and check the `dest_port` field. See [Kibana dashboards and logs](../../observability/kibana.mdx). + + Compare the policies in each flow's `policies` field against `calico-policy-snapshot.yaml`. + +1. Application traffic behaves as before. Test the Layer 7 behavior you rely on: header-based routing, path restrictions, JWT validation. + +## Roll back + +Roll back in the reverse order of the step you completed. + +:::note + +The $[prodname]-managed istiod does not inject sidecars. +Re-adding an injection label brings sidecars back only while a self-managed control plane is running. +If you have completed Step 1, first [go back to your self-managed control plane](#go-back-to-your-self-managed-control-plane), then re-add the labels and restart the workloads. + +::: + +| Last completed step | Rollback | +| --- | --- | +| Waypoint attached | `kubectl label namespace istio.io/use-waypoint-` | +| Ambient mode enabled | `kubectl label namespace istio.io/dataplane-mode-` | +| Sidecar injection removed | Re-add the label you recorded in [Inventory your mesh](#inventory-your-mesh): `kubectl label namespace istio-injection=enabled`, or `kubectl label namespace istio.io/rev=` | +| Workloads restarted | Re-add the injection label, then `kubectl rollout restart deployment -n ` | +| Old policies deleted | `kubectl apply -f istio-config-backup.yaml` | +| $[prodname]-managed Istio installed | See [Go back to your self-managed control plane](#go-back-to-your-self-managed-control-plane) | + +After a rollback that re-injects sidecars, confirm that pods show `2/2` containers and that traffic flows before you continue. + +:::warning + +Applying the full `istio-config-backup.yaml` restores your original resources, but it also overwrites any ambient resources you created during the migration that share a name with a backed-up resource. Delete the ambient resources first, or apply individual resources from the backup. + +::: + +### Go back to your self-managed control plane + +1. Delete the `Istio` custom resource: + + ```bash + kubectl delete istio.operator.tigera.io default + ``` + +1. Wait until nothing of it is left. The two control planes must never run at the same time. + + ```bash + kubectl get pods -n calico-system -l 'app in (istiod,ztunnel,istio-cni-node)' + kubectl get felixconfiguration default -o jsonpath='{.spec.istioAmbientMode}{"\n"}' + ``` + + Both commands must return nothing. + +1. Reinstall your self-managed control plane with the same version and options you used before. + With Helm, run `helm upgrade --install` for `istio-base` first. Deleting the `Istio` custom resource also deleted the `istiod-default-validator` webhook, and `istio-base` puts it back. + +## What changes in observability after migration + +* **Metrics.** In sidecar mode, metrics are reported with `reporter="source"` and `reporter="destination"`. In ambient mode they are reported with `reporter="source"` from zTunnel and `reporter="waypoint"`. Update dashboards and alerting rules that filter on the reporter label. +* **Metrics merging.** Sidecar mode can merge application metrics into the proxy's metrics endpoint. Ambient mode does not. Configure Prometheus to scrape zTunnel, Waypoint, and application pods as separate targets. +* **Tracing.** Sidecar mode produces two spans per hop. Ambient mode produces one span per Waypoint. Adjust trace-based SLOs. +* **`istioctl proxy-status`** does not list ztunnel workloads. Use `istioctl ztunnel-config workloads -n calico-system` instead. +* **$[prodname] flow logs** are unchanged, which is the point of the enhanced zTunnel: you keep the same service-level view you had before the mesh encrypted the traffic. + +## Troubleshooting + +Check whether the Istio pods are deployed: + +```bash +kubectl get pods -n calico-system | grep 'istio\|ztunnel' +``` + +Check whether the Istio CRDs are deployed: + +```bash +kubectl get crd | grep istio +``` + +Check which pods and namespaces are in the mesh: + +```bash +istioctl ztunnel-config workloads -n calico-system +``` + +Check for errors logged by the zTunnel component: + +```bash +ZTUNNEL_PODS=$(kubectl get pod -n calico-system \ + -l app.kubernetes.io/name=ztunnel \ + -o jsonpath='{.items[*].metadata.name}') + +for P in $ZTUNNEL_PODS; do + echo "--- Checking logs for pod: $P ---" + kubectl logs $P -n calico-system 2>/dev/null | grep -i error +done +``` + +**A workload was labeled but never joined the mesh.** The pod most likely still has a sidecar, which takes precedence. Confirm that injection is removed from the namespace and restart the workload. + +**Traffic fails between a migrated and a not-yet-migrated namespace.** The two workloads trust different certificate authorities, because the `cacerts` secret was not copied to `calico-system`. Finish migrating both namespaces, or temporarily disable mTLS for that service pair with a `DestinationRule`. + +**A migrated workload is denied all traffic.** Check for an `AuthorizationPolicy` with Layer 7 rules that still selects the workload. zTunnel treats it as a `DENY` policy. Delete the policy and re-create it against a Waypoint with `targetRefs`. + +## Additional resources + +* [Istio Ambient Mode](about-istio-ambient.mdx) +* [Deploy Istio Ambient Mode on your cluster](deploy-istio-ambient.mdx) +* [Overview of Istio ambient mode](https://istio.io/latest/docs/ambient/overview/) +* [Ambient and Kubernetes NetworkPolicy](https://istio.io/latest/docs/ambient/usage/networkpolicy/) +* [Configuration options](../../reference/installation/api) diff --git a/sidebars-calico-enterprise.js b/sidebars-calico-enterprise.js index de01d7ebe9..7825a47390 100644 --- a/sidebars-calico-enterprise.js +++ b/sidebars-calico-enterprise.js @@ -529,6 +529,7 @@ module.exports = { items: [ 'compliance/istio/about-istio-ambient', 'compliance/istio/deploy-istio-ambient', + 'compliance/istio/migrate-from-sidecar', ], }, 'compliance/encrypt-cluster-pod-traffic',