Every platform architect migrating to Istio makes the exact same configuration mistake.
They install Istio, read the legacy manuals, and start littering their repositories with VirtualService and Gateway Custom Resource Definitions (CRDs). They assume that because these components were built by the Istio team, they are the optimal way to manage edge and mesh ingress.
They are wrong. They are building a very comfortable cage of vendor lock-in.
The legacy Istio routing spec is officially legacy plumbing. The cloud-native ecosystem has unified around the Kubernetes Gateway API, and Istio’s implementation of this spec is now a first-class citizen. If you are still letting application developers write Istio-specific CRDs to handle simple path matching, header manipulation, or canary splits, you are generating future migration tech debt.
Here is the architectural reality of running Istio entirely through the standardized Kubernetes Gateway API, the precise declarative pattern required to decouple infrastructure from applications, and the exact manifests to back it up.
The classic Istio ingress deployment forces a rigid model: you spin up an istio-ingressgateway deployment, back it with a monolithic load balancer, and let operations and development fight over who owns the shared VirtualService routing table.
The Kubernetes Gateway API breaks this apart by recognizing three distinct roles:
Gateway resource, provisioning the compute and allocating external IP/TLS footprints.HTTPRoute resources, binding applications to exposed gateway ports without needing cluster-level network permissions.When you apply a standardized Gateway resource targeting the istio GatewayClass, the Istio control plane (istiod) watches this spec and automatically provisions the underlying Envoy deployment and service infrastructure. You no longer manually manage ingress gateway pod specs or daemonsets.
Here is the exact production-grade structure required to implement a zero-vendor-lock-in routing layer using Istio and the standardized Gateway API spec.
This manifest configures a shared edge gateway infrastructure, automatically telling istiod to spin up the necessary proxy pods.
The application team manages their routing inside their own isolated namespace (payments). They reference the parent infrastructure gateway across namespace lines, completely unaware that Istio is the underlying engine processing the request.
Platform teams adopting this multi-namespace approach often watch their HTTPRoute resources sit in a perpetual Admitted: False state.
By default, Istio's controller enforces strict namespace boundaries. If your application developers try to attach an HTTPRoute in the payments namespace to a Gateway sitting in the istio-ingress namespace, it will fail silently unless the infrastructure operator explicitly opens the gate using the allowedRoutes property.
Always ensure the Gateway listener includes an explicit namespace Selector match block. Without it, the cross-namespace attachment handshake fails, and your developers will waste hours debugging a valid HTTPRoute spec that refuses to bind.
Migrating to Istio shouldn't mean binding your application architecture to Istio-specific APIs. By adopting the Kubernetes Gateway API standard, you achieve complete vendor portability. If you ever need to swap Istio out for Cilium or Envoy Gateway down the road, your application team's HTTPRoute manifests don't change by a single line of code.
You preserve operational sanity, drop the custom engine debt, and keep your exit strategy entirely intact.
------
NDLR;
Creating a standard Kubernetes Gateway resource with gatewayClassName: istio automatically causes istiod to deploy, configure, and manage the underlying engine pods and load-balancer services. This replaces the legacy step of manually compiling your own ingress controller helm charts.
Official Sources:
<Gateway name>-<GatewayClass name>) and take over proxy lifecycle management. Refer to the Istio Gateway API Task SheetCross-Namespace Route Attachment Permissions (allowedRoutes)
By default, a Gateway rejects connection handshakes from routes defined in separate namespaces. Operators must leverage the allowedRoutes.namespaces.from: Selector schema block to open cross-namespace boundaries securely.
Official Sources:
Moving from vendor-locked VirtualService properties to standardized HTTPRoute formatting, and the requirement of deploying Standard-channel CRDs using server-side apply boundaries on modern Kubernetes engines (like K8s 1.35).
Official Sources:
Kubernetes Services & Networking Conceptual Model: Documentation defining the three organizational roles (Infrastructure Provider, Cluster Operator, Application Developer) driving the portable framework design. Refer to the Kubernetes Core Networking Concepts