EKS network policies are fundamentally about limiting pod-to-pod communication, not about blocking external traffic to your cluster.

Let’s see this in action. Imagine we have two applications: frontend and backend.

# frontend deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  labels:
    app: frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
# backend deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
  labels:
    app: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
      - name: httpd
        image: httpd:latest
        ports:
        - containerPort: 80

By default, these pods can talk to each other freely. If you kubectl exec into the frontend pod and try to curl http://<backend-pod-ip>, it will succeed.

Now, we want to enforce that only the frontend can talk to the backend. We’ll use Kubernetes NetworkPolicy objects.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-allow-frontend
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: backend # This policy applies to pods with the label app=backend
  policyTypes:
  - Ingress # We are defining rules for incoming traffic to the backend pods
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend # Allow traffic only from pods with the label app=frontend
    ports:
    - protocol: TCP
      port: 80 # Allow traffic on TCP port 80

After applying this policy, if you try to curl the backend pod from any other pod (including frontend if it didn’t have the app: frontend label, or any other arbitrary pod in the namespace), it will fail with a timeout. Only traffic originating from a pod labeled app: frontend will be allowed to reach port 80 on pods labeled app: backend.

The core problem NetworkPolicy solves is the "blast radius" of a compromised pod. Without policies, a compromised frontend pod could potentially pivot and attack your database pods, your cache pods, or any other service within the cluster. NetworkPolicy allows you to define explicit "allow lists" for communication, effectively creating a zero-trust network within your Kubernetes cluster.

Internally, EKS (and Kubernetes in general) relies on a Container Network Interface (CNI) plugin that supports network policy enforcement. The most common CNI for EKS is AWS VPC CNI, which integrates with AWS security groups. However, for NetworkPolicy to work, you must have a CNI plugin installed that implements the Kubernetes NetworkPolicy API. This is typically Calico, Cilium, or Weave Net. If you’re using the default AWS VPC CNI without an additional network policy agent, NetworkPolicy objects will be ignored.

To confirm which CNI you’re running and if it supports network policies, you can check your cluster’s add-ons or deployed pods in kube-system:

kubectl get pods -n kube-system -l k8s-app=calico-node
# or
kubectl get pods -n kube-system -l k8s-app=cilium

If you see pods for Calico or Cilium, your cluster is set up for network policies. If not, you’ll need to install one of these plugins.

The podSelector in a NetworkPolicy acts as the target. It determines which pods the policy applies to. If podSelector is empty, it applies to all pods in the namespace. The policyTypes field dictates whether the policy governs Ingress (traffic to the selected pods) or Egress (traffic from the selected pods).

The from (for Ingress) and to (for Egress) fields use selectors to define who or what is allowed to communicate. These selectors can target podSelectors (as shown above), namespaceSelectors (to allow/deny traffic from all pods in specific namespaces), or ipBlocks (to allow/deny traffic from specific IP ranges).

A crucial, often misunderstood aspect is that NetworkPolicy is additive when defining rules within a single policy, but selective across multiple policies. If a pod is selected by multiple NetworkPolicy objects, it must satisfy all policies that apply to it for a given type of traffic (Ingress or Egress). However, if any NetworkPolicy selects a pod for a given traffic type (Ingress or Egress), then only the traffic explicitly allowed by those policies will be permitted. If no policies select a pod for a given traffic type, all traffic is allowed by default.

The next logical step after mastering pod-to-pod communication is to control ingress traffic from outside the cluster using NetworkPolicy with ipBlocks or by integrating with AWS Load Balancers and security groups.

Want structured learning?

Take the full Eks course →