L11. Network Policies: Ingress, Egress and Default Deny
Video generating
Check back soon for the video lesson on Network Policies: Ingress, Egress and Default Deny
By default, every pod can talk to every other pod. Network Policies let you enforce microsegmentation at the namespace and pod level. Learn how to implement default-deny and whitelist-only rules.
The Default: No Isolation
In a default Kubernetes cluster, any pod can communicate with any other pod across all namespaces. There is no firewall, no segmentation, no access control on the network layer.
This means a compromised pod in a development namespace can reach databases in production, scan for other services, and attempt lateral movement.
How Network Policies Work
Network Policies are namespace-scoped resources that select pods using labels and define allowed ingress (incoming) and egress (outgoing) traffic. They are enforced by the CNI plugin (Calico, Cilium, Antrea) and not by Kubernetes itself. Critical requirement: Your CNI must support Network Policies. Some CNIs (like Flannel) do not enforce them. Use Calico, Cilium, or Antrea for production clusters.
Default Deny All
The first Network Policy in every namespace should be a default deny:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
<ul class="list-disc pl-6 mb-4 space-y-2">
<li class="text-slate-300">Ingress</li>
<li class="text-slate-300">Egress</li>
</ul>An empty podSelector selects all pods. With no ingress or egress rules defined, all traffic is blocked. You then whitelist specific flows.
Allowing Specific Traffic
After default deny, add policies for legitimate traffic:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-web-to-api
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
<ul class="list-disc pl-6 mb-4 space-y-2">
<li class="text-slate-300">Ingress</li>
</ul>
ingress:
<ul class="list-disc pl-6 mb-4 space-y-2">
<li class="text-slate-300">from:</li>
<li class="text-slate-300">podSelector:</li>
</ul>
matchLabels:
app: web
ports:
<ul class="list-disc pl-6 mb-4 space-y-2">
<li class="text-slate-300">protocol: TCP</li>
</ul>
port: 8080This allows pods labeled app: web to reach pods labeled app: api on port 8080. All other ingress to the API pods is blocked.
Cross-Namespace Rules
To allow traffic from another namespace, use namespaceSelector:
ingress:
<ul class="list-disc pl-6 mb-4 space-y-2">
<li class="text-slate-300">from:</li>
<li class="text-slate-300">namespaceSelector:</li>
</ul>
matchLabels:
environment: monitoring
podSelector:
matchLabels:
app: prometheusThis allows Prometheus pods in namespaces labeled environment: monitoring to scrape metrics.
DNS Egress
Default deny blocks DNS too. Always allow egress to the cluster DNS service:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
<ul class="list-disc pl-6 mb-4 space-y-2">
<li class="text-slate-300">Egress</li>
</ul>
egress:
<ul class="list-disc pl-6 mb-4 space-y-2">
<li class="text-slate-300">to:</li>
<li class="text-slate-300">namespaceSelector: {}</li>
</ul>
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
<ul class="list-disc pl-6 mb-4 space-y-2">
<li class="text-slate-300">protocol: UDP</li>
</ul>
port: 53
<ul class="list-disc pl-6 mb-4 space-y-2">
<li class="text-slate-300">protocol: TCP</li>
</ul>
port: 53
Limitations
Network Policies have limitations:
- They operate at L3/L4 (IP and port). For L7 policies (HTTP path, headers), use a service mesh
- They do not apply to host-network pods
- They cannot restrict traffic to external IPs by DNS name (only CIDR blocks)
- Policy ordering is not guaranteed: all matching policies are merged
- ✓By default, every pod can communicate with every other pod across all namespaces with no isolation
- ✓Network Policies are enforced by the CNI plugin (Calico, Cilium, Antrea), not by Kubernetes core: verify your CNI supports them
- ✓Always start with a default-deny-all policy (empty podSelector, no rules) then whitelist specific flows
- ✓Default deny blocks DNS too: always include an egress rule allowing UDP/TCP port 53 to kube-dns
- ✓Network Policies operate at L3/L4 only: for L7 policies (HTTP path, headers) use a service mesh
1. What is the default network behavior in Kubernetes when no Network Policies exist?
2. What must you remember to allow when implementing a default-deny egress policy?
3. Which CNI plugins support Kubernetes Network Policy enforcement?