Two Doors Need Two Guards
In one line
The door into the mesh (the ingress gateway) is a standalone Envoy, not a sidecar. In Istio there are two ways to open that door — the Istio Gateway, which picks a gateway that is already running and layers configuration on it, and the Kubernetes Gateway API, which stands up a new gateway from a single Gateway resource.
Why this was needed
A sidecar handles traffic going out of and coming into a Pod. A request from a user outside the cluster has to be received somewhere that is not any Pod's sidecar, and there you have to terminate TLS, split by host name, and block strange paths. The Kubernetes Ingress resource was too limited in expressiveness for that job — header conditions, weights, and TLS modes were all different annotations for each controller.
Istio first solved this problem with its own API (Gateway + VirtualService), and Kubernetes gathered that experience to make the vendor-neutral Gateway API. The Istio docs state that they will make the Gateway API the default traffic management API going forward. So today both approaches are used together, and it is common for two doors to appear in the same mesh.
How it works
Istio Gateway — it picks a gateway and decides what to receive.
Gateway mall-gw selector: istio=ingressgateway ← 이미 떠 있는 파드를 고른다
servers: 80 HTTP mall.example.com
443 HTTPS mall.example.com credentialName: mall-cred
VirtualService mall-ingress gateways: [mall-gw] ← 어디로 보낼지는 여기서
With only a Gateway, the gateway receives but does not know where to send, so it gives a 404. The two are connected only when a VirtualService writes that name in gateways.
TLS is received through SDS. credentialName is not a file path but a Secret name. istiod reads that Secret and pushes it down to the gateway Envoy through SDS, so even if you swap the certificate you do not restart the gateway. In exchange, the Secret must be in the same namespace as the gateway Pod.
Gateway API — the Gateway stands up the gateway.
| Istio Gateway | Gateway API Gateway | |
|---|---|---|
| Gateway Pod | Picks a pre-installed one with a selector | Creates a <이름>-istio Deployment and Service for each Gateway (the placeholder is the name) |
| Where it stands | Usually istio-system | The namespace where the Gateway is |
| Routing | VirtualService (gateways:) |
HTTPRoute (parentRefs:) |
| Fine tuning | IstioOperator and Helm values | The ConfigMap of infrastructure.parametersRef |
That it stands up the gateway by itself means each team can separately scale its own door up and down. The Pods increase by that much, and above all you have to apply policies to each door separately.
Authorization policies attach to workloads too. A gateway is an Envoy workload, so you can attach an AuthorizationPolicy to it with a selector, and a request blocked there does not enter the mesh. But if the selector is istio: ingressgateway, it is not applied to a gateway newly stood up by the Gateway API.
What it looks like in the field
"I created a Gateway but it does not become Programmed." This happens when the automatically deployed Service cannot get a LoadBalancer address. In the cloud it is often a load balancer quota, and on-premises it is often that there is no LB implementation. In this VM's k3s, another gateway already holds port 80, so the new Service stays at <pending>.
"I changed the certificate but I see the old certificate." You created the Secret in another namespace or the name differs from credentialName. If you look at the certificate the gateway actually received with istioctl proxy-config secret, it is sorted out right away.
"I blocked the admin path but it still gets in through the new gateway." This is the case where you opened a new door without moving the guard along with it. It is why, when you add a gateway, you must also review the authorization policy's selector (or targetRefs).
Official docs: Ingress Gateways · Secure Gateways · Kubernetes Gateway API · Authorization on ingress gateways
What you will do in the next lab
You put two copies of an app on a real mesh inside the VM (k3s + Istio 1.31.0), open the HTTP and HTTPS doors with the Istio Gateway, and then stand up a second door with the Gateway API and split traffic by header and weight. You compare where the two gateways stand, and confirm with status codes that the /admin block you put on the first door is not applied to the second door.