How Do You Isolate Namespaces with Network Policies?

intermediate|network policiesdevopssreplatform engineerCKA
TL;DR

Namespace isolation uses Network Policies with namespaceSelector to restrict traffic between namespaces. Apply a default-deny policy to each namespace, then use namespace labels to create explicit allow rules — for example, allowing only the frontend namespace to reach the backend namespace.

Detailed Answer

Namespace isolation is achieved by combining default-deny Network Policies with explicit allow rules that use namespaceSelector. This creates a zero-trust model where cross-namespace traffic is blocked unless explicitly permitted.

Step 1: Label Your Namespaces

Network Policies use labels to identify namespaces. Since Kubernetes 1.22, every namespace automatically gets the kubernetes.io/metadata.name label:

kubectl get namespace production --show-labels
# NAME         STATUS   AGE   LABELS
# production   Active   30d   kubernetes.io/metadata.name=production

# Add custom labels for fine-grained control
kubectl label namespace frontend team=frontend environment=production
kubectl label namespace backend team=backend environment=production
kubectl label namespace monitoring purpose=monitoring

Step 2: Apply Default-Deny to Each Namespace

# Apply this to every namespace that needs isolation
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: backend
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

Step 3: Create Cross-Namespace Allow Rules

Allow the frontend namespace to reach backend services:

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

Allow monitoring to scrape metrics from all namespaces:

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

Complete Namespace Isolation Example

A three-tier application with strict isolation:

# --- Backend Namespace Policies ---

# Deny all
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: backend
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
---
# Allow DNS
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: backend
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - protocol: UDP
          port: 53
---
# Allow intra-namespace communication
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-same-namespace
  namespace: backend
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - podSelector: {}
  egress:
    - to:
        - podSelector: {}
---
# Allow ingress from frontend namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-frontend
  namespace: backend
spec:
  podSelector:
    matchLabels:
      tier: api
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: frontend
      ports:
        - protocol: TCP
          port: 8080
---
# Allow ingress from ingress controller
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ingress-controller
  namespace: backend
spec:
  podSelector:
    matchLabels:
      exposed: "true"
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx

Common Patterns

Allow within the same namespace only

ingress:
  - from:
      - podSelector: {}    # All Pods in THIS namespace

Allow from specific namespaces

ingress:
  - from:
      - namespaceSelector:
          matchLabels:
            team: frontend

Allow from specific Pods in specific namespaces (AND logic)

ingress:
  - from:
      - namespaceSelector:
          matchLabels:
            team: frontend
        podSelector:
          matchLabels:
            app: web

Allow from all namespaces (cluster-wide)

ingress:
  - from:
      - namespaceSelector: {}    # ALL namespaces

Verification

# Test from the frontend namespace to backend
kubectl exec -n frontend deploy/web -- curl -m 5 http://api.backend:8080
# Should succeed

# Test from an unauthorized namespace
kubectl exec -n unauthorized deploy/attacker -- curl -m 5 http://api.backend:8080
# Should timeout (denied by policy)

System Namespace Considerations

Always allow traffic from system namespaces that provide essential services:

| Namespace | Service | Direction | |---|---|---| | kube-system | DNS (CoreDNS) | Egress from all Pods | | ingress-nginx | Ingress controller | Ingress to exposed Pods | | monitoring | Prometheus | Ingress to metrics ports | | cert-manager | Certificate management | Egress for ACME challenges |

Why Interviewers Ask This

Interviewers ask this to assess whether you can implement multi-tenant network isolation in a shared cluster — a common production security requirement.

Common Follow-Up Questions

Can you use namespace names in Network Policies?
Not directly. You use namespace labels in namespaceSelector. Since Kubernetes 1.22, every namespace automatically gets the label kubernetes.io/metadata.name set to its name.
How do you allow traffic from a specific namespace and a specific Pod?
Combine namespaceSelector and podSelector in the same from item (without a leading dash) to AND them — requiring both the namespace label and Pod label to match.
Does namespace isolation affect the Ingress controller?
Yes. If you deny ingress from the ingress-nginx namespace, external traffic cannot reach your Pods. You must explicitly allow traffic from the Ingress controller's namespace.

Key Takeaways

  • Label namespaces and use namespaceSelector in Network Policies for cross-namespace access control.
  • Default-deny per namespace combined with explicit cross-namespace allow rules creates strong isolation.
  • Remember to allow traffic from system namespaces (kube-system for DNS, ingress-nginx for external traffic).

Related Questions

You Might Also Like