Invisible Bad Neighbors: Kubernetes Pod-to-Pod Network Policy Battles
Kubernetes is a powerful orchestration platform that forms the backbone of our modern applications. But the power it brings comes with a responsibility: network security. Our applications are made up of countless pods that are constantly talking to each other. So how secure is that pod-to-pod communication? Malicious pods trying to break in, or misconfigured services, can quietly damage our system. That’s exactly where Kubernetes Network Policies come in.
In this post, I’ll go deep into how to bring pod-to-pod network communication in Kubernetes under control and how to build a defense line against invisible threats. We’ll start from the fundamentals of Network Policies and journey through to complex scenarios. The goal is to harden the security of your cluster and make sure your pods talk to each other only in the ways you allow.
What Are Network Policies and Why Do They Matter?
In Kubernetes, Network Policies are a set of rules applied to pods that determine which traffic flows are allowed or denied. By default, Kubernetes lets all pods in the cluster communicate freely with each other. While that simplifies things in development environments, it carries serious security risk in production. When a single pod is compromised, it means an attacker can easily reach every other pod on the same network.
Network Policies act as a firewall by turning that “default-open” state into a “default-closed” one. By defining rules that allow pods with specific labels to communicate over specific ports and protocols, they enable network segmentation. This significantly reduces the attack surface and stops a breach in one pod from spreading to the others.
Core Concepts of Network Policies
To understand Network Policies, you need to be familiar with some core concepts. They allow us to write rules correctly. First, labeling your pods is critical. Network Policies use these labels to identify target pods or source pods. For example, you can write a rule that lets only pods with the label app=frontend reach pods with the label app=backend.
Second, Network Policies have “ingress” (incoming traffic) and “egress” (outgoing traffic) rules. Ingress rules determine which traffic can enter a pod, while egress rules control which traffic can leave a pod. This bidirectional control gives you full management of network flow. Namespaces also play an important role in Network Policies. Rules can apply to pods within a specific namespace or to pods in different namespaces.
Creating a Simple Network Policy: Isolating Pods
The most basic Network Policy scenario is to isolate a pod group from all other pods. Say you have a database pod that contains sensitive data, and you want it to respond only to requests coming from a specific application pod. To pull that off, you can follow these steps:
- Label the Database Pod: Assign a unique label to your database pod, like
role=database. - Label the Application Pod: Assign a label like
role=frontendto your application pod. - Create the Network Policy: Define a Network Policy that restricts traffic going to the database pod. The policy will allow only TCP port 5432 (the PostgreSQL default port) traffic from pods with the
role=frontendlabel.
Here is a simple Network Policy YAML example for that scenario:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database-ingress-policy
namespace: default # Veritabanı podunun bulunduğu namespace
spec:
podSelector:
matchLabels:
role: database # Bu politika, bu etikete sahip podlara uygulanacak
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: frontend # Yalnızca bu etikete sahip podlardan gelen trafik
ports:
- protocol: TCP
port: 5432 # Ve bu porta gelen trafik
This policy lets pods labeled role=database be reached only from pods labeled role=frontend, on TCP port 5432. All other incoming traffic is denied.
Advanced Network Policies: Egress Control and Cross-Namespace Communication
Controlling only the incoming traffic is not enough. We may also need to manage how our applications talk to the outside world or to other services. That’s where egress rules come in. For example, you might want to allow a web server pod to reach only specific external APIs or a service in another namespace.
Cross-namespace communication management is also possible with Network Policies. You can define policies to allow or restrict pods in one namespace from talking to pods in another namespace. That’s particularly useful in microservice architectures for separating responsibilities between different service groups.
For example, let’s create a policy that allows an api-gateway pod to reach the user-api pod in the user-service namespace only over HTTP (port 80):
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-gateway-egress-to-userservice
namespace: api-gateway-namespace # API Gateway'in bulunduğu namespace
spec:
podSelector:
matchLabels:
app: api-gateway
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
name: user-service # Hedef namespace'i belirtiyoruz
podSelector:
matchLabels:
app: user-api # Hedef pod'u belirtiyoruz
ports:
- protocol: TCP
port: 80 # Ve bu porta gelen trafik
This policy lets the pod labeled app=api-gateway in the api-gateway-namespace send egress traffic only on TCP port 80 to the pod labeled app=user-api in the user-service namespace.
Things to Watch Out For When Applying Network Policies
Network Policies are a powerful tool, but used incorrectly they can produce unexpected results. Here are some important points to keep in mind:
- CNI Plugin Support: For Network Policies to work, the Container Network Interface (CNI) plugin you use must support Network Policies. Popular CNIs like Calico, Cilium, and Weave Net offer this feature.
- Test and Validation: Always try out your policies in test environments before applying them to production. Watch the communication flows carefully and check whether anything is being unexpectedly blocked.
- Step-by-Step Application: Rather than locking down your entire network all at once, apply Network Policies incrementally. Start with a specific namespace or application group and expand the scope over time.
- Documentation: Document the Network Policies you create and the reasoning behind them. That will help you in future troubleshooting and change management work.
- “Default Deny” Approach: Wherever possible, adopt the “default-deny” principle. In other words, don’t allow any traffic that you haven’t explicitly permitted. That’s the most secure approach.
Common Issues and Their Fixes
Some common issues you might run into when working with Network Policies:
- Pods Can’t Communicate: This usually comes from a missing or misconfigured Network Policy. Use the
kubectl describe networkpolicy <policy-name>command to inspect the policy details and make sure your pod labels are correct. - DNS Resolution Issues: If pods can’t reach the DNS server, that may also be blocked by a Network Policy rule. You may need to add an egress rule that allows traffic to the DNS server’s IP address and port (typically UDP 53).
- Application Crashes: Make sure you allow access to all the ports and services your application needs. Especially restrictions on access to external services or other microservices can cause applications to crash.
Conclusion: Building a Secure Kubernetes Future
Kubernetes Network Policies are an indispensable tool for securing pod-to-pod network communication. They build an effective defense line against invisible bad neighbors — meaning potential threats and bad configurations. In this post, we covered the fundamentals of Network Policies, key concepts, and basic and advanced usage scenarios.
Remember that security is a continuous effort. By applying Network Policies correctly, you can increase the resilience of your Kubernetes cluster and keep your data safe. Building a secure cloud-native future starts with the care we put into network security. By making sure your pods only talk to each other in the ways you allow, you can build more robust and reliable systems.