Kubernetes·7 min read·

Implementing Kubernetes Network Policies for Strict Pod-to-Pod Isolation

Enforce zero-trust pod communication within your Kubernetes cluster using declarative NetworkPolicy rules to block unauthorized ingress and egress.

NB

Netbay Infrastructure Team

Netbay Engineering

On this page

By default, the Kubernetes network model is completely open: every pod can communicate with every other pod across all namespaces without restriction. In a multi-service or multi-tenant deployment, this lack of boundary means that a vulnerability in a public-facing web tier grants immediate network access to private database instances and internal telemetry endpoints.

Kubernetes NetworkPolicies provide declarative firewalling at the pod level using label selectors. Enforcing a default-deny posture and selectively allowlisting necessary ingress and egress flows establishes a robust zero-trust security perimeter.

Network policies are enforced by the cluster's Container Network Interface (CNI) provider, such as Calico, Cilium, or Kube-Router. When you apply a NetworkPolicy manifest, the CNI controller translates the high-level podSelector stanzas into underlying Linux kernel packet filtering rules (using iptables, ipset, or modern eBPF maps). Traffic that does not match an explicit allow rule is dropped at the virtual network interface level before reaching the container's socket layer.

Expand
Kubernetes Network Policies Isolation
Zero-trust pod-to-pod network isolation policies

Enforcing a Default-Deny Security Baseline

The foundational principle of zero-trust networking is default-deny. Applying this policy instructs the CNI plugin to drop all ingress and egress traffic for pods in the target namespace unless explicitly authorized:

Kubernetes Zero-Trust Network Policy Ingress & Egress Matrix Frontend Web Pod app: frontend Permitted: Ingress :80/:443 Backend API Pod app: api-server Allowed Ingress from frontend Database Pod app: postgres Ingress: Port 5432 only Blocked Packet Vectors (Enforced by NetworkPolicy CNI): 1. Frontend Pod attempting direct connection to Database -> DROPPED 2. Database Pod attempting outbound egress connection to external WAN IP -> DROPPED 3. Unlabeled rogue pod attempting cross-namespace network scans -> DROPPED
yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  egress:
    # Always allow DNS resolution to CoreDNS
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53

A critical operational detail when establishing a default-deny egress policy is explicitly allowing DNS traffic to kube-dns or CoreDNS on port 53. If this rule is omitted, pods will be unable to resolve internal service names or external APIs, triggering silent connection timeouts throughout the application stack.

Creating Granular Ingress Allow Policies for Databases

Next, create targeted allow rules. The following policy allows incoming connections on port 5432 to PostgreSQL pods only when originating from pods labeled app: api-backend:

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api-to-database
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: api-backend
      ports:
        - protocol: TCP
          port: 5432

Verifying Policy Enforcement and Dropped Packets

Validate that non-authorized pods are blocked from connecting to the database:

bash
# Attempt connection from an authorized API pod (succeeds)
kubectl exec -it $(kubectl get pod -l app=api-backend -n production -o jsonpath='{.items[0].metadata.name}') -n production -- nc -zv postgres 5432

# Attempt connection from an unauthorized frontend pod (hangs and times out)
kubectl exec -it $(kubectl get pod -l app=frontend -n production -o jsonpath='{.items[0].metadata.name}') -n production -- nc -zv -w 3 postgres 5432

When the unauthorized frontend pod attempts to connect to port 5432, the CNI kernel filter drops the initial TCP SYN packet silently. The netcat command times out after 3 seconds, confirming that the database port is completely invisible to the frontend tier.

Implementing declarative NetworkPolicies turns the Kubernetes flat network into an isolated multi-tier fortress.

Kubernetes Network Policies Deep Dive
YouTube

You can spin up an Ubuntu 24.04 instance on Netbay in under 60 seconds with Intel Xeon Platinum compute and high-speed SSD storage in Lucknow — netbayhosts.in.

Keep reading

Follow along on a real VPS

Deploy Linux in under 60 seconds

These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.

Deploy an instance