TT Lab
Get started
Learn Learning paths Courses

Istio Field Lab

Is It Blocked Just Because There Is a Gateway?

Continue in TT Lab

In one line

The default for traffic leaving the mesh is pass to anywhere (ALLOW_ANY). There are four devices that narrow it — the Sidecar resource, which reduces the range the proxy knows about, REGISTRY_ONLY, which blocks unknown places, ServiceEntry, which puts outside destinations in the registry, and the egress gateway, which gathers the exit route in one place. The four block different things, and none of them alone blocks everything.

Why this was needed

A sidecar by default knows every service in the cluster. If there are thousands of services, every proxy holds thousands of clusters, and istiod pushes each change of a single service to everyone. And a destination that is not in the registry (an external address, a Pod IP) just flows out through the PassthroughCluster — with the mesh not knowing who is going where.

The security requirement runs in the opposite direction. Things like "only the payment service may go out to the card company's API" and "the only way out is one auditable place". For the mesh to help with that requirement, it first has to know the outside destinations by name, and then it has to gather the exit points into one.

How it works

The Sidecar resource — it decides what the proxies in this namespace know about.

egress:
  - hosts: ["./*", "istio-system/*"]   ← 같은 네임스페이스와 istio-system 만 안다
outboundTrafficPolicy:
  mode: REGISTRY_ONLY                  ← 모르는 곳은 BlackHoleCluster(502)

If you narrow the range, the proxy configuration gets smaller, and if you add REGISTRY_ONLY, what is outside the range is blocked. A blocked request is left in the access log as a 502 with the route name block_all.

ServiceEntry — it puts an outside destination in the registry. location: MESH_EXTERNAL means 'it is outside the mesh, so do not apply mTLS', and resolution: DNS means to resolve the endpoint name through DNS. But the host name itself (api.partner.test) is not in the cluster DNS. If you turn on the sidecar's DNS proxy (ISTIO_META_DNS_CAPTURE), the sidecar automatically assigns a virtual IP in the 240.240.0.0/16 range to that name and answers with it, and that value is also written in the ServiceEntry's status.addresses.

The egress gateway — it gathers the exit route in one place. A single VirtualService takes care of two segments.

Segment Match Where it sends
Sidecar → gateway gateways: [mesh] istio-egressgateway (mTLS)
Gateway → outside gateways: [partner-egress] The real destination

mTLS from the sidecar to the gateway is not applied by itself. You have to set the Gateway server to HTTPS and tls.mode: ISTIO_MUTUAL, and give ISTIO_MUTUAL and sni to the DestinationRule subset the sidecar uses when going to the gateway (the official Egress Gateways with TLS Origination doc uses the same pair). That DestinationRule is looked up in the order client namespace, then service namespace, then root namespace, so if you want several namespaces to use the same gateway, you put it on the gateway side (istio-system). When it is connected with mTLS like that, the gateway knows the identity of the workload that sent the request. So if you apply an authorization policy on the gateway, you can decide 'who can go out to this outside place' in one place.

What it cannot block. The Sidecar and REGISTRY_ONLY are only the configuration of that namespace's proxies. The proxies of other namespaces are still ALLOW_ANY, and a Pod without a sidecar does not know about it at all. The Istio docs state that an egress gateway alone cannot force all outside traffic to pass through it, and that you must block the paths outside the gateway with another device such as a Kubernetes network policy.

What it looks like in the field

"I turned on REGISTRY_ONLY and metric collection stopped." It was that the outside address the Pod was calling (a monitoring SaaS, the cloud metadata, and so on) was not in the registry. The order is to first count in the access log the requests going out through the PassthroughCluster before turning it on, and put them up as ServiceEntries.

"I built an egress gateway but the Pod IP shows up in the partner's firewall log." This is the case where the VirtualService's mesh side rule is missing or the host is different, so the sidecar went out directly without going through the gateway. The source seen by the receiving side is the most honest evidence.

"I blocked it at the gateway but some teams still get out." That team's namespace had no Sidecar configuration or had a Pod without a sidecar. The gateway blocks only requests that pass through it.

Official docs: Accessing External Services · Egress Gateways · Sidecar · DNS Proxying

What you will do in the next lab

You put an nginx acting as the partner API outside the mesh and first count how many things go anywhere by default. You narrow the range with the Sidecar, block with REGISTRY_ONLY, put up only the partner with a ServiceEntry, gather the route with the egress gateway, and confirm with the source the partner saw. Finally, you see that a route that bypasses the gateway remains in another namespace, and narrow the identities that can go out with the gateway's authorization policy.