Kubernetes Network Policies

Network Policies provide fine-grained control over traffic flow between pods in a Kubernetes clúster. They define how pods can communicate with each other and external servicios, implementing a zero-trust reding model. Esta guía cubre ingreso and egress rules, espacio de nombres isolation, and implementations using Calico and Cilium CNI plugins.

Tabla de contenidos

Network Policy Fundamentals

What are Network Policies?

Network Policies are Kubernetes objects that specify how pods communicate with each other and with red endpoints. They work like reglas de firewall for pod-to-pod traffic.

Requisitos previos

Network Policies require a red plugin que soporta them. Default red plugins (like Flannel) don't support policies. You need:

  • Calico: Fully-featured red policy support
  • Cilium: Advanced policy with eBPF-based implementation
  • Kube-router: Lightweight option
  • Weave Net: Network policy support available

Policy Evaluation

When a Network Policy is defined, it creates a whitelist of allowed traffic. By default:

  • All traffic is allowed (if no policies exist)
  • Once a policy targets pods, only traffic matching that policy is allowed
  • Multiple policies combine with OR logic (traffic allowed if ANY policy permits it)

Network Policy Syntax

Basic Structure

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: production
spec:
  podSelector: {}  # Applies to all pods in namespace
  policyTypes:
  - Ingress
  - Egress
  ingress: []  # No ingress traffic allowed
  egress: []   # No egress traffic allowed

Pod Selection

Target specific pods:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes:
  - Ingress
  - Egress

Policy Types

  • Ingress: Controls incoming traffic to pods
  • Egress: Controls outgoing traffic from pods
  • Both: Restricts both directions

Ingress Rules

Allow All Ingress

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-ingress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - {}  # Empty rule allows all traffic

Allow from Specific Pods

Allow traffic from pods in the same espacio de nombres:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: frontend
    ports:
    - protocol: TCP
      port: 8080

Allow from Namespace

Allow traffic from any pod in another espacio de nombres:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-monitoring
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: monitoring
    ports:
    - protocol: TCP
      port: 9090

Allow from External Networks

Allow traffic from specific external reds:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-external-api
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-gateway
  policyTypes:
  - Ingress
  ingress:
  - from:
    - ipBlock:
        cidr: 203.0.113.0/24  # External network
        except:
        - 203.0.113.5/32  # Exclude specific IP
    ports:
    - protocol: TCP
      port: 443

Multiple Sources

Allow traffic from multiple sources:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-multiple-sources
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: database
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: backend
    - podSelector:
        matchLabels:
          tier: admin
    - namespaceSelector:
        matchLabels:
          name: monitoring
    ports:
    - protocol: TCP
      port: 5432
    - protocol: TCP
      port: 9100  # Prometheus exporter

Egress Rules

Allow All Egress

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-egress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - {}  # Allow all egress

Restrict Egress to Specific Pods

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-egress
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: frontend
  policyTypes:
  - Egress
  egress:
  - to:
    - podSelector:
        matchLabels:
          tier: backend
    ports:
    - protocol: TCP
      port: 8080

Allow DNS and External Access

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-external
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: app
  policyTypes:
  - Egress
  egress:
  # DNS
  - to:
    - namespaceSelector:
        matchLabels:
          name: kube-system
    ports:
    - protocol: UDP
      port: 53
  # External HTTPS
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 169.254.169.254/32  # Block AWS metadata
    ports:
    - protocol: TCP
      port: 443

Namespace Isolation

Deny All Traffic to Namespace

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
  ingress: []
  egress: []

Apply to all espacio de nombress:

# Create the policy in each namespace
for ns in production staging development; do
  kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: $ns
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
EOF
done

Allow Traffic Within Namespace

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-same-namespace
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector: {}  # Any pod in same namespace

Allow Ingress from Specific Namespace

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-ingress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: ingress-nginx

Calico Implementation

Instalaing Calico

Instala Calico as your CNI:

# Download Calico manifest
curl https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/tigera-operator.yaml -o tigera-operator.yaml

# Apply operator
kubectl apply -f tigera-operator.yaml

# Wait for operator to be ready
kubectl wait --for=condition=ready pod -l k8s-app=tigera-operator -n tigera-operator --timeout=300s

Instala Calico custom resource:

apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
  name: default
spec:
  calicoNetwork:
    ipPools:
    - blockSize: 26
      cidr: 10.0.0.0/16
      encapsulation: VXLAN
      natOutgoing: Enabled
      nodeSelector: all()
    nodeAddressAutodetectionV4:
      interface: eth0

Calico NetworkPolicy Extensions

Calico supports additional NetworkPolicy features:

apiVersion: crd.projectcalico.org/v1
kind: NetworkPolicy
metadata:
  name: advanced-policy
  namespace: production
spec:
  selector: tier == "backend"
  types:
  - Ingress
  - Egress
  ingress:
  - action: Allow
    protocol: TCP
    destination:
      ports:
      - 8080
  egress:
  - action: Allow
    protocol: TCP
    destination:
      nets:
      - 10.0.0.0/8
  - action: Allow
    protocol: UDP
    destination:
      ports:
      - 53

Calico Policy Rules

Calico allows more granular control:

# View Calico workload endpoints
calicoctl get workloadendpoints -n production

# View Calico policies
calicoctl get networkpolicies -n production

# Describe a policy
calicoctl get networkpolicies production.allow-frontend -o yaml

Cilium Implementation

Instalaing Cilium

Instala Cilium with Helm:

helm repo add cilium https://helm.cilium.io
helm repo update

helm install cilium cilium/cilium \
  --namespace kube-system \
  --set kubeProxyReplacement=disabled \
  --set k8sServiceHost=10.0.0.10 \
  --set k8sServicePort=6443 \
  --set image.tag=v1.14.0

Wait for Cilium to be ready:

kubectl rollout status -n kube-system ds/cilium

Cilium Network Policies

Cilium supports standard Kubernetes NetworkPolicy plus extended features:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: frontend
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - podSelector:
        matchLabels:
          tier: database
    ports:
    - protocol: TCP
      port: 5432
  - to:
    - namespaceSelector: {}
    ports:
    - protocol: UDP
      port: 53

Cilium CLI for Debugging

# Install cilium CLI
curl -L --remote-name-all https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-amd64.tar.gz
sudo tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin

# Check Cilium status
cilium status

# Inspect connectivity between pods
cilium connectivity test

# View policy enforcement
cilium policy get

Practical Examples

Ejemplo: Three-Tier Application

Frontend, backend, and database isolation:

---
# Deny all by default
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress: []
---
# Allow external traffic to frontend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-ingress
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: frontend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: ingress-nginx
    ports:
    - protocol: TCP
      port: 80
    - protocol: TCP
      port: 443
---
# Allow frontend to backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-backend
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: frontend
    ports:
    - protocol: TCP
      port: 8080
---
# Allow backend to database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-database
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: database
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: backend
    ports:
    - protocol: TCP
      port: 5432
---
# Allow DNS for all pods
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: kube-system
    ports:
    - protocol: UDP
      port: 53

Ejemplo: Multi-Namespace Communication

Allow specific espacio de nombress to communicate:

---
# Label namespaces
# kubectl label namespace production environment=prod
# kubectl label namespace monitoring environment=monitoring
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-monitoring
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          environment: monitoring
    ports:
    - protocol: TCP
      port: 9090

Ejemplo: Microservicios Communication

Complex servicio mesh with specific rules:

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: order-service-policy
  namespace: microservices
spec:
  podSelector:
    matchLabels:
      service: order
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          service: api-gateway
    ports:
    - protocol: TCP
      port: 8080
  egress:
  # To payment service
  - to:
    - podSelector:
        matchLabels:
          service: payment
    ports:
    - protocol: TCP
      port: 8080
  # To inventory service
  - to:
    - podSelector:
        matchLabels:
          service: inventory
    ports:
    - protocol: TCP
      port: 8080
  # To databases
  - to:
    - podSelector:
        matchLabels:
          service: postgres
    ports:
    - protocol: TCP
      port: 5432
  # DNS
  - to:
    - namespaceSelector:
        matchLabels:
          name: kube-system
    ports:
    - protocol: UDP
      port: 53

Conclusión

Network Policies are essential for implementing zero-trust reding in Kubernetes. By carefully planning your communication requirements and implementing deny-all-by-default policies with explicit allow rules, you create a secure red architecture. Whether using Calico for comprehensive red policy support or Cilium for advanced eBPF-based enforcement, proper red segmentation protects your applications on VPS and baremetal infrastructure. Start with liberal policies and gradually restrict traffic as you understand your application requirements, then maintain clear documentation of each policy's purpose and scope.