Chris Collins

Tools · containers

Kubernetes NetworkPolicy and Pod Security checker

Paste NetworkPolicies, pods and namespaces (or kubectl get -o yaml output) and ask whether one pod can reach another on a port, with the policies that allow it or the reason it's blocked; a colour-coded pod × pod matrix, a lint, a policy builder, and a Pod Security Standards checker that lists every failing field and its fix.

Added

How to use it

"Why can’t the API reach the database?" usually comes down to one of a handful of NetworkPolicy rules: a pod is isolated as soon as any policy selects it, a connection needs egress from one side and ingress on the other, and a namespaceSelector and a podSelector mean something different in one list item than in two. This page applies those rules to the objects you paste and shows its working.

How to use it

Paste YAML or JSON into the box — NetworkPolicies plus the Pods (or Deployments, StatefulSets, DaemonSets, Jobs) and Namespaces they talk about. The easiest source is kubectl get ns,pods,svc,netpol -A -o yaml; kind: List output is unpacked. Without namespace objects, each namespace only has the kubernetes.io/metadata.name label the API server adds to every namespace. The built-in example is a three-tier shop (web → api → db) with a default deny, DNS egress, a named port, a port range and Prometheus scraping from another namespace.

  • Can A reach B? Pick a source and a destination — a pod, a Service (checked against each backend pod on its target port, since policies see pod addresses, not the Service’s), or an address outside the cluster — a port and a protocol. The answer shows both sides: the source’s egress policies and the destination’s ingress policies, each rule with its peers and ports ticked or crossed and the reason (namespace default: namespaceSelector team=ops doesn’t match its labels).

  • Matrix checks every pod against every pod, on one port or on each destination’s declared container ports, plus an outside address. Green is allowed, red denied, amber some ports. Click a cell for the explanation.

  • Policies and lint describes each policy in plain words and flags problems: empty peers, ipBlock mixed with selectors, except outside the CIDR, endPort with a named port, lower case protocols, policies that select nothing, a podSelector that only matches pods in another namespace, selectors split into two peers (OR) where one peer (AND) was probably meant, egress: [] without policyTypes (which does not isolate egress), and egress isolation with no way to reach DNS.

  • Builder writes the common patterns: default deny for ingress, egress or both, allow DNS, allow from the same namespace, from labelled pods, from another namespace, from labelled pods in another namespace, from the ingress controller, from or to an IP range with exceptions. Add to the input puts the policy into the other tabs.

  • Pod Security checks Pods and pod templates against the Baseline and Restricted Pod Security Standards: host namespaces, privileged, capabilities, hostPath, host ports, AppArmor, SELinux, /proc mount, seccomp, sysctls, volume types, privilege escalation, running as non-root, and dropping all capabilities. Each failing field is listed with its path and the fix; namespace labels (pod-security.kubernetes.io/enforce: baseline) show whether admission would reject the pod, and Fix for Restricted rewrites the manifest with the mechanical fixes and lists what you have to decide yourself.

Related tools: the Kubernetes manifest builder (forms for every kind, NetworkPolicy included), the Kubernetes simulator, the kubectl helper, DevOps YAML linting, and the firewall packet tracer for the iptables and nftables rules that kube-proxy and network plugins write on a node.

How faithful it is

The evaluator follows the "Network Policies" page of the Kubernetes documentation and the networking.k8s.io/v1 API. I checked it three ways:

  • On a real cluster. The example’s namespaces, pods and policies were applied to a throwaway kind cluster (Kubernetes 1.37, whose kindnet plugin enforces NetworkPolicy) and every pod tried a TCP connection to every other pod’s ports. All 32 results match. A second round changed the Prometheus peer from AND to OR and added an ipBlock with except; those match too, using the cluster’s own kubectl get -o yaml output as input.

  • Against the documentation’s examples and statements: the test-network-policy example (which sources reach port 6379, the except range, the egress CIDR), default deny and allow-all policies, endPort, the AND/OR selector section, and namespace targeting by kubernetes.io/metadata.name.

  • Against the behaviour each recipe in Ahmet Alp Balkan’s kubernetes-network-policy-recipes describes (deny all, limit to an app, allow from a namespace, from some pods in another namespace, external traffic, one port, multiple selectors, egress denies).

The Pod Security checker was compared with Pod Security Admission itself: 25 pods sent with kubectl apply --dry-run=server to namespaces enforcing Baseline and Restricted got the same level here as from the API server, failing the same controls.

What it doesn’t model:

  • The network plugin. NetworkPolicy is enforced by the CNI plugin, and Flannel on its own ignores it. Plugins differ where the API leaves room: whether ipBlock applies to pod IPs (the page notes it when an answer depends on that), traffic that was source-NATed through a Service or load balancer, hostNetwork pods (undefined in the API; usually unaffected), and traffic from the pod’s own node, which is allowed. kindnet, for one, lets all UDP port 53 traffic through without looking at policies.

  • Other policy APIs: Cilium’s and Calico’s own CRDs (layer 7, FQDNs, ordered deny rules, global policies) and AdminNetworkPolicy / BaselineAdminNetworkPolicy are out of scope.

  • The Pod Security edge cases: the controls are those of the current standard ("latest"); pinned older versions (enforce-version: v1.24) and exemptions in the admission configuration aren’t applied.

Browser support

Any current browser.

Privacy

Everything runs in this page; nothing you paste is sent anywhere and the page makes no network requests. Your input is kept in this browser’s local storage. Manifests can contain internal names and addresses — think before sharing a link, because a share link carries them.

Runs entirely in your browser; nothing you type leaves this page.