Skip to content
Cloud Security DeskSearch
Menu

Technical guideWorkload security

Know what service mesh mTLS proves about the caller

A mesh handshake proves that a peer held a key for a namespace and service account. It says nothing about the user or the operation, and permissive defaults, probes and waypoints open paths around it.

Published
Sources checked
Next review
Reading time
19 minutes
Coverage
Istio · Linkerd · Kubernetes · Google Cloud · Microsoft Azure · Amazon Web Services
Two dark green rounded blocks joined by a doubled tunnel with blue packets inside it. A small white name badge is clipped to the top of the left block, while a thin amber line starts from a lone dot below and curves under the tunnel into the bottom of the right block.
Conceptual illustration: the mesh tunnel and its badge identify a workload, while a plaintext path can still reach the same service from outside the tunnel.

A myth versus reality examination of service mesh mTLS for platform and security architects, built from Istio 1.31, Linkerd 2.20, Kubernetes 1.37, SPIFFE, Google Cloud, Microsoft and AWS documentation reviewed in October 2026. It maps the identity inside mesh certificates, the plaintext and waypoint paths that avoid it, certificate lifetimes, pod certificates and the App Mesh retirement, and ends with in-cluster tests and an order of operations.

At a glance

Key findings

  • Istio sidecar and ambient modes, Google Cloud Service Mesh and Linkerd all accept plaintext from clients outside the mesh by default, and Istio's migration task says permissive mode applies no authentication or authorization checks to plaintext by default. [4][5][6][2][13]
  • A mesh certificate identifies a service account in a namespace and trust domain, not a user or process, and Istio's own guidance says mutual TLS provides authentication, not authorization. [9][2][3]
  • In ambient mode a waypoint presents its own identity to the destination, and out-of-mesh clients, sidecars, gateways and mismatched pod-IP traffic skip it; only an ALLOW policy that admits just the waypoint's identity stops those requests reaching the workload without layer 7 policy. [5][7][18]
  • Istio, Linkerd and Kubernetes pod certificates all default to 24-hour workload certificates, while documented ceilings run from one day for Kubernetes built-in signers, none of which ships yet, to 90 days in Istio and 91 days for other pod certificate signers. [21][2][22][24]
  • AWS App Mesh support ended on September 30, 2026; AWS's September 2024 migration comparison said the mTLS peer authentication App Mesh offered was not yet available in ECS Service Connect, and the current Service Connect TLS page still describes no client certificates. [25][26][23]

What one mesh handshake verifies

Mesh mTLS proves less about the caller than the name suggests. When two Istio sidecars or two Linkerd proxies complete a handshake, the server side learns that the peer proxy held the private key for a certificate the mesh's certificate authority signed, and that the certificate names a Kubernetes service account in a namespace. The client side checks the server's certificate against the identity it expected for that destination. The bytes between the two proxies are encrypted. That is the whole of what the handshake establishes. [1][2]

It says nothing about which person or upstream request caused the call, which container or process in the pod wrote the bytes, or whether this caller should be allowed to perform this operation on this record. Istio's security guidance states the limit directly: mutual TLS provides authentication, not authorization, so anything holding a valid certificate can still reach a service until an authorization policy says otherwise. [3]

That protection also covers only the connections that actually travel through the tunnel, and the defaults leave several that do not. Istio in sidecar and ambient mode, Google Cloud Service Mesh and Linkerd all accept plaintext from clients outside the mesh until someone changes a setting. Kubelet health probes and ports excluded from traffic capture never enter the tunnel. In ambient mode a waypoint proxy presents its own identity to the destination, and clients outside the mesh skip the waypoint entirely. [4][5][6][2][7]

The sections that follow take one widely held belief at a time and test it against current documentation: Istio 1.31, Linkerd 2.20, Google Cloud Service Mesh with Istio APIs, the AKS Istio add-on, Kubernetes 1.37 pod certificates and the AWS App Mesh retirement, all reviewed on October 9, 2026. Istio 1.31 was released on August 27, 2026, and 1.29 and 1.30 remain supported. The sequence below follows one sidecar-mode request and marks where each identity check happens. [8]

Figure 01

Four checks on one sidecar request, none of them about the user

The handshake binds the connection to a service account; only the authorization step decides whether the request may proceed. [1][9]

Sequence diagram with five participants: client app, client sidecar, istiod, server sidecar and server app. The client sidecar sends a CSR with the pod's credentials to istiod and receives a certificate for its namespace and service account, plus the secure naming map of identities allowed to run each service. The client app sends a plaintext request that is redirected to its sidecar, which opens an mTLS handshake with the server sidecar and checks the server identity against the map. The server sidecar reads the peer principal, applies AuthorizationPolicy and forwards an allowed request to the server app over localhost.

Source. Istio security concepts (identity provisioning, mutual TLS authentication, principals) and Authorization Policy reference, Istio 1.31 documentation reviewed October 9, 2026. [1][9]

Method. Message order transcribed from the cited Istio documentation for sidecar mode and condensed into short labels. Certificate rotation, request authentication and telemetry are left out.

Accessible table and figure data
Figure 1 accessible table
FromToMessage
Client sidecaristiodCSR with the pod's credentials
istiodClient sidecarCertificate for namespace and service account
istiodClient sidecarSecure naming map: identities allowed per service
Client appClient sidecarPlaintext request, redirected inside the pod
Client sidecarServer sidecarmTLS handshake; client checks server identity against the map
Server sidecarServer sidecarRead peer principal, apply AuthorizationPolicy
Server sidecarServer appForward over localhost if allowed
Figure 1 accessible table
FromToMessage
Client sidecaristiodCSR with the pod's credentials
istiodClient sidecarCertificate for namespace and service account
istiodClient sidecarSecure naming map: identities allowed per service
Client appClient sidecarPlaintext request, redirected inside the pod
Client sidecarServer sidecarmTLS handshake; client checks server identity against the map
Server sidecarServer sidecarRead peer principal, apply AuthorizationPolicy
Server sidecarServer appForward over localhost if allowed

The certificate names a service account, not a caller

A common reading of mesh telemetry is that the certificate tells the server which service called. What it carries is narrower. In Istio the identity in a workload certificate is the Kubernetes service account, and authorization policies refer to it as a principal of the form <trust domain>/ns/<namespace>/sa/<service account>, for example cluster.local/ns/default/sa/productpage. Linkerd binds each proxy certificate to the pod's ServiceAccount, and its tooling prints identities as service account and namespace. Google's managed certificate authority for Cloud Service Mesh writes the project ID, the GKE namespace and the service account name into each certificate. [1][9][2][10][6]

A service account is a label shared by everything that runs under it. It follows that every replica of a Deployment, every Job that sets the same serviceAccountName and every container in those pods presents the same certificate identity. Istio's security guidance adds that there is minimal security boundary between an application and its sidecar: they share the pod's network and process namespaces, and the application can remove redirection rules or replace the proxy. The boundary Istio does describe is narrower: a client may not bypass another pod's sidecar. [3]

Who can obtain the certificate decides what it is worth. An Istio agent generates a private key and sends a certificate signing request with the pod's credentials to istiod, whose CA validates those credentials before signing. A Linkerd proxy sends its service account token with the request for the same reason. In ambient mode the node's ztunnel requests certificates on behalf of each service account with a pod on that node, and the CA must refuse identities that are not running there; Istio calls that check critical to stopping one compromised node from compromising the whole mesh. The consequence is that permission to create a pod with a given serviceAccountName in a namespace amounts to permission to obtain that mesh identity, and the Kubernetes RBAC around pod creation belongs in the mesh's trust model. [1][2][7]

SPIFFE supplies the vocabulary. A SPIFFE ID is a URI made of a trust domain and a path whose meaning is left to the administrator, and the standard warns that trust domain names are self-registered, with no guarantee of global uniqueness. Istio's ambient documentation says SPIFFE identities identify the workloads on each side of an HBONE connection, and Istio's examples use the trust domain cluster.local. A reasonable reading is that a principal string proves little on its own: two clusters that share a root of trust and both keep cluster.local issue principals nobody can tell apart. Istio 1.31 added trustDomains and notTrustDomains to AuthorizationPolicy so that a rule can match the trust domain taken from the peer certificate. [11][7][9][12]

Joining the mesh does not switch on enforcement

Teams often assume that once workloads are in the mesh, they accept only mTLS. Every mesh covered here starts in the opposite state, because enforcement on day one would break clients that have not joined yet. Istio peer authentication offers PERMISSIVE, STRICT and DISABLE, and a mesh-wide policy with no mode set uses PERMISSIVE, which accepts mTLS and plaintext side by side; an UNSET mode inherits from its parent and is otherwise treated as PERMISSIVE. Istio's migration task spells out the consequence: in permissive mode, plaintext traffic receives no authentication or authorization checks by default. [1][4][13]

Ambient mode keeps that default. The receiving ztunnel accepts both HBONE and plaintext connections, plaintext from an out-of-mesh source arrives with no peer identity, and only STRICT or an authorization rule that requires an identity turns it away. DISABLE is not supported in ambient mode, and policies that set it are ignored, because ztunnel always tunnels mesh traffic. [7][5][4]

The managed and alternative meshes behave the same way. Google Cloud Service Mesh turns on auto mTLS, under which a client sidecar sends mTLS to workloads with sidecars and plaintext to workloads without them, while services accept both; Google recommends migrating services to accept only mTLS. Linkerd requires mTLS between two meshed proxies but accepts plaintext from non-meshed sources by default. Its cluster-wide default inbound policy is all-unauthenticated, and the stricter all-authenticated, cluster-authenticated and deny values have to be chosen. A pod's default policy is fixed when its proxy starts, so changing the annotation later has no effect until the pod is recreated. Microsoft's overview of the AKS add-on describes it as built on open-source Istio and states no different default, so the safe assumption is Istio's permissive behavior until a test shows otherwise. [6][2][14][15]

Permissive mode does more than admit plaintext; it changes what authorization rules mean. The source fields principals and namespaces, their negative forms and the conditions source.principal and source.namespace are all read from the peer certificate, so a plaintext request presents empty values. Istio's advisory ISTIO-SECURITY-2021-004, which covers every release from 1.5 onward, shows the effect: an ALLOW rule with notNamespaces: ["foo"] admits a plaintext request that came from foo, and a DENY rule on namespaces: ["foo"] fails to block one. The remedy is STRICT, or rules that explicitly reject an empty namespace. [16][1]

Default handling of plaintext from clients outside the mesh, from Istio, Google Cloud, Linkerd and Microsoft documentation reviewed October 9, 2026. [4][5][6][14][15]
MeshPlaintext accepted by defaultSetting that rejects it
Istio sidecar modeYes, PERMISSIVEPeerAuthentication STRICT
Istio ambient modeYes, ztunnel accepts bothSTRICT, or ALLOW rules requiring a principal
Google Cloud Service MeshYes, under auto mTLSMigrate services to mTLS only
Linkerd 2.20Yes, from non-meshed sourcesDefault policy all-authenticated or deny
AKS Istio add-onNo separate default documentedIstio PeerAuthentication, sidecar mode only
Figure 02

Three ways plaintext reaches a permissive server

Only the tunnel carries a peer identity; unmeshed callers, node probes and excluded ports arrive without one. [4][17][2]

Illustration. A meshed client on the left reaches a server pod on the right through a doubled tunnel labeled mTLS tunnel and peer identity checked, ending at a proxy box marked PERMISSIVE. Below it, three amber lines arrive without the tunnel: from an unmeshed pod, labeled plaintext accepted, and from a kubelet probe, labeled node, no certificate, both into the proxy, and from an excluded port, labeled bypasses the proxy, straight into the app box. A note reads amber paths carry no peer identity.

Source. Conceptual illustration based on Istio PeerAuthentication, ambient NetworkPolicy and security guidance pages and Linkerd automatic mTLS documentation, reviewed October 9, 2026. [4][17][3][2]

Method. Conceptual hand-authored illustration. It simplifies sidecar and ambient data paths into one server pod and does not show gateways or waypoints.

Accessible table and figure data
Figure 2 accessible table
ElementWhat it represents
Meshed clientPod with a sidecar or in ambient mode
Doubled tunnelmTLS between proxies, peer identity checked
Proxy (PERMISSIVE)Server proxy accepting mTLS and plaintext
Unmeshed podClient with no proxy, sends plaintext
Kubelet probeNode health check, no mesh certificate
Excluded portCapture exclusion or skip port, bypasses proxy
No peer identityPolicy sees an empty principal
Figure 2 accessible table
ElementWhat it represents
Meshed clientPod with a sidecar or in ambient mode
Doubled tunnelmTLS between proxies, peer identity checked
Proxy (PERMISSIVE)Server proxy accepting mTLS and plaintext
Unmeshed podClient with no proxy, sends plaintext
Kubelet probeNode health check, no mesh certificate
Excluded portCapture exclusion or skip port, bypasses proxy
No peer identityPolicy sees an empty principal

STRICT still leaves traffic outside the tunnel

Switching to STRICT is sometimes treated as closing every plaintext path. It closes the one it governs: inbound connections to a proxy that should have arrived through the tunnel. Several kinds of traffic never reach that decision, and kubelet health probes are the most common. The kubelet runs on the node, holds no mesh certificate and sends plaintext. Linkerd's tap output marks these requests tls=no_tls_from_remote, and Linkerd authorizes probes automatically unless a Server has HTTPRoutes or GRPCRoutes attached. Istio ambient translates the source of probe packets that provably come from the local node to 169.254.7.127 and fd16:9254:7127:1337:ffff:ffff:ffff:ffff, and its policy enforcement ignores them as unsecured probe traffic. A NetworkPolicy rule that admits those addresses is therefore admitting node-originated plaintext by design. [10][14][17]

Capture exclusions come next. Istio sidecar redirection handles TCP only, so UDP and ICMP are never captured; inbound capture skips port 22 and the sidecar's own ports, and annotations such as traffic.sidecar.istio.io/excludeInboundPorts and excludeOutboundPorts widen the gap pod by pod. Linkerd's skip ports bypass the proxy entirely. A workload-scoped PeerAuthentication can also set portLevelMtls to DISABLE for one workload port, a legitimate migration tool that is easy to forget once the migration ends. [3][2][4]

Then there is the pod itself. Because an application can alter its own sidecar's redirection, Istio's documentation says it is not secure to rely on all traffic being captured unconditionally. Its recommended defense is to layer Kubernetes NetworkPolicy under mesh policy and to route egress through an egress gateway that NetworkPolicy makes mandatory. It warns that outboundTrafficPolicy: REGISTRY_ONLY on its own is a best-effort guard against accidental dependencies, not a security boundary. [3]

Name resolution is the last gap. Istio's secure naming check lets a client reject a server whose certificate identity is not authorized to run the destination service, which defeats a forged server holding a valid certificate for some other identity. For traffic that is not HTTP or HTTPS, the documentation says secure naming does not protect against DNS spoofing: a TCP connection carries no host information, the proxy can only route on the destination address, and a spoofed address can steer the connection to whatever service holds it. Istio authorization also cannot inspect the first bytes of server-first TCP protocols, which reach the client before any check runs. [1][3]

Ambient mode changes who the destination sees

Ambient mode is often described as the sidecar model with fewer proxies. At layer 4 the identity model is close. Ztunnel holds a separate certificate for each service account with a pod on its node, never uses its own identity for workload-to-workload mTLS, and encrypts and decrypts HBONE traffic inside the source and destination pods' network namespaces, on port 15008. The receiving ztunnel enforces AuthorizationPolicy, and layer 4 rules behave as they do in sidecar mode. [7][17][5]

The differences start at layer 7. Ztunnel cannot evaluate HTTP attributes, so a policy with a method, path or request principal that lands on a ztunnel fails safe and denies the connection. L7 policy runs only at a waypoint, and a waypoint does not impersonate the client. Once traffic passes through one, the destination ztunnel sees the waypoint's service account, which is named after its Gateway. A destination rule that allowed cluster.local/ns/shop/sa/frontend now meets a different principal, which is why Istio's guidance moves source-identity policy onto the waypoint. [5][18]

The waypoint is also easy to skip. A workload outside the mesh knows nothing about waypoints and sends straight to the destination, and the data plane page says traffic from sidecars and gateways does not pass through waypoints either, with awareness planned for a future release. Ingress gateway traffic uses the destination's waypoint only when the Service or Namespace carries istio.io/ingress-use-waypoint and istiod runs with ENABLE_INGRESS_WAYPOINT_ROUTING, which defaults to false. Ztunnel routes around the waypoint, instead of failing, when the named waypoint does not exist or has no address, or when the traffic type does not match, such as a request to a pod IP when the waypoint handles only service traffic. In each case the L7 policy never runs. [7][18]

The documented remedy makes the waypoint mandatory: an ALLOW policy selected by workload labels, so that ztunnel enforces it, which admits only the waypoint's identity. It holds when the waypoint is unavailable and when a client dials the pod directly, and because it requires a peer principal it also rejects plaintext from outside the mesh. Maturity varies by feature: multi-network multicluster ambient reached beta in Istio 1.29 on February 16, 2026, shifting traffic between waypoints is alpha in 1.31, and the AKS Istio add-on does not yet support ambient mode. [18][7][19][15]

Example AuthorizationPolicy fragment for Istio 1.31 ambient mode, following the documented require-waypoint pattern. The waypoint's service account is named after its Gateway; shop, orders and orders-waypoint are placeholders. Attach caller rules to the waypoint itself, or this policy will be the only check.
# Example: only the waypoint may reach app: orders in namespace shop.
# A selector (not targetRefs) makes ztunnel enforce this at layer 4.
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: require-orders-waypoint
  namespace: shop
spec:
  selector:
    matchLabels:
      app: orders
  action: ALLOW
  rules:
  - from:
    - source:
        principals:
        - cluster.local/ns/shop/sa/orders-waypoint

An authenticated peer is not an authorized caller

With STRICT in place, it is tempting to believe only the right callers get through. Istio allows every request to a workload that has no ALLOW policy, in sidecar and ambient mode alike, so a fully encrypted, fully authenticated mesh with no authorization policies admits any workload holding a valid certificate. When several actions apply, CUSTOM is evaluated first, then DENY, then ALLOW, while AUDIT only marks requests for logging. Istio recommends starting from a default-deny policy so that a missing rule produces a rejection rather than an exposure. [9][5][3]

The source fields map onto what the certificate carries. principals and namespaces require mTLS. serviceAccounts takes <namespace>/<serviceaccount> pairs, allows no wildcards and cannot be combined with those two. trustDomains and notTrustDomains, new in Istio 1.31, match the trust domain from the peer certificate by exact, prefix, suffix or presence. A policy built from these fields answers one question well, which workload identity may open this connection or send this request, and nothing beyond it. [9][12]

The end user is a different identity that arrives by a different route. Istio's request authentication validates a JWT and exposes its issuer and subject as request.auth.principal, matched with requestPrincipals, but a request that carries no token passes request authentication by default; only an authorization rule that requires a request principal rejects it. At ingress the difference is easy to see. Istio's namespace-isolation example admits the ingress gateway's service account, cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account, alongside workloads in the namespace. The example implies that, to the backend, every external request arrives with the gateway's certificate, so whatever the backend learns about the original user has to come from a token or header the gateway forwarded. [1][9][20]

Linkerd builds the same separation from different objects. A Server selects a port on a set of pods, MeshTLSAuthentication names client identities, NetworkAuthentication names address ranges, and an AuthorizationPolicy joins a target to an authentication. A Server's accessPolicy defaults to deny, and an audit value logs would-be denials during rollout. For decisions the mesh cannot express, Istio's CUSTOM action delegates to an external authorizer, with at most one provider per workload, and that extension cannot override native ALLOW and DENY results. Neither mesh knows whether this customer may read that invoice. That rule belongs in the application, exactly as it does for Cloud Run services that authenticate each other with IAM. [14][9]

Example policy set for Istio 1.31 sidecar mode. Warning: allow-nothing denies every request in the namespace, including traffic from the ingress gateway and other callers you have not yet listed, so try it with the istio.io/dry-run annotation or in a test namespace first.
# Example for Istio 1.31 sidecar mode in namespace shop (placeholder names).
# 1. Reject plaintext.
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: default
  namespace: shop
spec:
  mtls:
    mode: STRICT
---
# 2. Deny everything that no ALLOW policy matches.
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: allow-nothing
  namespace: shop
spec: {}
---
# 3. Let only the frontend service account read orders.
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: orders-read-from-frontend
  namespace: shop
spec:
  selector:
    matchLabels:
      app: orders
  action: ALLOW
  rules:
  - from:
    - source:
        serviceAccounts: ["shop/frontend"]
    to:
    - operation:
        methods: ["GET"]
        paths: ["/orders/*"]
Figure 03

What each layer proves and what it leaves open

Each layer answers one question; the user and the operation are only covered if the top two layers have rules. [3][9]

Four stacked layers. Transport encryption proves the hop between proxies is private but not that every hop uses the tunnel. Peer identity proves the peer holds a key for a namespace and service account but not which process, replica or user sent the request. Workload authorization proves the identity may reach the port or route but not that the operation suits the record. Request and user authorization proves a validated JWT subject may act, but only if a rule requires the token.

Source. Conceptual model by the editors, based on Istio security concepts, security guidance and the Authorization Policy reference, and Linkerd authorization policy documentation. [1][3][9][14]

Method. Conceptual layering of documented behavior. Each layer depends on the one below it; the model leaves out gateways and application code.

Accessible table and figure data
Figure 3 accessible table
LayerProvesLeaves open
Transport encryptionthe hop between proxies is privatewhether every hop used the tunnel
Peer identitypeer holds a key for a namespace and service accountwhich process, replica or user
Workload authorizationthis identity may reach this routewhether the action suits the record
Request and user authorizationa validated JWT subject may actanything, if no rule needs a token
Figure 3 accessible table
LayerProvesLeaves open
Transport encryptionthe hop between proxies is privatewhether every hop used the tunnel
Peer identitypeer holds a key for a namespace and service accountwhich process, replica or user
Workload authorizationthis identity may reach this routewhether the action suits the record
Request and user authorizationa validated JWT subject may actanything, if no rule needs a token

Short lifetimes shrink a stolen key's window without closing it

Short-lived certificates are often credited with making a stolen key harmless. The defaults are indeed short. Istio's CA issues workload certificates for 24 hours when the request does not ask for a lifetime, Linkerd proxy certificates last 24 hours, and a Kubernetes podCertificate projection asks for 24 hours when maxExpirationSeconds is not set. Amazon ECS Service Connect rotates its certificates every five days by default, and AWS recommends running AWS Private CA in short-lived mode for it. Google's Cloud Service Mesh security page states no workload certificate lifetime, only that shorter refresh intervals can be configured. [21][2][22][23][6]

Defaults are not ceilings. Istio's MAX_WORKLOAD_CERT_TTL is 2160 hours, or 90 days. A third-party pod certificate signer may be asked for up to 91 days, while signers built into Kubernetes are limited to one day, although none ships in core yet, and Service Connect's short-lived mode allows seven days. It follows that a copied key and certificate keep working against any peer that trusts the issuer until they expire, unless something checks revocation. Service Connect documents no revocation and relies on frequent rotation instead, and Istio added certificate revocation list support to ztunnel in 1.29, for plugged-in certificate authorities only. [21][22][24][23][19]

The signing root carries more weight than any leaf. Istio's self-signed root defaults to 87600 hours, ten years, and istiod checks it for rotation every hour. Linkerd's default install creates a trust anchor that expires after 365 days and must then be rotated by hand, a task Linkerd itself calls non-trivial, plus an issuer certificate and key that expire after a year; clusters joined by Linkerd multicluster must share an explicitly provided anchor. Linkerd stores the issuer key in a Secret that only the identity component's service account can read. Whoever can read a signing key can, in effect, mint any identity in its trust domain, so the RBAC on that Secret, or the access policy on the external CA behind it, deserves more review than the leaf lifetime does. [21][2]

Documented certificate defaults by platform, reviewed October 9, 2026. Google Cloud Service Mesh does not state a workload lifetime on its security overview. [21][2][22][23][6]
PlatformWorkload certificateSigning root or anchor
Istio 1.31, istiod CA24 h default, 2160 h maximumSelf-signed root 87600 h
Linkerd 2.2024 h, rotated automaticallyTrust anchor 365 days, issuer 1 year
Kubernetes 1.37 podCertificate24 h default, 1 h minimum, 91 days maximum (1 day for built-in signers)Set by the signer you deploy
ECS Service ConnectRotated every 5 days by default, 7 days maximum in short-lived modeThe AWS Private CA you provide
Google Cloud Service MeshNot statedManaged CA or CA Service
Figure 04

Defaults agree on one day; ceilings run to three months

Istio, Linkerd and pod certificates all default to 24 hours, but the documented maximums run from 1 to 91 days. [21][2][22][23]

Horizontal bar chart of documented maximum workload certificate lifetimes in days: Kubernetes built-in signers (none shipped yet) 1, ECS Service Connect short-lived CA mode 7, Istio maximum workload certificate TTL (MAX_WORKLOAD_CERT_TTL) 90, and Kubernetes podCertificate with other signers 91.

Source. Istio pilot-discovery environment reference (MAX_WORKLOAD_CERT_TTL 2160h), Kubernetes projected volumes documentation (maxExpirationSeconds at most 7862400, built-in signers at most 86400), Amazon ECS Service Connect TLS documentation (short-lived maximum seven days) and the Kubernetes v1.37 pod certificates announcement (no signers in core yet), reviewed October 9, 2026 and rechecked October 10, 2026. [21][22][23][24]

Method. Calculated: days equal hours divided by 24 or seconds divided by 86400; the ECS value is copied in days. Linkerd documents a 24-hour certificate but no configurable ceiling, and Google Cloud Service Mesh states no lifetime, so both are excluded.

Accessible table and figure data
Figure 4 accessible table
Platform and settingDocumented ceiling in days
Kubernetes built-in signers (none shipped yet)1
ECS Service Connect short-lived CA7
Istio maximum workload certificate TTL90
Kubernetes podCertificate, other signers91
Figure 4 accessible table
Platform and settingDocumented ceiling in days
Kubernetes built-in signers (none shipped yet)1
ECS Service Connect short-lived CA7
Istio maximum workload certificate TTL90
Kubernetes podCertificate, other signers91

Pod certificates are an issuance API, not a mesh

Kubernetes 1.37 is sometimes summarized as giving every pod an mTLS identity. Pod certificates, first available in 1.34, did become stable in 1.37, together with the older ClusterTrustBundle API, and the Kubernetes blog post announcing them is dated August 28, 2026. The kubelet generates a private key for each podCertificate volume source, creates a PodCertificateRequest addressed to a named signer, writes the issued chain into the container filesystem and refreshes it once the signer's beginRefreshAt time passes. The NodeRestriction admission plugin keeps one compromised node from requesting certificates for pods scheduled elsewhere, the same node check Istio requires of its ambient CA. [22][24][7]

What Kubernetes does not ship is a signer. The announcement says the project does not yet include any pod certificate signers in core, so trying the feature means installing a third-party signer. Its author's Tinycert is described as a starting point rather than a production solution, and one of its signers issues SPIFFE-compatible certificates naming the pod's namespace and service account. Any signer that Kubernetes later ships in core will issue certificates of at most 24 hours; other signers may go to 91 days. [24][22]

The API enforces nothing on the wire either. It delivers a key, a chain and trust anchors; the application, or a mesh that adopts the API, still has to require client certificates, verify them and decide what each identity may do. The application must reload the files when they change, ideally from the single credentialBundlePath file so it never pairs a new key with an old certificate. Signers receive userAnnotations copied into spec.unverifiedUserAnnotations, which the documentation tells them not to trust without verification. Istio's own support for ClusterTrustBundles is still marked experimental, behind ENABLE_CLUSTER_TRUST_BUNDLE_API. [22][1][28]

The motivation for the feature bears directly on what mTLS proves. The announcement contrasts certificates with service account JWTs, which are bearer tokens: whoever holds a copy is the identity, and every peer that receives one could replay it. A private key that stays in the pod gives proof of possession instead. Mesh mTLS gives each proxy the same property and carries the same limit, because the certificate still names a namespace and service account and proves nothing narrower about the caller. Projected tokens remain the route to cloud provider credentials. [24]

The trust domain ends at the mesh edge

Mesh identity is easy to picture as extending to whatever a service talks to. It ends where the proxies end. Linkerd states that it can enforce policy only on meshed pods and advises pairing policy with high-availability mode, which requires the proxy to be present when pods start, wherever policy is a strict requirement. Callers without a proxy, which can include batch pods, managed services and anything running in another cloud, reach a meshed service as plaintext, through a gateway, or with an identity system of their own. [14]

Gateways are where outside identity is converted, and the conversion can be loosened. Istio 1.31 implements the Gateway API AllowInsecureFallback option for client certificate validation: the gateway requests a client certificate but still admits the connection when none is presented or validation fails, and populates x-forwarded-client-cert so backends can verify for themselves. In that configuration a backend that trusts the gateway's principal without checking the header or a token holds no proof about the client at all. Egress is the mirror image; Istio's advice is an egress gateway made mandatory by NetworkPolicy, not REGISTRY_ONLY. [12][3]

Trust between clusters is configured, never inherited. Linkerd multicluster requires an explicit shared trust anchor. With its managed CA, Cloud Service Mesh fails authentication between different workload identity pools by default, and it supports identity-aware policies only across clusters in the same Google Cloud project. Multi-network multicluster ambient is still listed as beta in the Istio 1.31 feature status table. A service in another cloud that needs to call a meshed workload has a federation problem, with its own issuer, subject and audience checks. [2][6][19][28]

AWS App Mesh is the clearest case of a mesh ending outright. AWS ended support on September 30, 2026, after which the App Mesh console and resources are no longer accessible. AWS's migration guidance sends ECS users to Amazon ECS Service Connect and EKS users to Amazon VPC Lattice. Its September 24, 2024 comparison said App Mesh offered two-way peer authentication with mTLS, a feature not yet available for Service Connect, and the current Service Connect TLS page describes TLS 1.3 encryption with AWS Private CA certificates and managed rotation without describing client certificates. A reasonable reading is that teams who used App Mesh mTLS to authenticate callers need a replacement for that check, not only for routing. [25][26][23]

Prove it in your own cluster

Documentation describes defaults; only a test shows what one cluster actually does. Run these checks from a disposable namespace against harmless endpoints, and store the results with the policy revision they tested. Istio's migration task uses the same pattern: a client without a sidecar calls a service before and after STRICT is applied, and the second call fails, with curl reporting exit code 56. [13]

  • Plaintext from outside: from a pod with no proxy, call every port of each protected service and expect a refused or reset connection, not an HTTP response. [13]
  • Wrong identity: from a meshed pod running under a different service account in the same namespace, expect a denial; Linkerd documents HTTP 403 for HTTP traffic and a refused connection for everything else. [14]
  • Waypoint bypass: with a service-scoped waypoint, dial the pod IP directly; without a require-waypoint policy the request succeeds and skips layer 7 policy. [18]
  • Telemetry: on the destination side, look for istio_requests_total or istio_tcp_connections_opened_total with reporter="destination" and a connection_security_policy other than mutual_tls; in Linkerd, read the SECURED column of linkerd viz edges and the tls= field in linkerd viz tap. [27][7][10]
  • Exceptions: list portLevelMtls entries, capture-exclusion annotations and skip ports, and give each one an owner and an end date. [4][3][2]
  • Advisory pattern: search authorization policies for notNamespaces or notPrincipals on workloads that are still PERMISSIVE. [16]
Example read-only inventory and test fragment for Istio 1.31 using kubectl and jq. An HTTP status from the probe means plaintext reached the workload; a reset or refused connection means the mesh rejected it.
# Example read-only inventory for Istio 1.31 (needs kubectl and jq).
# Peer authentication modes, including port-level exceptions.
kubectl get peerauthentication -A -o json | jq -r '.items[] |
  [.metadata.namespace, .metadata.name, (.spec.mtls.mode // "UNSET"),
   ((.spec.portLevelMtls // {}) | tostring)] | @tsv'

# Pods that exclude ports from sidecar capture.
kubectl get pods -A -o json | jq -r '.items[] |
  select((.metadata.annotations // {}) | keys | any(test("exclude(Inbound|Outbound)Ports"))) |
  [.metadata.namespace, .metadata.name] | @tsv'

# Plaintext probe from a namespace with no injection or ambient label.
# Placeholder names; point it only at a test endpoint.
kubectl run mesh-probe -n no-mesh --rm -i --restart=Never \
  --image=curlimages/curl:8.10.1 -- \
  curl -sS -o /dev/null -w '%{http_code}\n' \
  http://orders.shop.svc.cluster.local:8080/healthz

When a mesh is not the right control

Mesh mTLS is the right tool for one job: authenticating and encrypting workload-to-workload connections inside a trust domain you operate, without changing application code. It becomes the wrong tool as soon as the question concerns something the certificate does not name. A workable rule follows from the sections above. If a decision depends only on which service account, in which namespace and trust domain, opened the connection, express it in mesh authorization. If it depends on a person, a tenant, a record or the business meaning of an action, check it at the gateway and in the application, using a token or session that the mesh merely carries.

Some callers fall outside the mesh altogether: workloads that cannot run a proxy, separate processes inside one pod, managed services, other clouds, and ECS services after App Mesh, where Service Connect's TLS documentation describes no client authentication. Give those callers an identity from their own system, such as cloud IAM or federated OIDC tokens, and use NetworkPolicy for connections that must never happen at all. Where a mesh is the right control, this order of operations gets the most from it.

  • Set STRICT, or Linkerd's all-authenticated or deny, one namespace at a time, and prove that plaintext from an unmeshed pod is refused.
  • Add default-deny authorization, allow by serviceAccounts or MeshTLSAuthentication identities, and move caller rules onto waypoints wherever one sits in the path.
  • Inventory every probe path, capture exclusion, skip port and port-level exception, and give each an owner.
  • Write down the trust domain and anchor: who can read the signing key, when the root or anchor expires, and which clusters share it.
  • Require end-user and tenant checks in tokens and application code, and test that a request with no token is rejected.

Method and provenance

Source-led analysis of Istio, Linkerd, Kubernetes, SPIFFE, Google Cloud, Microsoft and AWS documentation, release announcements and one Istio security advisory, organized as a test of common beliefs about mesh mTLS. Sources were reviewed on October 9, 2026. An independent fact-check on October 10, 2026 re-opened every source.

No mesh, cluster or cloud account was configured or tested. Behavior is limited to the cited documentation for Istio 1.29 to 1.31, Linkerd 2.20, Kubernetes 1.37 and the named managed services as of the review date; ambient waypoint routing in particular is documented as changing between releases.

AI assistance. AI assisted research synthesis, drafting, diagram planning and visual production, with deterministic editorial checks. No personal deployment experience, independent human review or live test is claimed.

Published under the Cloud Security Desk organizational byline. Read the practitioner guide policy.

References

  1. Security concepts (Istio 1.31 documentation) Istio. Accessed .
  2. Automatic mTLS (Linkerd 2.20 documentation) Linkerd. Accessed .
  3. PeerAuthentication reference (Istio 1.31) Istio. Accessed .
  4. Use Layer 4 security policy (Istio ambient) Istio. Accessed .
  5. Cloud Service Mesh security overview Google Cloud. Accessed .
  6. Ambient data plane (Istio architecture) Istio. Accessed .
  7. Supported releases (Istio) Istio. Accessed .
  8. Authorization Policy reference (Istio 1.31) Istio. Accessed .
  9. Announcing Istio 1.31.0 Istio. Published . Accessed .
  10. Mutual TLS migration (Istio task) Istio. Accessed .
  11. Authorization policy (Linkerd 2.20 documentation) Linkerd. Accessed .
  12. Configure waypoint proxies (Istio ambient) Istio. Accessed .
  13. Announcing Istio 1.29.0 Istio. Published . Accessed .
  14. Security policy examples (Istio) Istio. Accessed .
  15. Encrypt Amazon ECS Service Connect traffic Amazon Web Services. Accessed .
  16. Kubernetes v1.37: Pod Certificates and Cluster Trust Bundles Kubernetes. Published . Accessed .
  17. What is AWS App Mesh? (end of support notice) Amazon Web Services. Accessed .
  18. Migrating from AWS App Mesh to Amazon ECS Service Connect Amazon Web Services. Published . Accessed .
  19. Istio standard metrics Istio. Accessed .
  20. Feature Status (Istio 1.31 documentation) Istio. Accessed .