Home / Kubernetes

Cloud Service Mesh on GKE: mTLS, Traffic Splitting & Authorization Policies | 2026

Cloud Service Mesh on GKE: mTLS, Traffic Splitting & Authorization Policies | 2026

Cloud Service Mesh (CSM) — Google's managed Istio control plane for GKE — automatically encrypts all pod-to-pod communication with mutual TLS (mTLS) without touching application code. On top of encryption, it provides a rich traffic management layer: canary deployments via VirtualService weight splitting, circuit breakers via DestinationRule, and fine-grained authorization with AuthorizationPolicy. This guide walks through enabling CSM on GKE, configuring STRICT mTLS PeerAuthentication, deploying a canary traffic split, and locking down service-to-service access with authorization policies.

By Mateusz Chmielewski · Aug 29, 2026 · 16 min read

What is Cloud Service Mesh?

Cloud Service Mesh (CSM) is Google's managed service mesh based on Istio. It injects Envoy sidecar proxy containers into every pod in enabled namespaces. These proxies handle all inbound and outbound traffic, enforcing mTLS encryption, traffic routing policies, retry logic, and observability — entirely transparently to your application code.

Think of a microservice without a service mesh like a conversation in an open-plan office — anyone nearby can hear your messages, and there's no record of who said what. Cloud Service Mesh is like giving every employee a secure encrypted walkie-talkie with an ID badge. All communications are encrypted, logged, and only authorized employees can contact specific departments — your application code just 'talks', the walkie-talkie handles everything else.

ConceptExplanationWhen to use
Envoy Sidecar ProxyA high-performance L7 proxy container automatically injected alongside every application container in mesh-enabled namespaces.Automatically managed by CSM — no explicit configuration needed.
PeerAuthenticationIstio custom resource that configures mTLS mode (PERMISSIVE or STRICT) for traffic between pods within a namespace.Set to STRICT in production to enforce encrypted pod-to-pod communication.
VirtualServiceDefines traffic routing rules — weight splitting between service versions, retries, timeouts, and header-based routing.Deploy for canary releases, A/B testing, or blue-green rollouts.
DestinationRuleConfigures traffic policies for a target service — load balancing algorithm, connection pool limits, circuit breaker thresholds.Pair with VirtualService for complete traffic management.
AuthorizationPolicyIstio RBAC policy that permits or denies requests between services based on source service account, namespace, or request attributes.Restrict which services can call each other — implements zero-trust service-to-service access control.

mTLS Service Mesh vs Plain Kubernetes Networking

Default Kubernetes pod networking transmits all inter-service HTTP traffic in plaintext. Any compromised pod or rogue container in the cluster can sniff or spoof traffic between microservices. Standard Kubernetes NetworkPolicies operate at L3/L4 and cannot authenticate service identity.

Cloud Service Mesh enforces mutual TLS authentication and encryption at L7 between every pair of communicating pods. SPIFFE/SPIRE identity certificates are automatically rotated every 24 hours. AuthorizationPolicies add fine-grained service identity-based access control beyond what NetworkPolicy provides. Pair with [GKE Gateway API](/tutorial/gke-gateway-api-replace-ingress-multi-service-routing) for ingress routing and enforce image provenance via [Binary Authorization](/tutorial/binary-authorization-artifact-registry-signed-images-gke).

FeaturethisServicealtAaltB
EncryptionCSM: mTLS L7 (pod-to-pod, automatic)Kubernetes NetworkPolicy: None (L3/L4 only)Manual TLS: App-level code required
Service IdentitySPIFFE X.509 SVIDs (automatically rotated)IP-based (spoofable)Manual certificate management
Traffic SplittingVirtualService weights (0-100%)Deployment replica ratio onlyLoad balancer rules (manual)
ObservabilityAutomatic L7 metrics, traces, and topologyL4 flow logs onlyApplication-instrumented only
Access ControlAuthorizationPolicy (service account identity)NetworkPolicy (IP CIDR based)Application-level API keys

Prerequisites

  • GKE cluster (Standard or Autopilot) running Kubernetes v1.28+
  • Cloud Service Mesh feature enabled on the GKE fleet
  • kubectl and istioctl CLIs configured
  • gcloud CLI v480.0+ authenticated

Step-by-Step Guide

Step 1: Enable Cloud Service Mesh on GKE Fleet

Register your GKE cluster to a GCP Fleet and enable the Cloud Service Mesh managed feature. Fleet registration allows Google's managed CSM control plane to inject Envoy sidecars and synchronize mesh configuration without self-managing an Istiod control plane.

# Step 1: Register GKE cluster to Fleet
gcloud container fleet memberships register prod-gke-cluster \
  --gke-cluster=europe-west1/prod-gke-cluster \
  --enable-workload-identity \
  --project=PROJECT_ID

# Step 2: Enable Cloud Service Mesh feature on Fleet
gcloud container fleet mesh enable --project=PROJECT_ID

# Step 3: Enable CSM on the specific cluster membership
gcloud container fleet mesh update \
  --management=automatic \
  --memberships=prod-gke-cluster \
  --project=PROJECT_ID \
  --location=global

# Step 4: Enable sidecar injection on target namespace
kubectl label namespace production istio-injection=enabled

Step 2: Configure STRICT mTLS with PeerAuthentication

Apply a PeerAuthentication resource to enforce STRICT mTLS across the production namespace. PERMISSIVE mode accepts both plaintext and mTLS traffic during migration. STRICT mode rejects all non-mTLS connections, ensuring zero unencrypted traffic within the mesh.

# peer_authentication.yaml — Enforce STRICT mTLS in production namespace
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default-strict-mtls
  namespace: production
spec:
  mtls:
    mode: STRICT

Step 3: Deploy VirtualService and DestinationRule for Canary Traffic Splitting

Route 95% of traffic to the stable service version and 5% to the canary version using VirtualService weight configuration. VirtualService traffic splitting enables progressive delivery — gradually shifting traffic to a new version while limiting blast radius if bugs are detected.

# destination_rule.yaml — Define stable and canary subsets
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: api-service-destinations
  namespace: production
spec:
  host: api-service
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100
      http:
        h2UpgradePolicy: UPGRADE
  subsets:
    - name: stable
      labels:
        version: v1
    - name: canary
      labels:
        version: v2
---
# virtual_service.yaml — 95/5 traffic split
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: api-service-split
  namespace: production
spec:
  hosts:
    - api-service
  http:
    - route:
        - destination:
            host: api-service
            subset: stable
          weight: 95
        - destination:
            host: api-service
            subset: canary
          weight: 5
      timeout: 10s
      retries:
        attempts: 3
        perTryTimeout: 3s

Step 4: Create AuthorizationPolicy for Zero-Trust Service Access

Restrict which services can call the payments API using AuthorizationPolicy bound to Kubernetes service account identities. Without AuthorizationPolicy, any compromised pod in the cluster can send requests to sensitive services like payment processors. SPIFFE identity-based access control prevents lateral movement.

# authorization_policy.yaml — Allow only checkout-service to call payments-api
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: payments-api-access-policy
  namespace: production
spec:
  selector:
    matchLabels:
      app: payments-api
  action: ALLOW
  rules:
    - from:
        - source:
            principals:
              - "cluster.local/ns/production/sa/checkout-service-account"
      to:
        - operation:
            methods: ["POST"]
            paths: ["/v1/payments/*"]
---
# Deny-all fallback policy (deny everything not explicitly allowed)
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: payments-api-deny-all
  namespace: production
spec:
  selector:
    matchLabels:
      app: payments-api
  action: DENY
  rules:
    - from:
        - source:
            notPrincipals:
              - "cluster.local/ns/production/sa/checkout-service-account"

Step 5: Observe Mesh Traffic with Cloud Trace and Monitoring

Verify mesh telemetry using Cloud Monitoring service mesh dashboards and Cloud Trace distributed tracing. CSM automatically exports L7 RED metrics (Request rate, Error rate, Duration) to Cloud Monitoring without any application instrumentation.

# Step 1: Check mesh proxy injection status
kubectl get pods -n production -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].name}{"\n"}{end}'

# Expected output includes 'istio-proxy' alongside each app container:
# api-deployment-abc123    api-server istio-proxy
# payments-api-xyz456      payments-api istio-proxy

# Step 2: Verify mTLS connection between services
istioctl authn tls-check -n production checkout-pod payments-api.production.svc.cluster.local

# Step 3: View service mesh topology in Cloud Console
# Navigate: GKE -> Service Mesh -> Topology -> production namespace

Verification & Health Check

Best Practices

  • Start with PERMISSIVE mTLS Before Enforcing STRICT
  • Scope AuthorizationPolicy with Explicit Deny-All Fallback

Common Mistakes

  • {"errorCode":"SIDECAR_NOT_INJECTED","symptoms":"Pods start successfully but traffic is not encrypted. `kubectl describe pod` shows only one container per pod.","rootCause":"The namespace label `istio-injection=enabled` was not present before pod creation, or the pod has annotation `sidecar.istio.io/inject: 'false'`.","fixCommand":"kubectl label namespace production istio-injection=enabled --overwrite && kubectl rollout restart deployment -n production","code":"kubectl label namespace production istio-injection=enabled --overwrite\nkubectl rollout restart deployment --namespace=production\n","language":"bash","filename":"fix_injection.sh","prevention":"Automate namespace labeling in Terraform using `kubernetes_namespace` resource with the label."}

Cost Analysis

Featuremetriccost1kcost10kcost100kcost1m
CSM Managed Control Plane$0.00$0.00$0.00$0.00 / month
Envoy Sidecar Memory Overhead (~50MB per pod)~$8.00/mo~$8.00/mo~$8.00/mo~$96.00/yr
Cloud Trace (mesh distributed tracing)$0.20/M spans$0.20/M spans$0.20/M spans~$24.00/yr

References

Browse all tutorials