MastertheMesh
Solo Enterprise for Istio · Reference
Visual reference

Istio Ambient CRDs — a visual map

TO
Tom O'Rourke
EMEA Field CTO · Solo.io

Every CRD that still matters in Istio Ambient, who watches it (istiod), and where it actually lands — ztunnel at L4, waypoint at L7, istio-cni for traffic redirection. YAML you can copy for each one.

Istio Ambient ztunnel · waypoint Gateway API istiod controller

If you know sidecar Istio, here's what shifted: VirtualService + DestinationRule + PeerAuthentication still exist, but routing is moving to Gateway API and the dataplane is now split in two. Some CRDs moved house, some became no-ops, the rest land in a different place than they used to.

The dataplane is now two layers. A per-node ztunnel does L4 + mTLS for every workload in an ambient-enabled namespace. A waypoint proxy — per service, per namespace, or per service account — handles the L7 stuff (HTTP routing, JWT, L7 authz), but only when you opt in. Kubernetes Gateway API is the new front door: it's how you declare both your edge ingress and your waypoints.

What follows is the map. A diagram, then YAML for each CRD group, then a full table at the bottom so you can see at a glance where each resource ends up being enforced.

How the pieces fit together

CONTROL PLANE istio-system CRDs · watched by istiod DATA PLANE · programmed via xDS istiod CONTROLLER · OPERATOR · CA Watches CRDs  →  computes xDS  →  signs SPIFFE certs pushes config to ztunnel, waypoint, ingress gateways Deployment · namespace: istio-system SECURITY security.istio.io/v1 PeerAuthentication mTLS mode (STRICT / PERMISSIVE) RequestAuthentication JWT issuers, JWKS AuthorizationPolicy L4 → ztunnel · L7 → waypoint GATEWAY API gateway.networking.k8s.io/v1 Gateway declares ingress + waypoints HTTPRoute L7 routing, header / path match TCPRoute · TLSRoute · GRPCRoute protocol-specific routing ReferenceGrant cross-namespace permission NETWORKING (LEGACY) networking.istio.io/v1 VirtualService routing — prefer HTTPRoute DestinationRule subsets, outbound mTLS, LB ServiceEntry external / off-mesh services Sidecar N/A in Ambient (legacy) WORKLOAD & TELEMETRY networking · telemetry · extensions WorkloadEntry single VM / non-K8s endpoint WorkloadGroup VM auto-registration template Telemetry traces, metrics, access logs WasmPlugin · EnvoyFilter advanced — waypoint / gateway istio-cni-node DaemonSet · per node Sets up pod-network redirection into the local ztunnel via iptables / nftables / eBPF No CRDs — driven by namespace label ztunnel DaemonSet · per node · Rust L4 + mTLS (HBONE tunnels) SPIFFE identity per workload L4 AuthorizationPolicy enforced here Programmed via xDS by istiod waypoint Deployment · per ns / svc / SA · Envoy L7 — HTTP routing, JWT, L7 AuthZ, retries, traffic shifting, WasmPlugin Created from a Gateway (Gateway API) Opt-in: label workload istio.io/use-waypoint xDS (gRPC) redirects HBONE L7 Opt in: namespace label istio.io/dataplane-mode=ambient · workload label istio.io/use-waypoint=<name>
security.istio.io Gateway API networking.istio.io (legacy) workload · telemetry · extensions controller / dataplane

How to read it: CRDs in the middle, istiod on top watching them. istiod chews the CRDs into xDS and pushes config down to the three things at the bottom — istio-cni-node hooks pod traffic into ztunnel, ztunnel handles L4 + mTLS, and the waypoint handles anything that needs L7 (HTTP, JWT, L7 authz). If a CRD doesn't appear here, it's either a label (see the footnote) or not used in Ambient.

What a request actually does

Pod in an ambient namespace talks to a service that has a waypoint — here's the actual path. The waypoint is optional: if you don't need L7, traffic stays on the ztunnel fast path and never touches a waypoint at all.

Client podyour app
ztunnel (src node)HBONE · mTLS
waypointL7 policy (optional)
Destination podvia dest ztunnel

The CRDs, group by group

One section per family, with copy-paste YAML. The colour stripe matches the diagram. Start with the opt-in labels — there's no "enable ambient" CRD, it's just a namespace label, and that's easy to miss.

🏷️ Opt-in labels prerequisite

Not a CRD — and that's the gotcha. Turning a namespace into ambient is a label, and binding a workload to a waypoint is another label. Easy to miss because the namespace label looks innocuous.

Namespace · enrol into ambientlabel only — no CRD
apiVersion: v1
kind: Namespace
metadata:
  name: bookinfo
  labels:
    # Every pod in this namespace will be captured by ztunnel.
    istio.io/dataplane-mode: ambient
    # Optional: bind every workload in this namespace to a waypoint.
    istio.io/use-waypoint: bookinfo-waypoint

What each label does

istio.io/dataplane-mode: ambient
The actual enrolment label. Every pod in this namespace gets captured by ztunnel on the node — encrypted east-west over HBONE, SPIFFE identity, L4 authz. Strictly necessary; without it the namespace stays plain Kubernetes.
istio.io/use-waypoint
Optional. Routes the namespace's traffic through the named waypoint Gateway, which is where L7 features (HTTP authz, JWT, retries, header transforms) live. The same label can be applied per-Service or per-Pod for finer scope (next example).

These are labels, not CRDs — they don't show up in kubectl get crd or in most policy-audit tooling, which is the gotcha. Adding the label to an existing namespace needs a pod restart before ztunnel starts capturing traffic. To exclude a single pod from ambient inside an enrolled namespace, set istio.io/dataplane-mode: none on the pod.

Service or Pod · bind to a waypointfiner-grained opt-in
# Bind a single Service to a waypoint (preferred over per-pod).
apiVersion: v1
kind: Service
metadata:
  name: reviews
  namespace: bookinfo
  labels:
    istio.io/use-waypoint: reviews-waypoint
spec:
  selector:
    app: reviews
  ports:
    - port: 9080
      name: http

Where to put the label

istio.io/use-waypoint on a Service
Routes traffic addressed to this Service's ClusterIP through the named waypoint. Useful when you want L7 policy on a handful of services without conscripting an entire namespace.
istio.io/use-waypoint on a Pod
Routes traffic to that pod's IP through the named waypoint (workload-scoped waypoint). Rare — most policies are scoped to services, not individual pods.

Scope precedence: Pod-level beats Service-level beats Namespace-level. Setting istio.io/use-waypoint: none on a Service or Pod opts that one resource out of an otherwise-enrolled namespace. The waypoint itself is declared by the Gateway example in the Gateway API section below; this label only points to it.

🔐 Security security.istio.io/v1

Identity, mTLS, JWT, authz — the four things the security team will ask about. The split that matters: anything L4 (principals, namespaces, ports) ends up on ztunnel; anything that looks at an HTTP header needs a waypoint. Write an L7 rule with no waypoint and it silently does nothing — easy to miss.

PeerAuthentication · require STRICT mTLS in a namespaceenforced by ztunnel
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: default
  namespace: bookinfo
spec:
  mtls:
    mode: STRICT   # PERMISSIVE | DISABLE | UNSET

What each mode does

STRICT
Reject anything that isn't mTLS. The only mode that actually enforces zero-trust on inbound — use this as the destination state for every namespace.
PERMISSIVE
Accept both mTLS and plaintext. The migration default — lets off-mesh clients keep reaching the workload while you enrol them. In Ambient, meshed → meshed is always mTLS via HBONE regardless of this setting; PERMISSIVE only affects what unenrolled / off-mesh callers can do.
DISABLE
Plaintext only — mTLS handshakes are refused. Niche (e.g. fronting a non-mesh proxy that handles TLS itself); almost never what you want in production.
UNSET
Inherit from the next-broader scope. Resolution order: workload selector → namespace default → mesh-wide istio-system/default. With nothing set anywhere, the effective default is PERMISSIVE.
AuthorizationPolicy · L4 — only the productpage SA may reach reviewsztunnel · L4
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: reviews-allow-productpage
  namespace: bookinfo
spec:
  selector:
    matchLabels:
      app: reviews
  action: ALLOW
  rules:
    - from:
        - source:
            principals:
              - cluster.local/ns/bookinfo/sa/bookinfo-productpage

How to read this policy

selector
The workload being protected — every pod labelled app: reviews in the bookinfo namespace. The policy is enforced by ztunnel on the destination side of the connection.
action: ALLOW
Whitelist semantics. Once any ALLOW policy targets a workload, every connection that doesn't match an ALLOW rule is denied — there's an implicit "deny everything else".
from.source.principals
The allowed callers, by SPIFFE workload identity. cluster.local/ns/bookinfo/sa/bookinfo-productpage = the bookinfo-productpage ServiceAccount in the bookinfo namespace. Anything else reaching reviews is dropped at ztunnel before the connection is forwarded to the pod.

"L4" means ztunnel matches on workload identity, namespace and port — not on HTTP method, path or headers. To filter on those, target a waypoint and add a to.operation rule (see the L7 example below).

AuthorizationPolicy · L7 — only GET /reviews/* through the waypointwaypoint · L7
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: reviews-read-only
  namespace: bookinfo
spec:
  # Bind to the waypoint, not directly to the workload.
  targetRefs:
    - kind: Gateway
      group: gateway.networking.k8s.io
      name: reviews-waypoint
  action: ALLOW
  rules:
    - to:
        - operation:
            methods: ["GET"]
            paths:   ["/reviews/*"]

Where this is enforced — and why both fields matter

targetRefs
This is what makes the policy L7. It attaches the policy to the reviews-waypoint Gateway — the waypoint is the only thing in Ambient that parses HTTP, so it's the only enforcement point that can match on methods, paths or headers. Swap targetRefs for a selector (as in the L4 example above) and the policy lands on ztunnel instead.
to.operation
The HTTP L7 conditions themselves — methods, paths, headers, hosts. They only take effect when the enforcement point can read HTTP. Put a to.operation block on a selector-attached policy and ztunnel silently ignores those fields; the L4 parts (principals, namespaces, ports) still apply, the L7 parts don't.

Short answer: both are needed. targetRefs picks the enforcement point (waypoint = L7-capable). to.operation uses that L7 capability. Either one without the other either degrades to L4 silently, or attaches nothing meaningful. Also note: traffic must actually be routed through the waypoint (via a Gateway + HTTPRoute, or the istio.io/use-waypoint label) — a policy on a waypoint that nothing traverses is a no-op.

HTTP only. AuthorizationPolicy's to.operation is the upstream Istio schema — it understands HTTP attributes and nothing else. Same on every waypoint flavour: OSS istio-waypoint, Solo's istiod-gloo waypoint, and the enterprise-agentgateway-waypoint. For MCP tool-level or A2A skill-level enforcement, you need a separate Solo Enterprise CRD — EnterpriseAgentgatewayPolicy (enterpriseagentgateway.solo.io/v1alpha1) — which targets the agentgateway and matches on attributes like mcp.tool.name, mcp.tool.target and A2A skill names. agentgateway is the only proxy here that parses MCP/A2A frames; kgateway and native Istio waypoints speak HTTP/gRPC and use AuthorizationPolicy as shown above. See the Agentic / MCP lab for the full example.

RequestAuthentication · accept JWTs from an issuerwaypoint · L7
apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata:
  name: jwt-on-reviews
  namespace: bookinfo
spec:
  targetRefs:
    - kind: Gateway
      group: gateway.networking.k8s.io
      name: reviews-waypoint
  jwtRules:
    - issuer: "https://issuer.example.com"
      jwksUri: "https://issuer.example.com/.well-known/jwks.json"
      audiences: ["reviews-api"]

What this does — and what it doesn't

targetRefs
Attaches the policy to the waypoint Gateway. Same logic as the L7 AuthorizationPolicy above — JWTs live in the Authorization HTTP header, and the waypoint is the only thing in Ambient that parses HTTP. Use selector instead and ztunnel silently does nothing with it.
jwtRules.issuer
The required iss claim. A token whose iss doesn't match is rejected with a 401 from the waypoint.
jwtRules.jwksUri
Where istiod fetches the issuer's signing keys (JWKS) to verify the JWT signature. istiod caches and periodically refreshes them, so the istiod-to-issuer network path must be open — not the workload-to-issuer path.
jwtRules.audiences
Allowed aud claim values. A token whose aud isn't in this list gets a 401 even if the signature is valid — guards against replay of tokens minted for a different service that shares an issuer.

RequestAuthentication doesn't deny on its own. If a request has a token and it's invalid (bad signature, wrong issuer, wrong audience), the waypoint returns 401. But if the request has no token at all, this policy lets it through — it only validates tokens that are present. To actually require authentication, pair it with an AuthorizationPolicy that requires request.auth.principal != "" or specific claims. Valid claims surface to AuthorizationPolicy as request.auth.*. See the JWT / OIDC / on-behalf-of page for the full pairing pattern.

🛣️ Gateway API gateway.networking.k8s.io/v1

In Ambient, Gateway isn't just for ingress — it's also how you declare a waypoint (different gatewayClassName, same kind). HTTPRoute attaches to either, and that's where VirtualService-style routing lives now.

Gateway · declare a waypoint for one namespaceistiod will create the Envoy Deployment
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: bookinfo-waypoint
  namespace: bookinfo
  labels:
    # Waypoint scope: service | workload | all
    istio.io/waypoint-for: service
spec:
  gatewayClassName: istio-waypoint
  listeners:
    - name: mesh
      port: 15008
      protocol: HBONE

How this becomes a running waypoint

gatewayClassName: istio-waypoint
The signal to istiod that this Gateway is an east-west waypoint, not an ingress. istiod reconciles it into an Envoy Deployment + Service on your behalf — no Helm chart, no Pod spec. Same kind as the ingress example below; the class is what flips the role.
istio.io/waypoint-for
What the waypoint intercepts. service (default) handles traffic addressed to Service VIPs — the normal case. workload handles traffic addressed directly to pod IPs (rare; useful for headless services). all handles both.
listeners.port: 15008 · protocol: HBONE
Fixed values for a waypoint. HBONE is Ambient's HTTP/2 CONNECT tunnel-over-mTLS, and 15008 is the well-known HBONE port — ztunnel terminates the client side and forwards the inner request to the waypoint here. Don't change either.
metadata.name
This is how consumers find the waypoint: the istio.io/use-waypoint label on namespaces, Services or Pods refers to it by name (see the opt-in labels section above).

A waypoint is only invoked if the source is ambient-enrolled and the destination opts in. If the calling pod's namespace doesn't have istio.io/dataplane-mode: ambient, or the destination Service/namespace/pod isn't labelled istio.io/use-waypoint, ztunnel forwards L4 directly and the waypoint is skipped entirely — which is why an L7 policy can look perfectly correct and still do nothing.

Gateway · ingress gateway at the cluster edgereplaces legacy Istio Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: bookinfo-gateway
  namespace: bookinfo
spec:
  gatewayClassName: istio
  listeners:
    - name: http
      port: 80
      protocol: HTTP
      allowedRoutes:
        namespaces:
          from: Same

Same kind, different role

gatewayClassName: istio
Picks the north-south ingress controller. istiod provisions a Deployment + LoadBalancer Service named <gateway-name>-istio. Contrast with istio-waypoint (east-west L7) and istio-eastwest / istio-remote (multi-cluster peering over HBONE). The class is the only thing that tells these apart.
listeners.protocol: HTTP
An ordinary client-facing listener — terminates traffic from outside the cluster. Not HBONE; not 15008. HTTPS needs a tls block with a cert Secret.
allowedRoutes.namespaces.from
Which namespaces' HTTPRoutes may attach to this Gateway. Same (shown) = same namespace only. All = any namespace. Selector = namespaces matching a label selector. Cross-namespace backendRefs on a route additionally need a ReferenceGrant in the backend's namespace.

Ingress → waypoint handoff is not automatic. If the route's backend Service lives in a namespace that uses a waypoint, set istio.io/ingress-use-waypoint: "true" on the Service — otherwise the ingress sends straight to the pod IP and any L7 policy on the waypoint is bypassed (and any AuthorizationPolicy that expects the waypoint identity will 403). For new installs this Gateway replaces the legacy networking.istio.io/v1 Gateway + VirtualService pair, though both APIs still coexist.

HTTPRoute · 80/20 canary split between v1 and v2attached to a waypoint
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: reviews-split
  namespace: bookinfo
spec:
  parentRefs:
    - name: reviews-waypoint
      kind: Gateway
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /reviews
      backendRefs:
        - name: reviews-v1
          port: 9080
          weight: 80
        - name: reviews-v2
          port: 9080
          weight: 20

What the route actually does

parentRefs → the waypoint Gateway
This is what makes it an east-west route. The same HTTPRoute kind attached to the istio-class ingress Gateway is a north-south route — only the parent changes the role. The route can only act on traffic that actually flows through this parent.
matches.path.PathPrefix: /reviews
Scopes the rule to that URL prefix; requests to any other path on this waypoint fall through to the default backend (the Service that the route's host normally resolves to). Add a separate rules: entry to handle other paths.
backendRefs.weight
Relative ratio — weights don't have to sum to 100 (1/4 behaves the same as 20/80). The waypoint's Envoy rolls the dice per request. port: 9080 is the backend Service's port, not the waypoint's.

The route only fires if traffic reaches the waypoint. For an east-west split, the caller's namespace needs istio.io/dataplane-mode: ambient and the destination Service/namespace needs istio.io/use-waypoint: reviews-waypoint — otherwise ztunnel L4-forwards straight to the canonical Service VIP and the split is silently bypassed. Cross-namespace backendRefs additionally need a ReferenceGrant in the backend namespace.

🧭 Networking (legacy) networking.istio.io/v1

Don't write these off. DestinationRule and ServiceEntry are still the cleanest way to do subsets, outbound TLS, and pulling external services into the mesh. VirtualService still works on a waypoint, but for new config reach for HTTPRoute instead. Sidecar is dead code in Ambient.

ServiceEntry · register an external API into the meshrequired for ztunnel/waypoint to know about it
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
  name: external-api
  namespace: bookinfo
spec:
  hosts:
    - api.external.example.com
  ports:
    - number: 443
      name: https
      protocol: HTTPS
  resolution: DNS
  location: MESH_EXTERNAL

What each field does

hosts
The DNS names this entry registers into istiod's service registry. Required. Wildcards (*.example.com) are allowed, but a bare "*" is rejected. This is how the rest of Istio refers to the external service — DestinationRule.host, HTTPRoute backends, AuthorizationPolicy hosts must all match one of these.
ports
The protocols the mesh should expect on which ports. Misnaming the port (protocol: TCP for an HTTPS endpoint, etc.) means ztunnel/waypoint can't apply protocol-specific policy and traffic falls back to passthrough.
resolution: DNS
istiod resolves the hostnames on the workloads' behalf and pushes the resulting endpoints. Other options: STATIC (you supply endpoints explicitly), NONE (let the OS resolve at connection time — passthrough), DNS_ROUND_ROBIN (single endpoint at a time, refreshed by TTL).
location: MESH_EXTERNAL
Declares that the destination isn't part of the mesh — no SPIFFE identity is expected on the other end, so mTLS won't be attempted unless a DestinationRule says so. Use MESH_INTERNAL (paired with workloadSelector) for non-Kubernetes workloads that are meshed, e.g. a VM with an istio agent.

Without a ServiceEntry, the external host is invisible to the mesh. ztunnel doesn't know to capture traffic to it, the waypoint has no routing config for it, and any DestinationRule / AuthorizationPolicy / HTTPRoute written against the host name binds to nothing. Traffic still leaves the pod (assuming egress is open), it just leaves unmanaged — no mTLS origination, no L7 policy, no metrics under that host. exportTo (default: all namespaces) controls which workloads can see this entry; set it to scope down.

DestinationRule · outbound TLS to an external serviceapplied at waypoint
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: external-api-tls
  namespace: bookinfo
spec:
  host: api.external.example.com
  trafficPolicy:
    tls:
      mode: SIMPLE
      sni: api.external.example.com

What each tls.mode means

SIMPLE
The proxy originates a one-way TLS connection upstream — the workload sends plaintext to the waypoint, the waypoint wraps it in TLS to the external host. The classic "let Istio handle TLS to a third-party API" pattern.
MUTUAL
Same as SIMPLE, plus the proxy presents a caller-supplied client certificate (paths to cert/key in clientCertificate/privateKey). For external services that require mTLS with a cert you've been issued.
ISTIO_MUTUAL
Use the workload's own Istio-issued SPIFFE identity as the client cert. Only meaningful for in-mesh destinations — the other end has to be running an Istio proxy that trusts the same root. Mostly redundant in Ambient because meshed → meshed is already mTLS via HBONE.
DISABLE
Send plaintext. Use to opt out of mTLS to a specific destination that would otherwise get it.

In Ambient, this DestinationRule is applied at the waypoint — not at ztunnel. ztunnel handles L4 forwarding and mTLS-between-peers, but features like TLS origination, subsets, outlier detection, retries and locality LB live in Envoy. So for this rule to fire, the caller's namespace must be ambient-enrolled and the destination must be routed through a waypoint (typically via istio.io/use-waypoint on the ServiceEntry's namespace, or a waypoint that targetRefs the SE). A DR for a host that nothing routes through a waypoint silently does nothing. sni is usually needed when the upstream serves multiple names from one IP — the host header is L7-app, the SNI is what TLS handshakes on.

🛰️ Workload & Telemetry networking · telemetry · extensions

The grab-bag. VMs into the mesh via WorkloadEntry / WorkloadGroup, tracing and access logs via Telemetry, and Wasm modules into the waypoint Envoy when something is genuinely too custom for the rest of Istio. Use EnvoyFilter as the last resort it's always been.

WorkloadEntry · a single VM endpointnetworking.istio.io/v1
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
  name: legacy-billing-vm
  namespace: billing
spec:
  address: 10.20.30.40
  ports:
    http: 8080
  labels:
    app: billing
    version: v1
  serviceAccount: billing-sa

What each field is for

address
The VM's reachable IP (or DNS name) from the cluster pod network. This is what istiod hands to ztunnel/waypoint as the endpoint address. Required (unless network is set for multi-network routing).
ports
Map from port name → port number. The names must match a Service's port names — that's how Kubernetes Services bridge to the VM. Different port number, same name.
labels
Exactly the same selector mechanism as a Pod's labels — a Service with selector: { app: billing } will pick up this VM as an endpoint alongside any pods with the same label.
serviceAccount
The SPIFFE identity istiod issues for this VM — here cluster.local/ns/billing/sa/billing-sa. Without it the VM has no mesh identity, so other workloads can't write AuthorizationPolicy rules against it and STRICT mTLS calls to it will fail.

Rarely declared on its own. Usually paired with a WorkloadGroup — a Deployment-like template that auto-creates a WorkloadEntry for each VM that joins via the istio agent's onboarding flow. Ambient VM support is newer than sidecar VM support and still maturing — at time of writing, ambient pulls VMs in via a separate workload-onboarding mechanism rather than running ztunnel on the VM itself, so check the version compatibility matrix and your istio release notes before standing up production ambient VMs. The matching Service (selector hits these labels) still has to exist for the VM to be addressable cluster-side.

Telemetry · 100% trace sampling for one namespacetelemetry.istio.io/v1
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
  name: full-trace
  namespace: bookinfo
spec:
  tracing:
    - randomSamplingPercentage: 100.0
      providers:
        - name: otel

What this turns on

tracing.randomSamplingPercentage: 100.0
Sample every request — but only when the proxy has to make the call itself. If an upstream proxy already made a sampling decision (the standard tracing headers carry it), that decision is honoured and this percentage is ignored. So in practice the first proxy a request hits is the one that decides.
providers.name: otel
Refers to a tracing provider declared in mesh MeshConfig (extensionProviders) — typically an OTel collector or Zipkin/Jaeger endpoint. The name must match an entry in MeshConfig exactly; a typo here means no spans are exported and the rule silently does nothing.
no selector / targetRefs
Applies to every workload in the bookinfo namespace. Resolution order is workload → namespace → mesh-wide (istio-system) — more specific wins. Use targetRefs to a waypoint Gateway to scope tracing to traffic that goes through that waypoint specifically.

In Ambient, trace spans come from the waypoint, not from ztunnel. ztunnel emits L4 connection metrics and access logs, but it doesn't generate distributed-tracing spans — it's not Envoy. So a namespace with 100% sampling but no waypoint still gets you the L4 traffic graph in Kiali, but Jaeger/Tempo will be empty: there is nothing in the data path producing spans. Same Telemetry CRD also configures accessLogging (per-request log lines) and metrics (tag overrides, custom dimensions) — split across separate sibling blocks under spec.

WasmPlugin · attach a Wasm module to a waypointextensions.istio.io/v1alpha1
apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
  name: header-stamper
  namespace: bookinfo
spec:
  targetRefs:
    - kind: Gateway
      group: gateway.networking.k8s.io
      name: reviews-waypoint
  url: oci://registry.example.com/wasm/header-stamper:v1
  phase: AUTHN

What each field does

targetRefsGateway (gateway.networking.k8s.io)
Attaches the module to a waypoint Gateway. In Ambient this is the only attachment that works: ztunnel is Rust and doesn't host Wasm modules, so any attempt to attach a WasmPlugin to a non-waypoint ambient workload via selector is a no-op. Ingress Gateways also work because they're Envoy too. (For sidecar mesh, selector attaches directly to workload sidecars.)
url
Where the Wasm module is fetched from. Valid schemes: oci://, https://, http://, file:// (file requires the binary to already be on the proxy's filesystem). The pull happens on the waypoint pod itself, so the registry has to be reachable from the cluster — and from the waypoint pod's serviceaccount/network policy specifically.
phase: AUTHN
Where the module slots into the filter chain. AUTHN runs before built-in authentication filters (good for transforming incoming credentials), AUTHZ runs between authn and authz (good for custom permission checks), STATS runs last (good for metrics/logging). Order across multiple plugins in the same phase is controlled by priority — higher first.

Use this in preference to EnvoyFilter. WasmPlugin is the supported, versioned extension API; EnvoyFilter is the back-door that's brittle across Istio upgrades. Add imagePullSecret for private OCI registries, sha256 to pin a known-good build, and failStrategy: FAIL_CLOSE (default) to drop traffic if the module crashes — FAIL_OPEN bypasses it instead, which can be the right call for non-security filters. As with every waypoint-attached policy: only takes effect on traffic that actually traverses the waypoint, so the usual ambient enrolment + istio.io/use-waypoint opt-in still has to be in place.

Full reference table

One row per CRD, plus a couple of labels that count as honorary CRDs because you'll use them constantly. The column that matters most is Programmed at — that's where the resource actually gets enforced, and the single most useful thing to know when something isn't behaving the way you expect.

Resource Group API What it does Programmed at
PeerAuthentication security security.istio.io/v1 Sets mTLS mode (STRICT / PERMISSIVE / DISABLE) for workloads in scope. ztunnel
RequestAuthentication security security.istio.io/v1 Validates JWTs (issuer, audiences, JWKS). Populates a request.auth.* context for AuthZ. waypoint
AuthorizationPolicy security security.istio.io/v1 Allow/deny rules. L4-only (principals, namespaces, ports) → ztunnel; anything HTTP-aware → waypoint. ztunnel · waypoint
Gateway gateway-api gateway.networking.k8s.io/v1 Declares a network entry point — ingress at the edge, or a waypoint inside the mesh. waypoint · ingress envoy
HTTPRoute gateway-api gateway.networking.k8s.io/v1 HTTP routing: path/header/method match, weighted backends, retries, header rewrites. waypoint · ingress envoy
TCPRoute · TLSRoute · GRPCRoute gateway-api gateway.networking.k8s.io/v1alpha2 Protocol-specific routing on a Gateway. TCP/TLS pass-through, gRPC method matching. waypoint · ingress envoy
ReferenceGrant gateway-api gateway.networking.k8s.io/v1beta1 Permits a Route in namespace A to reference a backend in namespace B. istiod (admission)
VirtualService networking networking.istio.io/v1 Legacy L7 routing. Supported, but prefer HTTPRoute in Ambient. waypoint · ingress envoy
DestinationRule networking networking.istio.io/v1 Subsets, outbound TLS, load-balancer policy, connection pools. waypoint
ServiceEntry networking networking.istio.io/v1 Registers external endpoints (or VMs) so they're addressable from the mesh. ztunnel · waypoint
Sidecar networking networking.istio.io/v1 Sidecar-mode only — not used in Ambient. n/a (Ambient)
WorkloadEntry workload networking.istio.io/v1 Single VM / non-K8s endpoint registered into the mesh with identity + labels. ztunnel · waypoint
WorkloadGroup workload networking.istio.io/v1 Template + auto-registration for fleets of VMs. istiod
Telemetry telemetry telemetry.istio.io/v1 Sampling, custom tags, access-log format, OpenTelemetry / Zipkin providers. ztunnel · waypoint
WasmPlugin extensions extensions.istio.io/v1alpha1 Loads a Wasm filter into the waypoint's Envoy at a chosen phase. waypoint
EnvoyFilter extensions networking.istio.io/v1alpha3 Raw Envoy escape-hatch — bind it to waypoints or ingress gateways. Use sparingly. waypoint · ingress envoy
ProxyConfig networking networking.istio.io/v1beta1 Per-namespace / per-workload Envoy concurrency, log level, image overrides. waypoint · ingress envoy
Namespace label istio.io/dataplane-mode label Opts the namespace into ambient — istio-cni redirects pod traffic into ztunnel. istio-cni · ztunnel
Workload label istio.io/use-waypoint label Routes a service/pod/SA's traffic through a named waypoint. ztunnel · waypoint

Where to go from here

The CRDs here are grouped (Security · Gateway API · Networking · Workload & Telemetry) the same way the upstream Istio API reference does, so once you've found what you want here, jumping into the field-level docs should feel natural rather than like a second search.

For Ambient itself the two reference pages to keep open are the Ambient docs and the Gateway API site. Once the config surface makes sense, the runtime side is the other half of the picture — pair this with the Ambient metrics & alerting reference for when something starts misbehaving in prod.