Service meshes like Istio don’t just encrypt traffic; they fundamentally change how services discover and authenticate each other, making mTLS a natural byproduct, not the primary goal.

Let’s see this in action. Imagine two services, frontend and backend, running in Kubernetes.

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: backend
spec:
  host: backend
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL

This DestinationRule tells Istio’s sidecar proxy (Envoy) that any traffic destined for the backend service must be encrypted using mutual TLS, and the sidecar should handle the certificate management.

Here’s what happens when frontend wants to talk to backend:

  1. Request Initiation: The frontend application makes a standard HTTP request to backend (e.g., http://backend:8080/api/data).
  2. Sidecar Interception: The frontend’s Istio sidecar proxy intercepts this outgoing request.
  3. mTLS Handshake: The sidecar initiates an mTLS handshake with the backend service’s sidecar proxy.
    • The frontend sidecar presents its workload identity certificate (signed by Istio’s root CA).
    • The backend sidecar presents its workload identity certificate.
    • Both sidecars verify each other’s certificates against the trusted Istio root CA.
  4. Encrypted Communication: Once the handshake is successful, the actual HTTP request is encrypted and sent over the established TLS tunnel.
  5. Backend Sidecar Decryption: The backend sidecar receives the encrypted traffic, decrypts it, and forwards the original HTTP request to the backend application.

The backend application itself usually doesn’t need to be aware of mTLS. It just receives a plain HTTP request from its local sidecar.

The mental model here revolves around Istio’s control plane (istiod) and the data plane (Envoy sidecars).

  • istiod (Control Plane): This is the brain. It manages configurations like DestinationRule and VirtualService. Crucially, it acts as an intermediate Certificate Authority (CA). It generates and distributes TLS certificates to each sidecar proxy, tied to the workload’s identity (e.g., spiffe://<mesh_id>/sa/<service_account>).
  • Envoy Sidecars (Data Plane): These proxies run alongside every application pod. They intercept all inbound and outbound traffic. They are responsible for:
    • Service Discovery: Knowing where other services are located.
    • Traffic Routing: Applying policies defined in VirtualService and DestinationRule.
    • Security: Performing the mTLS handshake, encrypting/decrypting traffic, and enforcing authorization policies.

The DestinationRule with mode: ISTIO_MUTUAL is the trigger. It instructs the client-side Envoy to initiate an mTLS connection. For the connection to succeed, the server-side Envoy must also be configured to accept mTLS connections. This is often handled by a default PeerAuthentication policy that applies STRICT mTLS to all services in the mesh, or a specific PeerAuthentication for the backend service.

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: backend
spec:
  selector:
    matchLabels:
      app: backend
  mtls:
    mode: STRICT

This PeerAuthentication ensures the backend service’s sidecar will only accept mTLS connections. Combined with the DestinationRule on the client, this creates a secure, mutually authenticated channel.

The surprising part is how Istio’s authorization policies leverage the verified workload identity established during the mTLS handshake. You can define rules that say "only the frontend service’s identity is allowed to access the /api/data endpoint on backend," and this check happens after the mTLS handshake, using the cryptographic proof of identity.

The next logical step is to explore how to configure fine-grained authorization policies using Istio’s AuthorizationPolicy resource, which builds directly upon the mTLS identity.

Want structured learning?

Take the full Tls-ssl course →