beginner 3 min answer Multiple choice

A platform team rolls out sidecar proxies so every service gets mTLS without code changes. A month later an auditor captures traffic and finds one service still sending plaintext credentials to an external payments SaaS. The sidecar is running and healthy. Why is that traffic not encrypted by the mesh?

sidecarmtlsservice meshtrust boundariesegress
Pick one
Show the full answer Hide the answer

The mechanism

mTLS is mutual: it needs a proxy at both ends. A sidecar gets its traffic because an init container rewrites the pod's iptables rules to redirect outbound connections into the proxy. The proxy then looks up the destination in the mesh's service registry. If the destination is another mesh member, the proxy finds a peer proxy with a workload certificate and both sides authenticate.

An external SaaS has no peer proxy and no workload identity in your mesh. The sidecar forwards that connection as a pass-through, doing whatever the application asked for. If the application opened a plain HTTP connection, plain HTTP is what leaves the cluster. The mesh has not failed; it was never in that path in the security sense.

The same gap appears in four other places that surprise teams: traffic on ports excluded from interception, traffic from pods without a sidecar (jobs, DaemonSets, anything in a namespace that was never labelled), UDP and most non-HTTP protocols on many mesh configurations, and anything the application sends to a raw IP address that the registry cannot resolve to a known service.

What the mesh actually gave you

A workload identity per service, automatic certificate rotation on the order of 24 hours rather than the 12 months a manual PKI typically manages, and encryption plus policy between services you own. That is a real gain, it costs roughly 0.5 to 2 ms of added latency per hop, and it is bounded by the interception boundary. Trust the mesh for east-west traffic and nothing else. Choose an explicit egress control for everything leaving the cluster; the mesh does not cover it, and no setting makes it.

Why the other options fail

  • File descriptor exhaustion would produce connection errors and a very loud proxy, not a silent protocol downgrade. Proxies do not have a plaintext fallback mode to fall back to; this option imagines a failure mode that does not exist.
  • Permissive until strict is a real and important setting: meshes usually start in a permissive mode where a proxy accepts both mTLS and plaintext so migration is possible. It is worth checking, and it is the wrong answer here because permissive mode governs traffic between mesh members. It does not create a peer where none exists.
  • TLS version negotiation never downgrades to no TLS. A version mismatch produces a handshake failure, which is visible. This option confuses "negotiated a weaker cipher" with "gave up on encryption", which no client does silently.

When this is the wrong thing to worry about

If the service only ever talks to other services inside the mesh, the interception boundary and the trust boundary coincide, and this concern is theoretical. It becomes real the moment anything calls out: a payment provider, an email API, an object store on the public endpoint.

What to do about it

  1. Enumerate egress, do not assume it. A single egress gateway that all outbound traffic must pass through turns "which services call outside" into a query rather than an audit.
  2. Make TLS the application's job for external calls. The library making the call verifies the certificate and pins the expected issuer where the provider supports it. The mesh cannot do this for you.
  3. Alert on plaintext leaving the egress gateway, by port and destination. This is the signal that catches the next instance, and it is cheap.