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
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.
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
ztunnelon 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-waypointon 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-waypointon 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;
PERMISSIVEonly 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-wideistio-system/default. With nothing set anywhere, the effective default isPERMISSIVE.
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: reviewsin thebookinfonamespace. The policy is enforced byztunnelon the destination side of the connection. action: ALLOW- Whitelist semantics. Once any
ALLOWpolicy targets a workload, every connection that doesn't match anALLOWrule 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= thebookinfo-productpageServiceAccount in thebookinfonamespace. 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-waypointGateway — 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. SwaptargetRefsfor aselector(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.operationblock 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
AuthorizationPolicyabove — JWTs live in theAuthorizationHTTP header, and the waypoint is the only thing in Ambient that parses HTTP. Useselectorinstead and ztunnel silently does nothing with it. jwtRules.issuer- The required
issclaim. A token whoseissdoesn'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
audclaim values. A token whoseaudisn'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
Gatewayis an east-west waypoint, not an ingress. istiod reconciles it into an EnvoyDeployment+Serviceon your behalf — no Helm chart, no Pod spec. Samekindas 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.workloadhandles traffic addressed directly to pod IPs (rare; useful for headless services).allhandles both. listeners.port: 15008·protocol: HBONE- Fixed values for a waypoint. HBONE is Ambient's HTTP/2
CONNECTtunnel-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-waypointlabel 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+LoadBalancerService named<gateway-name>-istio. Contrast withistio-waypoint(east-west L7) andistio-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.
HTTPSneeds atlsblock with a certSecret. 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-namespacebackendRefson a route additionally need aReferenceGrantin 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 waypointGateway- This is what makes it an east-west route. The same
HTTPRoutekind attached to theistio-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/4behaves the same as20/80). The waypoint's Envoy rolls the dice per request.port: 9080is 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,HTTPRoutebackends,AuthorizationPolicyhosts must all match one of these. ports- The protocols the mesh should expect on which ports. Misnaming the port (
protocol: TCPfor 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 supplyendpointsexplicitly),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
DestinationRulesays so. UseMESH_INTERNAL(paired withworkloadSelector) 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 inclientCertificate/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
networkis 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
Servicewithselector: { 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 writeAuthorizationPolicyrules 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
bookinfonamespace. Resolution order is workload → namespace → mesh-wide (istio-system) — more specific wins. UsetargetRefsto 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
targetRefs→Gateway(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
WasmPluginto a non-waypoint ambient workload viaselectoris a no-op. Ingress Gateways also work because they're Envoy too. (For sidecar mesh,selectorattaches 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.
AUTHNruns before built-in authentication filters (good for transforming incoming credentials),AUTHZruns between authn and authz (good for custom permission checks),STATSruns last (good for metrics/logging). Order across multiple plugins in the same phase is controlled bypriority— 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.