In this episode you write your first network policy: inbound and outbound rules, layer 7 routing and request filtering, and how priority, scope, and matching rules work together to determine which requests are allowed through.

Welcome to episode 4 of the Learn OpenClaw series! In episode 3, OpenClaw was installed on your cluster and the sample application is running. Now we get to the core of a networking engineer's daily work: writing network policy and traffic rules. This is where OpenClaw's power becomes tangible: one language for managing who can talk to whom, which requests may pass, and how priority between rules is decided. We'll start with the anatomy of a policy, then build inbound, outbound, layer 7 routing, and finally priority and matching rules. Get your episode 3 cluster ready — all examples in this episode run against it.
An OpenClaw policy has three main parts: a selector (who is governed), match (when the policy applies), and rules (what is allowed or denied). Here's a minimal skeleton:
apiVersion: openclaw.io/v1
kind: Policy
metadata:
name: api-access
namespace: sample
spec:
selectors:
- matchLabels:
app: api
match:
from:
- app: web
rules:
- allow:
methods: [GET]The selector picks the protected workloads. Match determines the request conditions being evaluated — here, requests originating from app: web. Rules describe what happens when the condition is met.
Inbound policies govern traffic entering a service. A real example: service api may only accept requests from web, not from any other service:
apiVersion: openclaw.io/v1
kind: Policy
metadata:
name: api-allow-web
namespace: sample
spec:
selectors:
- matchLabels:
app: api
match:
from:
- app: web
rules:
- allow: {}Apply it and check its status:
kubectl apply -f api-allow-web.yaml{:bash}
kubectl get policy api-allow-web -n sample -o yamlNotice the status column: OpenClaw records whether the policy was successfully synced to the data plane. This is your first verification loop — make sure the status is successful before moving on.
Outbound policies govern traffic leaving a service. Example: web may only contact api and DNS services, not browse the internet freely:
apiVersion: openclaw.io/v1
kind: Policy
metadata:
name: web-egress-controlled
namespace: sample
spec:
selectors:
- matchLabels:
app: web
match:
to:
- app: api
- dns: true
rules:
- allow: {}This policy narrows web's "radius of movement". We'll deepen the outbound concept into egress management in episode 5, including how to manage access to external services outside the cluster.
At layer 7, policies can look deeper than IPs and ports — HTTP method, path, and headers are all available for filtering. For example, the old version of api (/v1) may only be accessed with GET, while the new version may use POST:
apiVersion: openclaw.io/v1
kind: Policy
metadata:
name: api-version-routing
namespace: sample
spec:
selectors:
- matchLabels:
app: api
match:
path: "/v1/**"
rules:
- allow:
methods: [GET]
- deny: {}Note the pattern above: requests to /v1/** are limited to GET, everything else is denied. For the new version, create a similar policy with match.path pointing to /v2/** and methods: [GET, POST, PUT]. Headers can also be used as a match condition, for example checking for the presence of a specific token before forwarding a request.
When several policies match the same request, the evaluation order is determined by priority. Smaller values win first:
apiVersion: openclaw.io/v1
kind: Policy
metadata:
name: deny-any-debug
namespace: sample
spec:
priority: 5
match:
path: "/debug/**"
rules:
- deny: {}
---
apiVersion: openclaw.io/v1
kind: Policy
metadata:
name: allow-api-default
namespace: sample
spec:
priority: 100
match:
from:
- app: web
rules:
- allow: {}The deny-any-debug policy with priority 5 is evaluated before allow-api-default (priority 100). So even though web is allowed by default, requests to /debug/** are still denied. This is the pattern of a strong but specific deny sitting on top of a broad allow.
Scope limits a policy's reach: per namespace, per cluster, or global. A policy scoped to a namespace only applies within that namespace, while a global policy governs all workloads:
apiVersion: openclaw.io/v1
kind: ClusterPolicy
metadata:
name: require-mtls-global
spec:
scope: cluster
match: {}
rules:
- require:
mTLS: trueMatching rules combine selector, from, to, path, method, and headers into a single expression. The golden rule: use the most specific match for deny policies and the most general match for allow policies. This pattern keeps deny from leaking onto other workloads and allow from creating security holes.
Warning
The default priority is a common trap. If you don't set priority explicitly, use kubectl describe policy <name> to see the default value and its evaluation against a sample request before deploying to another environment.
In episode 4 you wrote inbound and outbound network policies, used layer 7 routing and request filtering based on path and method, and understood how priority, scope, and matching rules work together to determine decisions.
Key takeaways:
In the next episode, episode 5, we'll cover ingress and egress management: ingress traffic configuration and TLS termination, egress control to external services, and gateway and route policies for mesh entry and exit points. You'll master the north-south and east-west intersections there.