Cloud Native 16 min read

Master Kubernetes NetworkPolicy: Secure Pod Communication with Real‑World Examples

This article explains Kubernetes NetworkPolicy, covering its purpose, how pod and namespace selectors work, required fields, policy types, and detailed YAML examples, followed by practical scenarios and step‑by‑step commands for deploying and testing network policies in a cluster.

Efficient Ops
Efficient Ops
Efficient Ops
Master Kubernetes NetworkPolicy: Secure Pod Communication with Real‑World Examples

Network Policy Overview

With the rise of micro‑service architectures and serverless frameworks, the demand for inter‑module network calls has grown dramatically. Kubernetes introduced NetworkPolicy in version 1.3 to provide application‑centric, policy‑based network control that isolates workloads and reduces the attack surface.

Pod communication can be verified through three combinations: allowed Pods, allowed namespaces, and IP CIDR blocks.

Version Changes

Brief Introduction

Related Explanation

By default, Pods are non‑isolated and accept any traffic.

When a Pod is selected by a NetworkPolicy, it becomes isolated. Any Pod in the same namespace that is not selected continues to accept all traffic.

Network policies do not conflict; a Pod selected by multiple policies is subject to the union of all inbound (Ingress) and outbound (Egress) rules.

When using NetworkPolicy, the network plugin must support it, such as Calico, Romana, Weave Net, or Trireme. "Egress" refers to outbound traffic, "Ingress" to inbound traffic.

Struct Definition

<code>staging/src/k8s.io/api/networking/v1/types.go</code>

Below is a sample NetworkPolicy; see the official struct documentation for full details.

<code>apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: network-policy-sample
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978</code>

Required fields: apiVersion, kind, and metadata (name, namespace).

spec contains all information needed to define a policy within a namespace.

podSelector selects the Pods the policy applies to; an empty selector matches all Pods in the namespace.

policyTypes lists Ingress, Egress, or both. If omitted, Ingress is assumed; Egress is added when egress rules are present.

ingress defines a whitelist of allowed inbound traffic, matching both "from" and "ports".

egress defines a whitelist of allowed outbound traffic, matching "to" and "ports".

Isolate Pods with label

role=db

in the

default

namespace.

Egress restriction: allow Pods with label

role=frontend

in

default

, Pods in namespaces labeled

project=myproject

, and IP ranges

172.17.0.0/16

except

172.17.1.0/24

to reach port

6379/TCP

on the selected Pods.

Ingress restriction: allow any Pod in namespaces with label

role=db

to reach port

5978/TCP

on CIDR

10.0.0.0/24

.

Simple Example (Calico)

1) Configure kubelet to use the CNI network plugin (usually pre‑configured).

<code>kubelet --network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin ...</code>

2) Install the Calico network plugin.

<code># Note: adjust CIDR to match the cluster's pod‑network‑cidr (default 192.168.0.0/16)
# Installation for clusters with fewer than 50 nodes
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml</code>

3) Deploy an application (nginx).

<code>$ kubectl create deployment nginx --image=nginx
deployment "nginx" created
$ kubectl expose deployment nginx --port=80
service "nginx" exposed</code>

Test the network:

<code>$ kubectl get svc,pod
... (output omitted for brevity)
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.233.27.142:80)
remote file exists
/ #</code>

Application Scenarios

General Scenarios

a) Deny access to a specific service.

<code>$ kubectl run web --image=nginx --labels app=web --expose --port 80
# Without a policy, the service is reachable
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
/ # wget -qO- http://web
<!DOCTYPE html>
<html>...</html></code>

Create a deny‑all policy:

<code># cat web-deny-all.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-deny-all
spec:
  podSelector:
    matchLabels:
      app: web
  ingress: []
$ kubectl apply -f web-deny-all.yaml
networkpolicy "web-deny-all" created</code>

Test that the service is now blocked:

<code>$ kubectl run busybox --rm -ti --image=busybox /bin/sh
/ # wget -qO- --timeout=2 http://web
wget: download timed out</code>

Namespace Restrictions

a) Block non‑whitelisted traffic in a namespace.

<code># cat default-deny-all.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: default-deny-all
  namespace: default
spec:
  podSelector: {}
  ingress: []
$ kubectl apply -f default-deny-all.yaml
networkpolicy "default-deny-all" created</code>

b) Block traffic from other namespaces.

<code>$ kubectl create namespace secondary
$ kubectl run web --namespace secondary --image=nginx --labels=app=web --expose --port 80</code>
<code># cat web-deny-other-namespaces.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  namespace: secondary
  name: web-deny-other-namespaces
spec:
  podSelector:
    matchLabels:
  ingress:
  - from:
    - podSelector: {}
$ kubectl apply -f web-deny-other-namespaces.yaml</code>

Testing shows that pods in the default namespace cannot reach the service, while pods in

secondary

can.

Allow All Namespaces

<code># cat web-allow-all-namespaces.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  namespace: default
  name: web-allow-all-namespaces
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - namespaceSelector: {}
$ kubectl apply -f web-allow-all-namespaces.yaml</code>

This policy permits traffic from any namespace to Pods labeled

app=web

.

Restrict Access to Specific Namespaces

<code># cat web-allow-prod.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-allow-prod
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          purpose: production
$ kubectl apply -f web-allow-prod.yaml</code>

Only namespaces labeled

purpose=production

can access the

web

service.

Allow Specific Pods Across Namespaces

<code># cat web-allow-all-ns-monitoring.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: web-allow-all-ns-monitoring
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          team: operations
      podSelector:
        matchLabels:
          type: monitoring
$ kubectl apply -f web-allow-all-ns-monitoring.yaml</code>

Pods with label

type=monitoring

in namespaces labeled

team=operations

are allowed to reach the

web

service.

kubernetesYAMLCNICalicoNetworkPolicyPod Isolation
Efficient Ops
Written by

Efficient Ops

This public account is maintained by Xiaotianguo and friends, regularly publishing widely-read original technical articles. We focus on operations transformation and accompany you throughout your operations career, growing together happily.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.