| name | k8s-network-policy |
| description | Review Kubernetes NetworkPolicies — what is actually permitted to reach a workload, and whether the answer can be trusted. Use when asked what can talk to a pod, whether a namespace is restricted, why traffic is being blocked, or for any security review of cluster network segmentation. |
| version | 1.0.0 |
| license | Apache-2.0 |
| tags | ["kubernetes","k8s","networkpolicy","security","segmentation","audit","cni"] |
| user-invocable | true |
| metadata | {"openclaw":{"requires":{"bins":"[Truncated]","env":"[Truncated]"}}} |
Kubernetes NetworkPolicy Review
Server
k8s-mcp — vendored third-party (containers/kubernetes-mcp-server v0.0.66, Apache-2.0), a pinned
static Go binary. 7 tools, strictly read-only, Secrets denied.
⚠ Two rules before anything else
1. No NetworkPolicy means ALL traffic is permitted
Kubernetes is default-allow. A namespace with zero policies permits everything, in both directions.
So "no policies found" is not a neutral observation — it is a finding, and reporting it without the
consequence invites exactly the wrong conclusion. Someone reading "no policies" while thinking about
security will hear "nothing to worry about". The opposite is true.
Always say the consequence: "No NetworkPolicy applies to this workload, so all ingress and egress
traffic is permitted."
2. An empty result may mean you could not see, not that nothing exists
This is the one that gets people, and this server makes it worse.
Given a credential without cluster-wide list permission, the adopted server does not return an error.
It silently rewrites your cluster-wide query to a single namespace and hands back that result with no
caveat. Reproduced against a live cluster:
raw kubectl → Forbidden: cannot list networkpolicies at the cluster scope
this server → success, one policy ← the cluster actually had two
For a security review that is an audit lie: "no policy restricts this pod" when the truth is "I could
not see them".
The procedure — do this every time
Step 1 — confirm scope before you trust anything.
kubectl --kubeconfig $K8S_KUBECONFIG auth can-i list networkpolicies --all-namespaces
yes → cluster-wide answers are trustworthy. Proceed.
no → stop treating empty results as absence. Any answer you give is namespace-scoped at best, and
you must say so explicitly.
The supported deployment uses a dedicated cluster-wide-read ServiceAccount precisely so this returns yes
and the narrowing branch never executes. If it returns no, the deployment is misconfigured — say that
rather than working around it.
Step 2 — list the policies.
resources_list({"apiVersion": "networking.k8s.io/v1", "kind": "NetworkPolicy"})
resources_list({"apiVersion": "networking.k8s.io/v1", "kind": "NetworkPolicy", "namespace": "app1"})
Step 3 — report selectors, policy types and rules, not merely that a policy exists. "There is a policy"
tells a reviewer nothing about what is permitted. Give the podSelector, the policyTypes
(Ingress/Egress), and the actual from/to rules.
Step 4 — state the scope you actually queried, and which cluster answered. An operator with several
clusters must never have to guess.
The six reasons you get nothing back
| Cause | How to tell | How to say it |
|---|
| Permission insufficient | Step 1 returned no | "Scope could not be established — this is not evidence that no policies exist" |
| Namespace does not exist | namespaces_list does not contain it | "No such namespace" — not "no policies" |
| Namespace exists but is empty | it is in namespaces_list | "No policies in this namespace, so all traffic there is permitted" |
| Selector matched nothing | you passed a label selector | "No match for <selector>" — and show the selector, so a typo is visible |
| CRD not installed | GVK resolution error | "Cilium/Calico policies are not installed on this cluster" — a real error, distinguishable |
| Cluster unreachable | transport failure | "The cluster could not be reached" — never "no policies" |
A typo'd selector and a genuine non-match are identical over the wire — both return HTTP 200 with an
empty list. Showing the selector you used is the only thing that lets a reader spot the difference.
Completeness caveat
A namespace-scoped policy list is not a complete picture of what can reach a workload. Policies in other
namespaces, and cluster-scoped CRD policies (Cilium CiliumClusterwideNetworkPolicy, Calico
GlobalNetworkPolicy), also apply. Say so unless cluster-wide scope was confirmed and CRDs were checked.
Traffic observed is not traffic permitted
kubeshark-traffic shows packets that flowed. This shows what is declared. They answer different
questions and are constantly confused:
- Traffic flowing does not prove a policy permits it — the policy may have been added after.
- No traffic does not prove a policy blocks it — nothing may have tried.
When both are used, report them as two kinds of evidence, never as one conclusion.
Boundaries
| Want to… | Use |
|---|
| See actual packets | kubeshark-traffic — observed traffic, not declared config |
| Workload metrics | prometheus, grafana |
| Build a lab | containerlab, gns3, cml |
| Service/ingress path | k8s-service-path |
| Pod inventory | k8s-workload-inventory |
| Change anything | nothing here. Strictly read-only; no mutation is reachable |
Rules
- Run the Step 1 preflight. An empty result without confirmed scope is not an absence.
- Never report "no policies" without "therefore all traffic is permitted."
- Show the selector and the scope in every answer.
- Say which cluster answered.
- Read-only. Secrets are denied and no mutation exists.