Istio handles mTLS beautifully when you're routing traffic through Kubernetes services. You flip on strict mode, everything keeps working, and you go home happy. But the moment you need to address pods directly by IP -- say, for cross-cluster communication over a flat network -- things get weird. Strict mTLS breaks in ways that are surprisingly hard to debug.
This post walks through that exact scenario: how to get Istio's mTLS working when your traffic targets pod IPs instead of service names.
When would you need this?
If you're addressing pods by IP rather than by service name, this post is for you. Common scenarios:
- Multi-cluster with a flat network -- pods are routable by IP across clusters, but you don't have shared DNS or a common service registry. You can't just
curl my-service.namespace because that service doesn't exist in the calling cluster.
- ServiceEntry + WorkloadEntry patterns -- you're grouping remote pod IPs under a logical hostname using Istio primitives, essentially building your own cross-cluster service discovery.
- Migrating workloads off-cluster -- VMs or legacy pods that need to participate in the mesh but aren't behind a Kubernetes Service.
In all these cases, Istio doesn't have a native Service object to associate with the destination pod. And that's where strict mTLS falls apart, because Istio relies on that association to know the destination's identity.
The short version: your WorkloadEntry needs a serviceAccount field, and your ServiceEntry needs the correct subjectAltNames. Keep reading for the full debugging story.