Onboarding a Namespace to Ambient Mode With L7 Policy
Your cluster runs Istio 1.22 in sidecar mode for eight namespaces. The analytics namespace (12 Deployments serving gRPC on 9090 and HTTP on 8080) is being moved to ambient mode. You label the namespace istio.io/dataplane-mode=ambient, restart the pods, and istioctl ztunnel-config workloads shows the analytics pods handled by ztunnel with mTLS. You then apply an AuthorizationPolicy that allows only GET /v1/report from service account reporter, plus a RequestAuthentication for your JWT issuer. Testing shows every HTTP path is still allowed and the JWT is not validated. After you add Layer 7 enforcement, gRPC clients start seeing connection resets roughly 60 seconds into long-lived streams. A NetworkPolicy in analytics currently allows ingress only on 8080 and 9090 from istio-system. The existing istio-ingressgateway in istio-system must expose analytics at reports.example.com.
1. Why do the HTTP-path authorization rules and JWT validation have no effect even though mTLS clearly works, and what exactly do you deploy to fix it?
Read the worked answer
Ambient splits enforcement into two layers, and you have only deployed one of them.
- ztunnel runs per node and provides L4 identity and mTLS. It can enforce L4 policy: source identity, namespace, port. It cannot see HTTP methods, paths, headers or JWT claims, because it does not terminate HTTP.
- Waypoint proxy is an Envoy-based per-namespace (or per-service) L7 proxy that receives traffic over HBONE and enforces HTTP routing, retries and L7 AuthorizationPolicy/RequestAuthentication.
So an AuthorizationPolicy with to.operation.methods/paths or when: request.auth.claims[...] is simply beyond ztunnel's reach. Configure a waypoint for analytics:
- Confirm the Gateway API CRDs are installed - the waypoint is a
GatewaywithgatewayClassName: istio-waypoint. istioctl waypoint apply -n analytics --enroll-namespacecreates the waypoint and labels the namespace so all services in it use it. Service-level control is available via theistio.io/use-waypointlabel on a Service if you want a narrower scope.- Verify the Gateway is programmed and appears in
istioctl proxy-status; also re-checkistioctl ztunnel-config workloadsto confirm traffic for analytics is now redirected to the waypoint. - Re-apply and retest: with the waypoint in the data path, an unauthenticated request should now get 401/403 rather than 200.
Do not expect existing sidecar-era assumptions to hold: there is no sidecar to inspect locally, and istioctl x authz check on a pod will not explain ambient denials. Read the waypoint's config and logs instead.
2. Long-lived gRPC streams now reset about 60 seconds in. What are the likely causes given the NetworkPolicy, and how do you confirm which one it is?
Read the worked answer
Once the waypoint is enrolled, the traffic path changes from "ztunnel to app port" to "ztunnel to waypoint over HBONE, waypoint to app". HBONE listens on TCP 15008 on the waypoint. A NetworkPolicy that allows only 8080 and 9090 from istio-system blocks that leg.
Two candidate mechanisms fit the 60-second signature:
- Blocked HBONE path / half-open connections. Packets to 15008 are dropped rather than rejected, so a stream that looks established can hang until a keepalive or app deadline fires. A reset at a suspiciously round interval is characteristic of a keepalive timing out, not of immediate connection refusal.
- Idle/keepalive mismatch on the waypoint or app. gRPC keepalive or an HTTP/2 max connection age on the waypoint can terminate long streams even when connectivity is fine.
Distinguish them:
- Compare a short unary call (works?) with a long stream (fails?). If unary calls succeed, the path is up and the problem is stream lifetime, not policy.
- Inspect the waypoint's access logs and Envoy stats for resets and for
upstream_reset_before_response_startedstyle flags. - Temporarily add an explicit allow for TCP 15008 from istio-system (and from any other namespace that must reach the waypoint) and retest. If the resets stop, it was the NetworkPolicy.
- If they persist, look at max stream duration and keepalive settings on the waypoint and on the gRPC server.
Fix by making the path explicit in policy: allow 15008 between ztunnel and waypoint, document it as a mesh requirement, and add a test that asserts a stream longer than the previous failure point succeeds.
3. The sidecar-mode ingress gateway in istio-system must serve analytics at reports.example.com. What has to be true for that to work end to end in ambient mode?
Read the worked answer
The ingress gateway does not need to be ambient; it only needs a valid path to the analytics workloads, and that path now includes the waypoint.
Required pieces, in order:
- Routing objects are visible to the gateway. A
Gatewayin istio-system withhosts: [reports.example.com]bound to the ingressgateway Deployment, and aVirtualServicein analytics (or in istio-system) that lists that gateway, uses matching hosts, and routes to the analytics Service port 8080. WatchexportTo: withexportTo: ["."]the VirtualService is only visible to gateways in its own namespace, and the gateway in istio-system will return 404 NR despite the objects looking correct. - Network path to the workload. The gateway's sidecar resolves the analytics Service and connects to a pod IP on 8080. ztunnel on the destination node intercepts and enforces L4 policy. If the waypoint is enrolled, the connection is redirected to the waypoint, so the gateway namespace must be able to reach TCP 15008 on the waypoint as well as 8080 on the pods. With the current NetworkPolicy allowing only 8080/9090, ingress will fail once the waypoint exists - this is the same gap that broke the gRPC streams.
- Authorization accounts for the gateway identity. If the policy only allows principal
cluster.local/ns/analytics/sa/reporter, requests arriving from the ingress gateway's service account are denied. Either add an explicit allow for the gateway principal on the public route, or terminate JWT validation at the waypoint for external traffic and authorize on claims. - TLS. Terminate at the gateway and re-originate inside the mesh; do not rely on plaintext passthrough to the app.
Verify from the outside in: curl -v https://reports.example.com/v1/report, then the gateway access log, then waypoint logs, then ztunnel connection state. The first hop that shows no traffic tells you which of the four is missing.