How to Implement Mutual TLS in Istio: Step‑by‑Step Guide and Common Pitfalls
This article explains Istio's security features, focusing on mutual TLS configuration at global, namespace, and service levels, demonstrates practical YAML examples, shows how sidecar presence affects traffic, and discusses TLS mode choices, certificate handling, and real‑world deployment considerations.
Istio Mutual TLS Overview
Istio can enforce mutual TLS (mTLS) between Envoy sidecars, encrypting all service‑to‑service traffic. mTLS can be applied mesh‑wide, per namespace, or per individual service.
Global Mesh‑Wide mTLS Configuration
A mesh‑wide authentication policy must be named default and use the MeshPolicy CRD. The corresponding DestinationRule sets tls.mode to ISTIO_MUTUAL, causing Istio to generate certificates for every service.
apiVersion: "authentication.istio.io/v1alpha1"
kind: "MeshPolicy"
metadata:
name: "default"
spec:
peers:
- mtls: {}
---
apiVersion: "networking.istio.io/v1alpha3"
kind: "DestinationRule"
metadata:
name: "default"
spec:
host: "*.local"
trafficPolicy:
tls:
mode: ISTIO_MUTUALOnly the name default is recognized for mesh‑wide policies; other names are ignored. Destination rules may have any name and reside in any namespace.
TLS Mode Options
DISABLE : No TLS connection is established to the upstream.
SIMPLE : Initiates a TLS connection without presenting client certificates.
MUTUAL : Uses mutual TLS with client certificates for authentication.
ISTIO_MUTUAL : Istio‑generated certificates are used for mutual TLS; all other TLS fields must be empty.
Peer mTLS Settings
STRICT : Client certificate is required; connection is always TLS.
PERMISSIVE : Both plain HTTP and TLS are accepted; client certificate is optional.
Namespace and Sidecar Scenarios
Three namespaces are created: test1, test2 (both with automatic sidecar injection) and test3 (no sidecar). Sample httpbin and sleep pods are deployed in each namespace.
When a sidecar‑enabled client calls a service without a sidecar, the request fails because the server cannot present a client certificate. The fix is to disable TLS for that service:
apiVersion: "networking.istio.io/v1alpha3"
kind: "DestinationRule"
metadata:
name: "httpbin"
namespace: "test3"
spec:
host: "httpbin.test3.svc.cluster.local"
trafficPolicy:
tls:
mode: DISABLEConversely, when a non‑sidecar client calls a sidecar‑enabled service, the service must allow permissive traffic:
apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
name: "httpbin"
namespace: "test1"
spec:
targets:
- name: "httpbin"
peers:
- mtls:
mode: PERMISSIVEPolicy precedence follows a hierarchy: a more specific policy (service‑level) overrides a broader one (namespace‑level or mesh‑wide).
Service‑Level TLS Example (productpage)
A Policy CRD can enable mTLS for a single service. Omitting the targets field applies the policy to the entire namespace.
apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
name: "productpage-tls"
spec:
targets:
- name: productpage
peers:
- mtls: {}After applying the policy, Istio generates a self‑signed certificate for productpage. The certificate can be extracted to inspect its validity period and Subject Alternative Names (SANs).
Port‑Specific TLS Settings
If a service exposes multiple ports, TLS can be enabled on a single port using portLevelSettings in a DestinationRule:
apiVersion: "networking.istio.io/v1alpha3"
kind: "DestinationRule"
metadata:
name: "productpage-2"
spec:
host: "productpage.bookinfo.svc.cluster.local"
trafficPolicy:
tls:
mode: DISABLE
portLevelSettings:
- port:
number: 9080
tls:
mode: ISTIO_MUTUALBy default the service has no TLS; only port 9080 is secured with mutual TLS.
Interaction with External HTTPS Services
When an Istio sidecar proxies an external HTTPS service, the sidecar forwards the traffic at L4 without terminating TLS, regardless of the mTLS configuration.
Environment Preparation Commands
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /tmp/nginx.key -out /tmp/nginx.crt -subj "/CN=my-nginx/O=my-nginx"
kubectl create secret tls nginxsecret --key /tmp/nginx.key --cert /tmp/nginx.crt
kubectl create configmap nginxconfigmap --from-file=samples/https/default.conf
kubectl apply -f samples/https/nginx-app.yaml -n ngtest
kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n ngtestPractical Guidance
Use PERMISSIVE mode only during migration; it reduces security because it accepts both plain and TLS traffic.
In private networks the benefit of mTLS may be limited, but for public‑facing workloads encrypting critical data streams remains important.
When enabling mTLS, ensure that any component needing to reach the Kubernetes API server has an appropriate policy.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Cloud Native Technology Community
The Cloud Native Technology Community, part of the CNBPA Cloud Native Technology Practice Alliance, focuses on evangelizing cutting‑edge cloud‑native technologies and practical implementations. It shares in‑depth content, case studies, and event/meetup information on containers, Kubernetes, DevOps, Service Mesh, and other cloud‑native tech, along with updates from the CNBPA alliance.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
