k8wiz
All graphs

Istio graph

Istio ambient mode: ztunnel, waypoint proxies and authorization without sidecars

How Istio ambient mode secures traffic with no sidecar: a namespace label enrolls Pods, ztunnel carries mTLS between nodes, a waypoint Gateway adds HTTP rules, and PeerAuthentication and AuthorizationPolicy decide who may call what.

Ambient mode splits what a sidecar did in two. A per-node proxy, ztunnel, gives every enrolled Pod an identity and mutual TLS at layer 4. HTTP features such as routing by path or authorizing by method run in a waypoint proxy, which you deploy only for the namespaces or services that need it.

Pods join by a label on their namespace, with no restart and no extra container. This graph shows one call from web to api through both layers.

Interactive graph

Click a resource to see what it does, or follow the setup step by step.

You write itComes with an add-onCreated by a controllerselects by labelreferencestrafficcreates

How it works

All 11 resources and what they do

Namespace shopv1
istio.io/dataplane-mode: ambient enrolls every Pod in the namespace. istio.io/use-waypoint sends traffic for its Services through the named waypoint.
DaemonSet ztunnelapps/v1
One per node. It takes over the traffic of enrolled Pods on its node, wraps it in mutual TLS over port 15008 (HBONE), and presents each Pod's own SPIFFE identity, taken from its ServiceAccount.
Pod web-5b7c9-…v1
The caller. It has one container and shows 1/1. Its plain HTTP request to api is picked up by the ztunnel on its node.
ServiceAccount webv1
The caller's identity in the mesh: cluster.local/ns/shop/sa/web. Authorization rules name this principal, so each workload needs its own ServiceAccount.
Gateway waypointgateway.networking.k8s.io/v1
A Gateway of class istio-waypoint. Istio turns it into an Envoy Deployment that handles layer 7 for the namespace's Services. istioctl waypoint apply -n shop --enroll-namespace creates it and labels the namespace.
Deployment waypointapps/v1
The Envoy Pods istiod creates for the Gateway. They scale like any Deployment, apart from the applications they serve.
PeerAuthentication defaultsecurity.istio.io/v1
STRICT makes ztunnel refuse plain text to the namespace's Pods. A caller outside the mesh gets a reset connection.
AuthorizationPolicy api-read-onlysecurity.istio.io/v1
An HTTP rule, so it attaches to the Service with targetRefs and is enforced by the waypoint: web may GET /orders/* on api and nothing else.
AuthorizationPolicy api-from-waypoint-onlysecurity.istio.io/v1
A layer 4 rule with a workload selector, enforced by ztunnel at the destination: only the waypoint's identity may connect to the api Pods. Without it a caller could skip the waypoint by using a Pod IP.
Service apiv1
What web calls. Because the namespace uses a waypoint, ztunnel sends traffic for this Service to the waypoint first.
Pod api-7f6d4-…v1
The destination. The ztunnel on its node ends the mutual TLS, checks the layer 4 policy and hands plain HTTP to the container.

Common mistakes

  • ztunnel only understands layer 4. An AuthorizationPolicy with a selector and HTTP fields such as methods or paths is not enforced as written: attach HTTP rules to the Service or the waypoint with targetRefs.
  • Deploying a waypoint does nothing until something uses it. The namespace or the Service needs the istio.io/use-waypoint label.
  • Identity comes from the ServiceAccount. Workloads that share default share one principal, and no policy can tell them apart.
  • A waypoint policy alone can be bypassed by calling a Pod IP. Add the layer 4 policy that admits only the waypoint's principal.
  • Pods that use hostNetwork are not captured, and a namespace with both sidecars and the ambient label should pick one mode per Pod.

The manifests you write

Everything above that is marked "You write it", in one file. The rest comes from add-ons and controllers.

apiVersion: v1
kind: Namespace
metadata:
  name: shop
  labels:
    istio.io/dataplane-mode: ambient
    istio.io/use-waypoint: waypoint
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: web
  namespace: shop
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: waypoint
  namespace: shop
  labels:
    istio.io/waypoint-for: service
spec:
  gatewayClassName: istio-waypoint
  listeners:
    - name: mesh
      port: 15008
      protocol: HBONE
---
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: default
  namespace: shop
spec:
  mtls:
    mode: STRICT
---
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: api-read-only
  namespace: shop
spec:
  targetRefs:
    - kind: Service
      group: ""
      name: api
  action: ALLOW
  rules:
    - from:
        - source:
            principals: ["cluster.local/ns/shop/sa/web"]
      to:
        - operation:
            methods: ["GET"]
            paths: ["/orders/*"]
---
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: api-from-waypoint-only
  namespace: shop
spec:
  selector:
    matchLabels:
      app: api
  action: ALLOW
  rules:
    - from:
        - source:
            principals: ["cluster.local/ns/shop/sa/waypoint"]
---
apiVersion: v1
kind: Service
metadata:
  name: api
  namespace: shop
spec:
  selector:
    app: api
  ports:
    - name: http
      port: 8080

Keep going

More graphs