A Practical Guide to Kubernetes Network Policies
Master Kubernetes network security by learning how to write, apply, and troubleshoot NetworkPolicy resources to control traffic flow between your pods.
What You'll Learn
🏷️ Topics Covered
What are Kubernetes Network Policies?
By default, Kubernetes has a "flat" network where all pods can communicate freely. This is a significant security risk. A single compromised pod could potentially attack any other service in the cluster. Network Policies are the native Kubernetes resource for controlling traffic flow at the IP address or port level (OSI Layer 3/4), acting as a firewall for your pods.
🎯 Core Concept
Think of Network Policies as the "guardrails" for your cluster's network traffic. They allow you to enforce network segmentation and a zero-trust security model, ensuring pods can only communicate with the services they're explicitly allowed to.
The Building Blocks of Network Policies
Ingress Rules
Define which incoming traffic is allowed to reach a pod. If any ingress rules are specified, only matching traffic is permitted.
Egress Rules
Define what outbound traffic a pod is allowed to initiate. If any egress rules are defined, only matching connections are permitted.
Selectors
Policies use label selectors to target groups of pods. This flexible mechanism allows you to manage rules for entire applications at once.
Writing Basic Policies: The Default Deny Model
The most effective security posture is to deny all traffic by default and then explicitly allow only what is necessary. This is the foundation of a zero-trust network.
1. Default Deny All Ingress Traffic
This is the foundational policy for any secure namespace. It selects all pods in its namespace and specifies that no ingress traffic is allowed.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: my-app
spec:
podSelector: {}
policyTypes:
- Ingress 2. Allowing Ingress from a Specific Namespace
Once you have a default deny, you can layer on policies. This policy allows pods with the label `app: api` to receive traffic from any pod in the namespace that is labeled `name: monitoring`.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-api-from-monitoring
namespace: my-app
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring 3. Allowing Ingress based on Pod Selector
This is the most common pattern. It allows pods with `app: database` to receive traffic on port 5432 from pods with the label `app: api` within the same namespace.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-db-from-api
namespace: my-app
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 5432 Advanced Ingress & Egress Rules
Real-world applications require more complex rules, such as controlling outbound traffic and combining multiple rulesets.
1. Controlling Egress (A Common Pitfall: DNS)
When you apply egress policies, you must explicitly allow all necessary outbound traffic, including DNS. This policy allows `app: api` pods to send DNS queries and connect to external services on port 443.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-api-egress
namespace: my-app
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Egress
egress:
# Allow DNS traffic to pods labeled k8s-app: kube-dns
- to:
- podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
# Allow other external traffic over HTTPS
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8 # Exclude internal cluster CIDR
ports:
- port: 443
protocol: TCP 2. Combining Ingress Rules (OR Logic)
You can combine multiple `from` clauses in an ingress rule. Traffic is allowed if it matches *any* of the clauses. This policy allows the `database` pod to receive traffic from the `api` pods OR the `backup-job` pods.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-db-access-combined
namespace: my-app
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Ingress
ingress:
- from:
# Rule 1: Allow from 'api' pods
- podSelector:
matchLabels:
app: api
# Rule 2: Allow from 'backup' pods
- podSelector:
matchLabels:
job: backup
ports:
- protocol: TCP
port: 5432 Best Practices for Policy Management
Start with Deny-All
Always apply a default deny-all policy to every new namespace to ensure a zero-trust foundation.
Use Consistent Labels
Establish a clear, consistent labeling strategy for all your applications to make policy management scalable.
Be Specific and Explicit
Avoid overly broad rules. Whenever possible, specify ports and protocols to enforce the principle of least privilege.
Visualize Your Policies
Use tools like Cilium's Hubble to visualize traffic flows and understand the real-world impact of your policies.
Troubleshooting Common Issues
❌ Pods cannot connect to a Service
Problem: After applying a policy, pods can no longer communicate with a service they previously could.
Solutions:
- Check Labels: Ensure both the source pod and the destination pod have the correct labels matching the `podSelector` in the policy. A single typo will cause the policy to fail.
- Check Namespaces: If using a `namespaceSelector`, verify that the source namespace has the required label.
- Check Egress Rules: The source pod might be missing an egress rule that allows it to initiate the connection.
❌ Pod cannot connect to the internet or resolve DNS
Problem: A pod can't make external API calls or resolve domain names.
Solutions:
- Missing DNS Egress Rule: You must explicitly allow egress traffic to the `kube-dns` service (usually on port 53 TCP/UDP) from your pod.
- Missing External Egress Rule: To reach the internet, you need an egress rule with an `ipBlock` of `0.0.0.0/0`. Be sure to exclude internal cluster CIDRs.
- CNI Not Ready: On cluster startup, sometimes pods come up before the CNI is ready, leading to DNS resolution failures. Ensure your readiness checks are robust.
Getting Started Step-by-Step
Verify Your CNI
Ensure your cluster's Container Network Interface (e.g., Calico, Cilium, Weave Net) supports and enforces Network Policies.
Apply a Default Deny
Choose a non-critical namespace, apply a `default-deny-ingress` policy, and observe that traffic is blocked.
Incrementally Add "Allow" Rules
One by one, add specific "allow" policies for required traffic, testing connectivity at each step.
Automate with Policy-as-Code
Store your Network Policy YAML files in a Git repository and apply them as part of your CI/CD process.
🎉 Congratulations!
You now have a solid understanding of how to use Kubernetes Network Policies to secure your cluster. You've learned how to:
- ✅ Isolate workloads and implement a default-deny posture.
- ✅ Write specific ingress and egress rules using selectors.
- ✅ Control traffic based on pods, namespaces, and IP addresses.
- ✅ Troubleshoot common connectivity issues caused by policies.