How does Istio implement mutual TLS (mTLS) and what is the difference between STRICT, PERMISSIVE, and DISABLE modes?
Quick Answer
Istio's control plane (istiod) acts as a CA, issuing SPIFFE certificates to each Envoy proxy. mTLS modes: STRICT (require mTLS), PERMISSIVE (accept both plain and mTLS), DISABLE (no mTLS).
Detailed Answer
mTLS in Istio
Certificate Management
- istiod runs a Certificate Authority (CA) - Each Envoy sidecar requests a certificate via SDS (Secret Discovery Service) - Certificates use SPIFFE identity format: spiffe://cluster.local/ns/<namespace>/sa/<service-account> - Certificates auto-rotate (default 24h TTL) - No application code changes needed
PeerAuthentication Modes
- PERMISSIVE (default): Accepts both mTLS and plaintext. Use during migration — services without sidecars can still communicate. Not secure for production.
- STRICT: Requires mTLS for all inbound traffic. Non-mesh services cannot communicate. Use in production for zero-trust networking.
- DISABLE: No mTLS. Use when connecting to external services that don't support TLS.
Scope: PeerAuthentication can be applied at mesh level (all services), namespace level, or workload level. Most specific wins.
Migration Path
1. Start with PERMISSIVE mesh-wide 2. Enable sidecar injection on all namespaces 3. Verify all services have sidecars (istioctl analyze) 4. Switch to STRICT namespace by namespace 5. Monitor for connection failures in Kiali
Code Example
# Mesh-wide PERMISSIVE (migration phase)
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system # mesh-wide
spec:
mtls:
mode: PERMISSIVE
---
# Namespace-level STRICT (production)
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: production
spec:
mtls:
mode: STRICT
---
# Workload-level exception (external DB)
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: db-client
namespace: production
spec:
selector:
matchLabels:
app: db-client
mtls:
mode: STRICT
portLevelMtls:
5432: # PostgreSQL port
mode: DISABLE # DB doesn't have sidecar
# Verify mTLS status
istioctl authn tls-check <pod> <service>
# Check certificate info
istioctl proxy-config secret <pod> -o json | jq '.dynamicActiveSecrets[0].secret.tlsCertificate'Interview Tip
Explain the migration path: PERMISSIVE → STRICT. This shows you've done mTLS rollouts in production, not just toggled a config. Mention SPIFFE identity format — it's the underlying standard.