Kubernetes Network Policies Explained with Examples
Learn how Kubernetes NetworkPolicy objects work, why default deny matters, how ingress and egress selectors combine, and which CNI plugins actually enforce them.

On this page
A Kubernetes cluster is open by default. Every Pod can reach every other Pod unless something stops it, and the flat network that makes services easy to deploy also makes lateral movement easy. NetworkPolicy is the native object that lets you draw boundaries inside that flat network without leaving Kubernetes.
The confusion is usually not about syntax. It is about how policies combine, why a policy that looks correct has no effect, and which plugin is responsible for enforcing it. This guide covers the model, shows working examples, and points out the failure modes that make teams think NetworkPolicy is broken when it is doing exactly what the cluster was told.
What a NetworkPolicy Can and Cannot Do
A NetworkPolicy is a namespaced object. It selects a group of Pods with podSelector and declares allowed traffic in one or both directions using policyTypes. Ingress rules describe traffic arriving at the selected Pods, and egress rules describe traffic leaving them. Anything not explicitly allowed in a direction that is governed is denied.
The object is deliberately narrow. It works at Layer 3 and Layer 4, matching Pods, namespaces, IP blocks, ports, and protocols. It does not inspect HTTP paths or methods, it does not encrypt traffic, and it does not replace a service mesh for application layer controls. It also does not apply to traffic that uses the host network, which is why some system components appear to ignore policy.
The most important property is that policies are additive. There is no priority, no ordering, and no deny rule. If any policy that selects a Pod allows a flow, the flow is allowed, even if another policy is narrower. You build restrictions by starting from deny and adding allowances, not by writing exceptions to a broad allow.
Default Deny Is the Baseline
Kubernetes ships with no policies at all, which means all Pod to Pod traffic is allowed. The first useful policy in any namespace selects every Pod and permits nothing. This is the default deny posture, and it turns the cluster from open to closed so that every later policy is a deliberate, reviewable allowance.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: payments
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
An empty podSelector matches every Pod in the namespace. Because policyTypes lists both directions and the spec contains no ingress or egress rules, every connection is blocked. Existing connections are unaffected, but new connections are denied immediately, which is why you should stage default deny with the allowances ready.
Default deny is the right posture, but apply it namespace by namespace with the team that owns the workloads. A cluster wide switch that nobody planned for will page people at midnight for traffic that used to just work.
Select Pods, Then Decide Who May Connect
Ingress rules answer two questions: which Pods does this policy govern, and who is allowed to reach them. The governing selection is podSelector at the top level. Each entry in ingress has a from list and a ports list. Any entry that matches both the source and the port allows the connection.
Each item inside from is a peer, and a peer can reference Pods, namespaces, or IP blocks. Peers in the same list are ORed together, while selectors inside a single peer are ANDed. That single distinction explains most selector bugs.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-api
namespace: payments
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
This policy governs Pods labeled app: api and allows TCP 8080 only from Pods labeled app: frontend in the same namespace. To also allow a monitoring namespace, add a second peer. Combining a namespaceSelector and a podSelector in one peer means “Pods with these labels, in namespaces with those labels”, which is an AND, not an OR.
Use ipBlock for traffic to or from addresses outside the cluster, such as a managed database or a monitoring host. An ipBlock peer can include an except list to carve out subnets, and because it refers to raw addresses rather than Pods, a port on an ipBlock rule must be numeric.
Control Egress, Including DNS
Most teams start with ingress and forget egress. If your default deny policy lists Egress in policyTypes, Pods lose outbound access as well, including the DNS lookups that almost everything depends on. That is why a default deny will take down a healthy application even though it makes no inbound requests.
Allow DNS explicitly, scoped to the namespace that runs it, rather than opening all egress. Modern clusters label every namespace with kubernetes.io/metadata.name, which gives you a stable selector that does not depend on your own labels.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: payments
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Egress rules matter for reducing the blast radius of a compromised workload. A Pod that can only reach the database and the API server is far less useful to an attacker than one that can reach the whole cluster and the internet. When you allow egress to a service, remember that Pod IPs change, so selectors on Pod labels survive churn while hard coded addresses do not.
A frequent oversight is health checking. Kubelet runs on the node and probes Pods over the node network, which is not always governed the same way as Pod traffic. If probes start failing after you apply default deny, verify that the plugin and the cluster are treating node to Pod traffic as you expect before you assume the application is broken.
Which Plugin Actually Enforces Policies
NetworkPolicy is an API contract, not an implementation. The cluster’s network plugin decides whether the rules are enforced at all. Calico, Cilium, Antrea, and OVN-Kubernetes enforce them, and each adds its own extensions and observability. A plain Flannel installation does not, and neither does a default kind or minikube network in many configurations.
Managed services vary. GKE with Dataplane V2 uses Cilium and enforces policies. Legacy GKE Calico mode enforces them, while some clusters without a policy capable dataplane silently ignore the objects. Amazon EKS needs a policy capable option, since the default VPC CNI historically did not enforce native NetworkPolicy. Azure AKS supports either Cilium or Calico as the policy engine.
The dangerous case is a cluster that accepts the objects but does not enforce them. kubectl apply succeeds, the resource appears in kubectl get networkpolicy, and nothing changes. Before you rely on policies, confirm the dataplane with a controlled test: apply default deny to a scratch namespace and verify that a previously working connection now fails.
A Practical Adoption Plan
Roll policies out in a way that keeps the cluster working while you tighten it. Start by observing what actually talks to what, then write allowances that match reality, and only then switch to deny. A namespace that has never had policies is not ready for a blanket default deny on a Friday afternoon.
A workable sequence looks like this:
- Choose one namespace and identify its entry points, its dependencies, and its datastores.
- Write explicit allow policies for each known flow, including DNS and any egress to external services.
- Apply default deny in that namespace and watch the logs and error rates during business hours.
- Fix the gaps that appear, then repeat in the next namespace.
- Keep the policies in version control next to the workloads they protect, so a deploy and its network rules move together.
Review policies when services change, not only when incidents happen. A renamed label, a new dependency, or a database migration can leave an allow policy pointing at a selector that no longer matches anything, which is a slow outage waiting for the next deploy. The common TCP and UDP ports reference is useful when you are translating an application’s documented ports into policy rules.
What to Remember About Network Policies
NetworkPolicy gives you a flat network by default and a segmented one when you ask for it. The model is small: select Pods, declare the directions you govern, and list the peers and ports that are allowed. The difficulty is entirely in the details, which are worth restating.
- Policies are additive allow lists with no ordering and no deny rules.
- A direction is only restricted once a policy selects a Pod for that direction.
- Peers in a list are ORed, and selectors inside one peer are ANDed.
- Default deny also blocks DNS, so allow name resolution with the rest of your egress.
- Enforcement belongs to the CNI, so verify the dataplane before trusting the policy.
- Host network traffic and node level probes can behave differently and deserve testing.
Treat the policy set as part of the application, reviewed and deployed together with the workload, and it stops being a mysterious object that only matters during incidents.
Frequently Asked Questions
What does a Kubernetes NetworkPolicy do?
Is all traffic allowed by default in Kubernetes?
Do NetworkPolicies work on every Kubernetes cluster?
How do I block all traffic and then allow specific flows?
Free Tools
Put this into practice with the free calculators, reference tables, and checklists in the Obelinf toolkit.
Stop reaching for a spreadsheet
Obelinf keeps every subnet, device, circuit, and rack in one live source of truth, with audit logs and a topology view. Free for personal use.
Related Articles

Kubernetes CIDR Planning: A Practical Guide
Plan Kubernetes Pod, Service, Node, and Load Balancer networks with practical CIDR sizing, overlap checks, growth assumptions, and a worked example.
Read more
AWS VPC Design Best Practices: CIDR, Subnets, and Routing
Design an AWS VPC the right way: size the CIDR block, lay out public, private, and isolated subnets across availability zones, and wire route tables without common mistakes.
Read more
Fiber Optic Cable Types Explained: OS1, OS2, OM3, OM4
Understand single mode and multimode fiber grades, what OS1, OS2, OM3, OM4, and OM5 mean, how far each reaches, and how to pick the right cable for a run.
Read more