Mutual TLS gives every service a cryptographic identity bound to its certificate. No tokens to leak, no central auth service to call on every hop, no replay window — just 'do you have a cert signed by our CA, and is it for the SAN we expected'.

Advertisement

Why mTLS over JWTs internally

JWTs need a token issuance step, expiry handling, refresh logic. mTLS handshakes once per connection and reuses. Authn AND channel integrity in one mechanism. No 'forgot to verify the signature' bug class.

Cert issuance — the hard part

Each pod/service needs a cert signed by an internal CA. SPIFFE/SPIRE, cert-manager + Vault PKI, or a service mesh's built-in CA. Rotation is automatic in mesh setups; manual rotation is where teams fall behind.

Advertisement

Service mesh does it for free

Istio, Linkerd, Consul: sidecar handles mTLS transparently. Apps speak plaintext to localhost. The mesh proxy handles cert issuance, rotation, verification. The right answer if you can swallow the operational cost of the mesh.

Without a mesh

Each language has libraries (Go: crypto/tls, Java: keystore, Python: ssl). Generate per-service certs from cert-manager. Wire SAN-based identity into authz. More code, less infra; right for small teams.

Don't disable verification

InsecureSkipVerify=true is the most-shipped vulnerability in mTLS code. Test paths often run with it 'temporarily'. Make it impossible: structurally fail the build if verifier is disabled in non-test builds.

mTLS replaces bearer-token internal auth. Mesh if you have one; library-based if not. Never skip verify.