mTLS and Service Mesh Security
Why mTLS?
In a Kubernetes cluster, pod-to-pod communication is unencrypted by default. Any process on the cluster network can eavesdrop on traffic between services. Mutual TLS (mTLS) encrypts all service-to-service communication and provides mutual authentication -- both the client and server verify each other's identity.
CKS Exam Relevance
The CKS exam tests conceptual understanding of mTLS and service meshes. You should know:
- What mTLS is and why it matters
- How Istio implements mTLS
- PeerAuthentication and AuthorizationPolicy resources
- The difference between permissive and strict mTLS modes
- Certificate rotation concepts
What Is mTLS?
Mutual TLS extends standard TLS by requiring both parties to authenticate with certificates, not just the server.
Standard TLS vs mTLS
| Aspect | Standard TLS | Mutual TLS (mTLS) |
|---|---|---|
| Server authenticates to client | Yes | Yes |
| Client authenticates to server | No (usually) | Yes |
| Encryption | Yes | Yes |
| Identity verification | Server only | Both parties |
| Use case | Web browsers to servers | Service-to-service |
mTLS Handshake
Service Mesh Architecture
A service mesh implements mTLS transparently by injecting sidecar proxies alongside each application container. The application does not need to be modified.
How the Sidecar Proxy Works
- Outbound traffic from the app is intercepted by the sidecar proxy (via iptables rules)
- The proxy encrypts the traffic using mTLS with its certificate
- Inbound traffic arrives at the destination pod's sidecar proxy
- The proxy decrypts and verifies the client certificate
- Decrypted traffic is forwarded to the application container on localhost
- The application never sees TLS -- it communicates in plain HTTP on localhost
Istio Service Mesh Security
Installing Istio (Conceptual)
# Download Istio
curl -L https://istio.io/downloadIstio | sh -
# Install with demo profile
istioctl install --set profile=demo
# Enable sidecar injection for a namespace
kubectl label namespace default istio-injection=enabled
# Verify
kubectl get pods -n istio-systemAutomatic Sidecar Injection
When a namespace is labeled with istio-injection=enabled, Istio's mutating webhook automatically injects the Envoy sidecar proxy into every new pod:
# Enable automatic injection
kubectl label namespace production istio-injection=enabled
# Verify injection
kubectl get pods -n production
# NAME READY STATUS
# frontend-abc123 2/2 Running # 2/2 means sidecar is presentPeerAuthentication
PeerAuthentication controls the mTLS mode for workloads in the mesh.
Modes
| Mode | Behavior |
|---|---|
STRICT | Only mTLS traffic is accepted. Non-mTLS connections are rejected. |
PERMISSIVE | Accepts both mTLS and plain text traffic (default). |
DISABLE | mTLS is disabled entirely. |
UNSET | Inherits from parent scope. |
Mesh-Wide Strict mTLS
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system # Mesh-wide when in istio-system
spec:
mtls:
mode: STRICT # All services require mTLSSTRICT Mode
Enabling STRICT mTLS mesh-wide means any service without a sidecar proxy cannot communicate with mesh services. Ensure all workloads have sidecars before enabling STRICT mode.
Namespace-Level mTLS
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: production # Only affects this namespace
spec:
mtls:
mode: STRICTWorkload-Specific mTLS
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: frontend-mtls
namespace: production
spec:
selector:
matchLabels:
app: frontend # Only this workload
mtls:
mode: STRICTPort-Level mTLS
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: db-mtls
namespace: production
spec:
selector:
matchLabels:
app: database
mtls:
mode: STRICT
portLevelMtls:
3306:
mode: PERMISSIVE # Allow non-mesh clients on MySQL portAuthorizationPolicy
While PeerAuthentication controls whether mTLS is used, AuthorizationPolicy controls who can access what. It implements Layer 7 access control.
Deny All Traffic (Default Deny)
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: production
spec:
{} # Empty spec = deny allAllow Specific Traffic
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-frontend-to-api
namespace: production
spec:
selector:
matchLabels:
app: api-server # Target: api-server pods
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/production/sa/frontend" # Source: frontend SA
to:
- operation:
methods: ["GET", "POST"] # Only GET and POST
paths: ["/api/*"] # Only /api/* pathsDeny Specific Traffic
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-external
namespace: production
spec:
selector:
matchLabels:
app: internal-service
action: DENY
rules:
- from:
- source:
notNamespaces: ["production"] # Deny from other namespacesCommon Authorization Patterns
# Allow only same-namespace communication
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: same-namespace-only
namespace: production
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ["production"]# Allow health checks from any source
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-health-checks
namespace: production
spec:
selector:
matchLabels:
app: api-server
action: ALLOW
rules:
- to:
- operation:
methods: ["GET"]
paths: ["/health", "/ready"]Certificate Management
Istio Certificate Architecture
Istio's control plane component (formerly Citadel, now part of istiod) acts as the Certificate Authority:
Certificate Identity
Istio uses SPIFFE (Secure Production Identity Framework for Everyone) identities:
spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>Example:
spiffe://cluster.local/ns/production/sa/frontendThis identity is embedded in the X.509 certificate's SAN (Subject Alternative Name) field.
Certificate Rotation
Istio automatically rotates workload certificates:
- Default lifetime: 24 hours
- Rotation: Automatic, no downtime
- Grace period: Certificates are renewed before expiration
- Root CA: Can be configured with custom CA certificates
# Custom certificate configuration in Istio
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
defaultConfig:
# Certificate rotation settings
proxyMetadata:
SECRET_TTL: "12h" # Certificate lifetimeKey Concept
Automatic certificate rotation is a major advantage of service meshes. Without a mesh, certificate management is manual and error-prone. With Istio, certificates are rotated automatically every 24 hours with zero downtime.
Zero Trust Networking
mTLS and service meshes enable Zero Trust networking principles:
| Principle | Implementation |
|---|---|
| Never trust, always verify | mTLS authenticates every connection |
| Least privilege access | AuthorizationPolicy restricts access |
| Assume breach | Encrypt all internal traffic |
| Verify explicitly | Certificate-based identity, not IP-based |
| Micro-segmentation | Per-service access control policies |
Before vs After Service Mesh
| Aspect | Without Mesh | With Istio mTLS |
|---|---|---|
| Service identity | IP-based (unreliable) | Certificate-based (cryptographic) |
| Encryption | None (or manual TLS) | Automatic mTLS |
| Access control | NetworkPolicy (L3/L4) | AuthorizationPolicy (L7) |
| Observability | Limited | Full traffic visibility |
| Certificate management | Manual | Automatic rotation |
Verifying mTLS
# Check if mTLS is enabled between services
istioctl authn tls-check <pod-name> <service-name>
# Check PeerAuthentication policies
kubectl get peerauthentication --all-namespaces
# Check AuthorizationPolicy
kubectl get authorizationpolicy --all-namespaces
# Verify mTLS in proxy configuration
istioctl proxy-config listeners <pod-name> -o json
# Check if a specific connection uses mTLS
kubectl exec <pod-with-sidecar> -c istio-proxy -- \
openssl s_client -connect <service>:80 -showcerts
# View Istio proxy logs for TLS errors
kubectl logs <pod-name> -c istio-proxy | grep -i tlsService Mesh Security Summary for CKS
Exam Focus Areas
For the CKS exam, remember these key points:
- mTLS encrypts service-to-service communication and provides mutual authentication
- PeerAuthentication controls mTLS mode (STRICT, PERMISSIVE, DISABLE)
- AuthorizationPolicy controls who can access which services (Layer 7)
- STRICT mode rejects all non-mTLS connections
- PERMISSIVE mode accepts both mTLS and plain text (migration mode)
- SPIFFE identities are based on namespace and service account
- Certificate rotation is automatic in Istio (default: 24h)
- Service meshes implement zero trust networking
Quick Reference
# PeerAuthentication - control mTLS mode
kubectl get peerauthentication -A
kubectl describe peerauthentication <name> -n <namespace>
# AuthorizationPolicy - control access
kubectl get authorizationpolicy -A
kubectl describe authorizationpolicy <name> -n <namespace>
# Istio injection
kubectl label namespace <ns> istio-injection=enabled
kubectl get namespace -L istio-injection
# Verify mTLS status
istioctl authn tls-check <pod>.<namespace> <service>.<namespace>.svc.cluster.local
# Check Istio proxy status
istioctl proxy-status
# Analyze Istio configuration
istioctl analyze -n <namespace>