Kubernetes NetworkPolicy Generator
Build a NetworkPolicy with the DNS rule included by default, the cloud metadata endpoint excluded from any broad CIDR, and an explicit choice between ANDing and ORing your selectors. The output is checked by our own NetworkPolicy analyzer as you type.
networkpolicy.yaml
updates as you type Common mistakes
These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.
Applying a default deny with no DNS rule
Egress to kube-dns is blocked, so every name resolution fails and the symptom looks like a network fault rather than a policy.
Instead:Always include the DNS egress rule. This generator puts it in for that reason.
Expecting the policy to work on any CNI
The API server accepts NetworkPolicy objects whether or not the CNI implements them. On one that does not, they are stored and ignored.
Instead:Confirm the CNI enforces them before relying on any of it.
Adding an allow policy to carve an exception out of a deny
Policies are additive with no precedence and no deny rule. Traffic is allowed if any policy allows it.
Instead:Narrow the deny instead, or select a different set of pods.
How a NetworkPolicy decides what to allow
A NetworkPolicy is not a firewall rule, it is a whitelist that switches on. Pods are unrestricted until something selects them, and the moment anything does, everything not listed is denied. That switch is the source of nearly every surprise.
Selecting a pod flips it to deny by default
There is no ordering, no priority and no deny rule. Policies are purely additive: a pod's permitted traffic is the union of every policy that selects it. But a pod selected by no policy at all is completely open, and a pod selected by one policy is closed to everything that policy does not name. Applying your first policy to a namespace is the disruptive moment, not the tenth.
no policy selects this pod -> everything allowed
one policy selects it,
policyTypes: [Ingress] -> ingress: only what is
listed. egress: still
completely open.
policyTypes: [Ingress,
Egress] -> both now closed DNS is the one everybody forgets
The moment a policy gives a pod an Egress policyType, its outbound traffic is restricted, and DNS is outbound traffic. Without an explicit rule to kube-dns, nothing resolves. The application does not report a DNS failure: it reports that it cannot reach the database, so the investigation starts in the wrong place.
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- {port: 53, protocol: UDP}
- {port: 53, protocol: TCP} # not optional
# TCP matters: any response over 512 bytes falls back
# to it, which includes SRV records and busy namespaces. One list item ANDs, two list items OR
This is the difference between a correct policy and one far wider than intended, and the two forms differ by a single dash. Inside one item of the from list, namespaceSelector and podSelector must both match. As two separate items, either matching is enough.
from:
- namespaceSelector: {matchLabels: {env: prod}}
podSelector: {matchLabels: {app: web}}
# AND: pods labelled app=web, in prod namespaces only
from:
- namespaceSelector: {matchLabels: {env: prod}}
- podSelector: {matchLabels: {app: web}}
# OR: EVERY pod in prod namespaces, plus every
# app=web pod in this namespace Empty, absent, and what each one means
An empty map is not a blank. podSelector: {} at the top level selects every pod in the namespace, which is how a default-deny is written. Inside a from block the distinction between an empty selector and an omitted one changes the scope from this namespace to all namespaces, and both look like unfinished YAML.
spec:
podSelector: {} every pod in the namespace
policyTypes: [Ingress]
# no ingress key at all -> deny all inbound
from:
- podSelector: {} every pod in THIS namespace
- namespaceSelector: {} every pod in EVERY namespace It is the CNI that enforces this, not Kubernetes
The API server stores a NetworkPolicy whether or not anything implements it. On a cluster running plain flannel, or any CNI without policy support, the object is accepted, appears in kubectl get, and has no effect whatsoever. Calico, Cilium and the managed CNIs from the major clouds do enforce it. There is nothing in the object or in kubectl to tell you which case you are in.
kubectl get networkpolicy
NAME POD-SELECTOR AGE
api-policy app=api 3m
# this output is identical whether the policy is being
# enforced or completely ignored. Test it by actually
# trying a connection that should now fail.