Service Mesh (ASM) Ambient mode enforces authorization at two layers. Layer 4 policies, handled by ztunnel, control access based on workload identity at the transport layer. Layer 7 policies, handled by a waypoint proxy, add HTTP-level controls such as method and path restrictions. Use Layer 4 policies when identity-based access control is sufficient. Add a waypoint proxy and Layer 7 policies when you need fine-grained HTTP request filtering.
This walkthrough covers both layers using the Bookinfo sample application: first restricting access at Layer 4, then deploying a waypoint proxy to enforce Layer 7 rules.
How it works
ASM Ambient mode separates authorization enforcement into two layers:
Layer 4 (ztunnel): A Rust-based per-node proxy deployed as a DaemonSet. Ztunnel handles Layer 3 and Layer 4 traffic, including mTLS, identity verification, Layer 4 authorization, and observability for all pods on the node. Policies at this layer match on source identity, namespace, and IP, but not on HTTP attributes.
Layer 7 (waypoint proxy): An optional Envoy-based proxy that processes HTTP traffic. Deploy a waypoint when you need to enforce rules based on HTTP methods, paths, or headers.
When both layers are active, traffic flows through ztunnel first, then through the waypoint. The Layer 4 policy must explicitly allow the waypoint's ServiceAccount -- otherwise ztunnel blocks the waypoint's traffic before it reaches the target pod.
Supported Layer 4 policy attributes
Ztunnel evaluates only the following attributes. Any attribute outside this set requires a waypoint proxy for Layer 7 enforcement.
| Type | Attribute | Positive match | Negative match |
|---|---|---|---|
| Source | Peer identity | principals | notPrincipals |
| Source | Namespace | namespaces | notNamespaces |
| Source | IP block | ipBlocks | notIpBlocks |
| Operation | Destination port | ports | notPorts |
Layer 4 vs. Layer 7 policy targeting
| Aspect | Layer 4 (ztunnel) | Layer 7 (waypoint) |
|---|---|---|
| Targeting mechanism | selector with matchLabels | targetRefs pointing to a Service |
| Enforced by | ztunnel (per-node DaemonSet) | Waypoint proxy (Envoy) |
| Supported attributes | Identity, namespace, IP, port | All Layer 4 attributes + HTTP method, path, headers |
| Deployment requirement | None (always active in Ambient mode) | Requires a waypoint proxy |
If a policy containing Layer 7 attributes (such as methods or paths) is applied at Layer 4 through a workload selector instead of targetRefs, ztunnel cannot evaluate it and fails safe by denying all traffic matched by that policy. Always use targetRefs for policies that include HTTP-level rules.
Prerequisites
Before you begin, make sure that you have:
A running Bookinfo sample application with Ambient mode enabled. For more information, see Deploy the sample application and enable Ambient mode for encrypted communication
Deploy the test client
Deploy the Sleep application as a test client in your cluster:
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: sleep
---
apiVersion: v1
kind: Service
metadata:
name: sleep
labels:
app: sleep
service: sleep
spec:
ports:
- port: 80
name: http
selector:
app: sleep
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sleep
spec:
replicas: 1
selector:
matchLabels:
app: sleep
template:
metadata:
labels:
app: sleep
spec:
terminationGracePeriodSeconds: 0
serviceAccountName: sleep
containers:
- name: sleep
image: registry.cn-hangzhou.aliyuncs.com/acs/curl:8.1.2
command: ["/bin/sleep", "infinity"]
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /etc/sleep/tls
name: secret-volume
volumes:
- name: secret-volume
secret:
secretName: sleep-secret
optional: true
EOFEnforce Layer 4 access control
Layer 4 policies are enforced by ztunnel. The following steps restrict access to productpage so that only the ingress gateway's ServiceAccount can reach it.
Step 1: Apply the Layer 4 policy
Create an AuthorizationPolicy that allows only istio-ingressgateway to access pods with the app: productpage label:
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: productpage-ztunnel
namespace: default
spec:
selector:
matchLabels:
app: productpage
action: ALLOW
rules:
- from:
- source:
principals:
- cluster.local/ns/istio-system/sa/istio-ingressgateway
EOFStep 2: Verify browser access
Open http://<ingress-gateway-ip>/productpage in a browser. The page loads normally because the request arrives through the ingress gateway, whose ServiceAccount is allowed by the policy.
Step 3: Verify that the Sleep client is blocked
Send a request from the Sleep application:
kubectl exec deployment/sleep -- curl -s "http://productpage:9080/productpage" -IExpected output:
command terminated with exit code 56The connection is refused at the transport layer. Because ztunnel operates at Layer 4, no HTTP status code is returned -- the connection is dropped.
Add Layer 7 access control with a waypoint proxy
Layer 7 policies require a waypoint proxy. After deploying the waypoint, you label the namespace so that all service traffic passes through it. This enables HTTP-level authorization rules.
Step 1: Deploy a waypoint proxy
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: waypoint
spec:
gatewayClassName: istio-waypoint
listeners:
- name: mesh
port: 15008
protocol: HBONE
EOFStep 2: Wait for the waypoint to become ready
kubectl get gtwWait until the PROGRAMMED column shows True:
NAME CLASS ADDRESS PROGRAMMED AGE
waypoint istio-waypoint 172.16.99.15 True 2m29sStep 3: Route namespace traffic through the waypoint
Label the default namespace so that all service traffic is routed through the waypoint:
kubectl label namespace default istio.io/use-waypoint=waypoint --overwriteStep 4: Create the Layer 7 policy
This policy allows only the Sleep application to access productpage, and only with the GET method:
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: productpage-waypoint
namespace: default
spec:
targetRefs:
- kind: Service
group: ""
name: productpage
action: ALLOW
rules:
- from:
- source:
principals:
- cluster.local/ns/default/sa/sleep
to:
- operation:
methods: ["GET"]
EOFLayer 7 policies use targetRefs to attach to a specific service at the waypoint, rather than selector labels used in Layer 4 policies. The to field restricts allowed HTTP methods.
Step 5: Update the Layer 4 policy to allow waypoint traffic
The waypoint proxy now sits between clients and the productpage pods. Ztunnel sees the waypoint -- not the original client -- as the traffic source. Update the Layer 4 policy to include the waypoint's ServiceAccount:
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: productpage-ztunnel
namespace: default
spec:
selector:
matchLabels:
app: productpage
action: ALLOW
rules:
- from:
- source:
principals:
- cluster.local/ns/istio-system/sa/istio-ingressgateway
- cluster.local/ns/default/sa/waypoint
EOFStep 6: Verify the Layer 7 policy
Run three tests to confirm the policy works as expected.
Test 1: DELETE from Sleep (denied -- method not allowed)
kubectl exec deploy/sleep -- curl -s "http://productpage:9080/productpage" -X DELETEExpected output:
RBAC: access deniedThe Sleep ServiceAccount is allowed, but the DELETE method is not.
Test 2: GET from reviews-v1 (denied -- identity not allowed)
kubectl exec deploy/reviews-v1 -- curl -s http://productpage:9080/productpageExpected output:
RBAC: access deniedThe reviews-v1 ServiceAccount is not listed in the policy's principals.
Test 3: GET from Sleep (allowed)
kubectl exec deploy/sleep -- curl -s http://productpage:9080/productpage | grep -o "<title>.*</title>"Expected output:
<title>Simple Bookstore App</title>All three results match the policy configuration, confirming that both Layer 4 and Layer 7 authorization policies are working correctly.
What's next
Learn about Layer 4 policy attributes supported by ztunnel
Explore Layer 7 traffic features available through waypoint proxies
Read about waypoint proxy deployment and configuration