Lesson 04 of 7 · Modules
mTLS & identity
How meshes identify workloads and encrypt traffic: SPIFFE IDs derived from service accounts, short-lived certificates and rotation, rolling out mTLS from permissive to strict without breaking callers, and writing identity-based authorization policies.
Identity first
Encryption alone isn't the main win; knowing who is calling is. Meshes issue each workload a certificate encoding its identity, following the SPIFFE standard:
spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>
spiffe://cluster.local/ns/shop/sa/cart
The certificate (an X.509 SVID) is short-lived (Istio's default is 24 hours) and rotated automatically by the proxy.
Every pupil gets a photo ID card from the school office, renewed every day so a lost card is useless tomorrow. When two pupils pass notes, they show each other their cards first (mutual TLS), and the teacher's rule says "only pupils from class 3 may hand notes to the class 5 monitor" (authorization policy), based on the card, not on where someone is sitting (IP).
Rolling out mTLS safely (Istio)
- Mesh the workloads (sidecars or ambient); default mode is PERMISSIVE: accepts mTLS and plaintext.
- Check which traffic is still plaintext (Kiali, or metrics'
connection_security_policylabel). - Switch namespace by namespace to STRICT:
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: default
namespace: shop
spec:
mtls:
mode: STRICT
- Finally, a mesh-wide STRICT default in the root namespace (
istio-system), with explicit exceptions (e.g. a port used by a non-mesh health checker).
Linkerd mTLSes meshed-to-meshed traffic automatically; its policy resources can require mTLS/identities per server port.
Authorization by identity
Default-deny for a namespace, then allow specific callers:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-nothing
namespace: orders
spec: {} # empty spec = deny all requests to this namespace's workloads
---
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: orders-api
namespace: orders
spec:
selector:
matchLabels: { app: orders-api }
action: ALLOW
rules:
- from:
- source:
principals: [ "cluster.local/ns/shop/sa/checkout" ]
to:
- operation:
methods: [ "POST" ]
paths: [ "/v1/orders" ]
- L7 conditions (methods, paths) need an L7 proxy (sidecar, or a waypoint in ambient mode).
- Keep NetworkPolicies too: defence in depth at L3/L4, and protection if the mesh is bypassed.
Certificate authority choices
- Built-in CA (self-signed root generated at install): fine for labs; for production, plug in your own root/intermediate.
- External CA integration: an intermediate from your corporate PKI, Vault, or cert-manager (e.g. istio-csr) so mesh identities chain to a root you control and can rotate.
- Multi-cluster: clusters must share a root of trust (common root, different intermediates) to authenticate each other.
Try it: mTLS and identity policies (Istio on kind)
- Deploy
sleep(curl) pods in a meshed and an un-meshed namespace, andhttpbinin a meshed namespace. - With PERMISSIVE, confirm both callers reach httpbin; switch httpbin's namespace to STRICT and confirm the un-meshed caller fails.
- Inspect the certificate chain a proxy presents (e.g.
istioctl proxy-config secret deploy/httpbin -o json) and find the SPIFFE ID. - Add the allow-nothing policy and a rule allowing only the meshed
sleepservice account toGET /headers; test allowed and denied calls. - Give two deployments the same service account and explain why the policy can no longer tell them apart.
Going deeper: identity at scale
- Enforce one service account per workload with a policy engine; default service accounts should have no mesh permissions.
- Plan root/intermediate rotation before go-live; test it in staging.
- Use SPIRE (the SPIFFE reference implementation) when identities must span meshes, VMs and non-Kubernetes workloads.
Recap
- Mesh identity = SPIFFE ID from namespace + service account, in short-lived, auto-rotated certificates.
- Roll out mTLS PERMISSIVE → STRICT, namespace by namespace, then mesh-wide.
- AuthorizationPolicies allow callers by verified identity (and L7 attributes); keep NetworkPolicies as defence in depth.
- Use your own CA/intermediate in production; share a root of trust across clusters.
This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.