Kubernetes Network Policies: Securing Pod-to-Pod Communication

Implement microsegmentation in Kubernetes using Network Policies to control traffic flow between pods and enforce zero-trust networking.

published: reading time: 29 min read author: GeekWorkBench updated: June 17, 2026
Quick Summary

Kubernetes Network Policies enforce zero-trust microsegmentation by restricting which pods can communicate, using labels, namespaces, and ports as the control plane. The practical sequence: apply default-deny first, then explicitly allow only the traffic your services actually need — and always allow DNS on port 53 before touching egress rules. CNI support varies wildly — Calico and Cilium handle full L3/L4 plus L7 HTTP policies, while Flannel ignores network policies entirely and Weave only covers the basics. When a pod gets compromised, it can't reach your database or secrets manager, which is the whole point.

Kubernetes Network Policies: Securing Pod-to-Pod Communication

By default, all pods in a Kubernetes cluster can communicate with all other pods. This flat network model works during development but creates security risks in production. A compromised pod can reach any other pod in the cluster, including sensitive services like databases and secrets management.

Kubernetes Network Policies let you restrict pod-to-pod communication based on labels, namespaces, and ports. This microsegmentation approach implements zero-trust networking inside the cluster.

This post covers how Network Policies work, default deny patterns, and practical policy configurations.

For Kubernetes basics, see the Kubernetes fundamentals post. For services and Ingress, see the Services and Networking post.

Introduction

When Network Policies make sense

Multi-tenant clusters need them by default. If you do not control what runs in every namespace, a compromised workload could reach your database.

Compliance mandates often require them. PCI-DSS, SOC2, HIPAA all have requirements around network segmentation. Network policies are how you implement that inside Kubernetes.

Zero-trust means no flat network. A compromised pod should not automatically have access to everything. Restrict what can reach your database, your cache, your secrets manager.

Here is where policies actually earn their keep:

ScenarioRisk without policiesWhat a policy does
Shared cluster with multiple teamsTeam A’s pod reads Team B’s databaseAllow only explicitly permitted pod-to-pod traffic
Sensitive workloads (payments, PII)Any compromised pod reaches the data layerIsolate the sensitive namespace from all other workloads
Third-party or contractor-deployed appsUntrusted code reaches internal servicesLock down ingress and egress at the namespace level
Production vs. development co-locationDevelopment bugs affect production servicesApply production-grade policies to production namespaces only

The multi-tenant case comes up most often. When your cluster hosts workloads from multiple teams, you cannot assume every deployment is trustworthy. A policy like allow-api-to-db means a buggy or malicious pod dropped into the same namespace still cannot reach the database — it needs an explicit rule allowing it.

For compliance auditors, network policies alone do not make you compliant, but they are a required control in PCI-DSS, SOC 2, and HIPAA frameworks. They want to see that traffic between a cardholder data environment and other networks is restricted at the Kubernetes layer — not just at the VPC level. A default-deny ingress plus explicit allow rules gives them the evidence trail they expect.

On zero-trust — the phrase is overused but here it is literal. Without a policy, your web-frontend pod can reach your database pod directly on port 5432. With a policy, it cannot. It must go through the API on the API’s ingress port. If the web-frontend gets compromised, the attacker cannot bypass the API layer to hit the database directly. In a flat network, an attacker moves from pod to pod in minutes. Microsegmentation forces them through one hop at a time.

When to skip them

Single-tenant clusters where you control every workload are lower risk. If every person who can deploy to your cluster is trusted, the flat network is less of a concern.

External segmentation can be enough. Cloud VPC security groups that isolate your Kubernetes nodes from each other and from other services provide some protection. Network policies then add defense in depth.

Early development is not the time. The operational overhead of debugging why your service cannot reach its database when you forgot to allow port 5432 slows down iteration.

Traffic Filtering Flow

flowchart TD
    P1[Pod A<br/>app=web-frontend] -->|Egress| NP1{Network Policy<br/>on Pod A}
    NP1 -->|Allow to<br/>DNS| DNS[CoreDNS<br/>:53]
    NP1 -->|Allow to<br/>:8080| P2[Pod B<br/>app=api-backend]
    NP1 -->|Block all<br/>else| X[Dropped]
    P2 -->|Ingress| NP2{Network Policy<br/>on Pod B}
    NP2 -->|Allow from<br/>web-frontend| P1
    NP2 -->|Block all<br/>else| X2[Dropped]

Network policies are pod-scoped. Each pod has its own ingress and egress rules. Without a policy, all traffic is allowed by default on most CNI plugins. With a policy, only explicitly allowed traffic is permitted.

How Network Policies Work

A Network Policy is a namespaced resource that selects pods and defines ingress and egress rules. The policy controller (part of the CNI plugin) enforces the rules by configuring network filters on the node.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-backend-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-backend
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: web-frontend
      ports:
        - protocol: TCP
          port: 8080
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: postgres
      ports:
        - protocol: TCP
          port: 5432

This policy allows the api-backend pod to receive traffic from web-frontend pods on port 8080, and to send traffic to postgres pods on port 5432.

Policy evaluation order

Network Policies are additive. If multiple policies select the same pod, the union of all allowed traffic is permitted. This means you must carefully design policies to avoid unintended exposure.

Some CNI providers like Calico support policy priorities to resolve conflicts:

spec:
  order: 100

Lower order values have higher priority.

Default Deny All Ingress and Egress

Start with a default deny policy for each namespace, then explicitly allow required traffic. This follows the principle of least privilege.

Default deny ingress

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

podSelector: {} selects all pods in the namespace. With no ingress rules, all incoming traffic is blocked.

Default deny egress

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

This blocks all outgoing traffic until you add policies allowing specific destinations.

Combined default deny

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

Apply this before deploying any application, then add allow policies as you deploy services.

Allowing Specific Traffic with Pod Selectors

After setting default deny, allow specific traffic patterns:

Web frontend to API backend

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

API backend to database

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

Application layer filtering

For more complex rules, use namespaceSelector to allow traffic from specific namespaces:

ingress:
  - from:
      - namespaceSelector:
          matchLabels:
            name: frontend
        podSelector:
          matchLabels:
            app: web-frontend
      - namespaceSelector:
          matchLabels:
            name: monitoring
        podSelector:
          matchLabels:
            app: prometheus

This allows traffic from frontend namespace pods labeled app: web-frontend and from monitoring namespace pods labeled app: prometheus.

Namespace-Level Policies

Apply policies at the namespace level to protect entire namespaces or enforce compliance requirements:

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

This allows traffic only from pods in the production namespace or from the ingress-nginx namespace.

Isolating system namespaces

kube-system runs the pieces your cluster needs to stay up: the API server (through kube-apiserver), CoreDNS for service discovery, kube-proxy for network policy enforcement, and sometimes your CNI agent and metrics collectors. If any of these are reachable from application pods, a compromised workload can disrupt cluster operation itself, not just other applications.

A default-deny ingress on kube-system stops application pods from reaching these services directly. Only traffic from other kube-system pods should reach kube-system components, and in most cases even that is unnecessary. The policy below restricts ingress to self-namespace traffic:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-system-namespaces
  namespace: kube-system
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system

This blocks application pods from hitting the API server endpoint, scanning CoreDNS, and interfering with metrics collectors in kube-system. But this ingress-only policy does not stop kube-system pods from receiving traffic from applications, so add egress rules to kube-system if your threat model requires restricting system components outbound as well.

One thing that gets overlooked: some CNI agents run as regular pods in kube-system instead of as host-level daemons. If that pod is compromised, it can bypass network policy enforcement entirely, regardless of how tight your policies are. Treat your CNI agent pod like a high-privilege workload and restrict who can deploy to kube-system with RBAC, not just network policies.

The same pattern works for other system namespaces you might have: monitoring (Prometheus), logging (Fluentd, Loki), ingress controllers. Apply a default-deny ingress to each one, then add explicit allow rules only for the cross-namespace dependencies that system component actually needs.

DNS Egress Rules

Pods need DNS resolution to work properly. DNS runs in the kube-system namespace on port 53 (TCP and UDP). Allow DNS traffic in your egress policies:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-egress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    # Allow DNS
    - ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
      to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
    # Allow other necessary egress (example)
    - ports:
        - protocol: TCP
          port: 443
      to:
        - namespaceSelector: {}

The DNS rule uses to to specify destination namespaces. Without this, pods cannot resolve service names or external domains.

CNI Providers and Policy Enforcement

Network Policy support varies by CNI provider. Not all providers implement all policy features:

ProviderIngressEgressPolicy PrioritiesDNAT
CalicoYesYesYesYes
CiliumYesYesYesYes
WeaveYesYesNoNo
FlannelNoNoNoNo

Calico NetworkPolicy

Calico extends standard NetworkPolicy with additional features:

apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: api-isolation
  namespace: production
spec:
  selector: app == 'api-backend'
  types:
    - Ingress
    - Egress
  ingress:
    - action: Allow
      source:
        selector: app == 'web-frontend'
      destination:
        ports:
          - 8080
    - action: Deny
  egress:
    - action: Allow
      destination:
        selector: app == 'postgres'
        ports:
          - 5432
    - action: Allow
      protocol: TCP
      destination:
        ports:
          - 53

Calico’s explicit action: Deny rules make policy intent clearer.

Cilium NetworkPolicy

Cilium uses eBPF for enforcement and supports L7 policies:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: api-policy
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: api-backend
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: web-frontend
      toPorts:
        - ports:
            - port: "8080"
              protocol: TCP

Cilium also supports HTTP, Kafka, and DNS filtering at L7.

Testing Network Policies

Verify your policies work correctly with connectivity tests:

Using kubectl to test connectivity

kubectl gives you two ways to check connectivity: spin up a test pod, or exec into one you already have. Both will tell you whether traffic passes or gets dropped. Neither will tell you which specific policy rule caused the result.

Test ingress by creating a busybox pod and reaching the target:

kubectl run -it --rm test-pod \
  --image=busybox \
  --restart=Never \
  -- wget -q -O- http://api-backend:8080/health

Connection succeeds: the policy allows it. Connection times out: the policy blocks it. For HTTPS, swap wget for curl -k.

Test egress the other way around — exec into the source pod and reach outward:

kubectl exec -it api-backend-pod -- sh -c "wget -q -O- http://postgres:5432"

If that fails, either the destination’s ingress policy, the source’s egress policy, or both are blocking.

Before assuming a policy is at fault when a test fails, check three things: the pod is actually running (kubectl get pods), the service name resolves (kubectl exec test-pod -- nslookup api-backend), and the port in your policy matches the service port. Port mismatches masquerade as policy failures more often than actual policy misconfigurations.

For repeated testing, keep a debug pod around instead of creating a new one every time:

kubectl run debug-pod --image=busybox --restart=Never -- sleep 3600
kubectl exec -it debug-pod -- sh

You get a persistent shell with the same network properties as your application pods, without the overhead of recreating a throwaway container each time.

Using a policy visualizer

Hornet, Calico Enterprise, and Cilium Hubble show your policy rules as pictures instead of YAML. Hornet is open-source and renders policy relationships as interactive graphs — click a pod and see exactly which other pods it can reach. Calico Enterprise adds a simulation mode so you can preview how a new policy would change allowed traffic before applying it to the cluster.

You will notice the value when you have more than five policies across multiple namespaces. Reading YAML files, it is easy to miss an allow rule buried in a large policy. A picture shows you the whole topology at once: which pods reach which services, where default-deny is active, and where DNS exceptions exist. During security audits, this helps confirm no unexpected exposure paths exist between workloads.

If you do not have commercial tooling, kubectl get networkpolicy --all-namespaces lists all policies fast, and kubectl describe on individual policies shows the full rule set. Pair that with a topology diagram of your services and you can trace paths manually. Incident response is where this really pays off — you can quickly confirm whether a policy change caused an outage.

Production Failure Scenarios

Common Policy Failures

Policy Blocking All Traffic

A default-deny accidentally applied to the wrong namespace, or an overly broad rule that blocks your application’s actual dependencies. The result is sudden outage with no obvious cause in application logs.

Test in staging first. Apply to production during low-traffic windows. Have a rollback plan.

DNS Resolution Fails After Default Deny Egress

This is the most common mistake. Default deny goes in, DNS stops working, pods cannot resolve service names or reach each other.

DNS runs on port 53 in kube-system. Allow it explicitly before applying default deny egress. This is not optional.

CNI Does Not Support Your Policy Features

Flannel does not support network policies at all. Weave supports basic ingress and egress but not priorities or DNAT. If you write a policy assuming a feature and your CNI does not implement it, the traffic flows anyway.

Check CNI capabilities before designing policies. Calico and Cilium have the most complete implementations.

Provider and Compliance Considerations

CNI Provider Trade-off Comparison

CNINetwork PoliciesL7 FilteringEgressComplexity
CalicoFullYes (Tiered)YesMedium
CiliumFullYes (HTTP)YesMedium
WeaveBasicNoLimitedLow
FlannelNoneNoNoLowest
AWS VPC CNIPartialNoYesMedium

For production security, Calico or Cilium are the practical choices. Flannel and Weave work for development clusters where network policy enforcement is not a requirement.

Compliance Checklist

Network policies help meet compliance requirements for network isolation:

PCI-DSS:

  • Req 1.3.1 — Restrict traffic between cardholder data environment and other networks
  • Req 2.2.1 — Restrict traffic to only necessary protocols and ports

SOC 2:

  • CC6.1 — Restrict access to systems and data based on need-to-know
  • CC6.6 — Enforce network boundaries
# Default deny for PCI-DSS scoped namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: cardholder-data
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

Key checklist items:

  • Default deny applied to all untrusted namespaces
  • Explicit allow rules for required traffic paths only
  • DNS egress allowed on port 53 (TCP and UDP)
  • Payment card data namespace isolated from general workloads
  • Audit logging enabled for security group changes
  • Annual review of policy effectiveness

Advanced L7 Policies

L7 Policy Examples with Cilium

Cilium supports HTTP-level network policies for fine-grained L7 control:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: api-access-control
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: api-backend
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: frontend
      toPorts:
        - port: "8080"
          protocol: TCP
          rules:
            http:
              - method: GET
                path: "/api/v1/.*"
              - method: POST
                path: "/api/v1/users"
              - method: GET
                path: "/api/v1/health"
          allowedHeaders:
            - Content-Type
            - Authorization

This policy allows only the frontend to reach the API, and only on specific HTTP methods and paths. A request to /api/v1/admin or using DELETE would be blocked.

# Deny specific paths for a microservice
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: deny-admin-paths
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: internal-api
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: web-frontend
      toPorts:
        - port: "8080"
          rules:
            http:
              - method: GET
                path: "/api/v1/.*"
              # Implicitly deny POST, PUT, DELETE, etc.

Common Pitfalls / Anti-Patterns

Blanket podSelector: {}

podSelector: {} selects every pod in the namespace, including system pods. Applying a restrictive policy to all pods can break core functionality.

Always scope policies to your application pods specifically.

The danger is that kube-system runs the API server, CoreDNS, kube-proxy, metrics collectors, and potentially your CNI agent. If a default-deny ingress blocks traffic to CoreDNS, none of your application pods can resolve service names. If it blocks your metrics scraper, your monitoring goes dark. You will see cryptic connectivity timeouts instead of clear error messages pointing at the policy.

The dangerous pattern looks like this:

# Applies to system pods too
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress:
    # Intended only for application pods
    - from:
        - podSelector:
            matchLabels:
              app: web-frontend

Scope the selector to your application workloads only. Use label prefixes like app:, component:, or tier: to separate system pods from application pods. If you need a default-deny in a namespace that also runs system components, apply the default-deny to application pods only and handle system namespace isolation separately with explicit allow rules for the system components. Run kubectl get pods --show-labels against the target namespace before applying any broad selector.

Ingress Only

Focusing only on ingress leaves egress wide open. A compromised pod can still exfiltrate data or call out to malicious servers.

Define both ingress and egress rules. Include DNS.

Ingress-only thinking is tempting because the attack surface feels obvious: someone calling your API, someone reaching your web server. But a pod with only ingress restrictions behaves like a server with an open outbound firewall. If an attacker compromises your API pod, they can use it as a launchpad — reach command-and-control servers, mine cryptocurrency on external infrastructure, scan internal services for further exploitation.

Egress filtering is where the real value of defense-in-depth lives. A compromised web-frontend pod should not reach your database directly. It reaches the API on the API’s ingress port. The database then has its own ingress rules. Even if one pod is compromised, lateral movement is cut off.

To implement proper egress control, start with default-deny egress on every namespace with untrusted or multi-tenant workloads. Then add explicit egress rules for DNS (port 53 to kube-system), external APIs your application calls, and the specific backend services each tier needs. Avoid allowing all egress to internal networks — scope it to the exact pods and ports each source requires.

Forgetting DNS Egress

Default deny plus no DNS rule means no service discovery works. Your pods cannot resolve .cluster.local addresses.

DNS rule is mandatory. Add it before anything else.

When a pod wants to reach api-backend.production.svc.cluster.local, it queries CoreDNS in kube-system on port 53. Without an explicit egress rule for port 53, the query is dropped and the pod cannot discover any services. This breaks health checks, readiness probes that rely on service names, and any service mesh control plane traffic — not just application-to-application communication.

Use the kubernetes.io/metadata.name: kube-system label selector instead of a fixed IP address. CoreDNS pod IPs change during restarts and upgrades, so hardcoded IPs break. The rule needs both TCP and UDP on port 53:

egress:
  - ports:
      - protocol: UDP
        port: 53
      - protocol: TCP
        port: 53
    to:
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: kube-system

Put this rule at the top of your egress policy before anything else. Some teams centralize it by creating a single allow-dns-egress policy that applies to all namespaces rather than duplicating the rule per namespace — easier to audit and harder to forget.

Interview Questions

1. How do Kubernetes Network Policies implement zero-trust networking?

Expected answer points:

  • By default, all pods can communicate with all other pods in the cluster (flat network model)
  • Network Policies implement microsegmentation by explicitly defining allowed ingress and egress traffic
  • Without a policy, all traffic is allowed by default on most CNI plugins; with a policy, only explicitly allowed traffic is permitted
  • Policy is pod-scoped — each pod has its own ingress and egress rules that are additive when multiple policies select the same pod
  • Enforces least-privilege: start with default deny, then explicitly allow only required traffic patterns
2. How do you set up a default deny all ingress and egress policy?

Expected answer points:

  • Create a NetworkPolicy with empty podSelector (`{}`) to select all pods in the namespace
  • Set policyTypes to include both Ingress and Egress for full denial
  • Combined default deny: set policyTypes to ["Ingress", "Egress"] with no ingress/egress rules defined
  • Apply default deny before deploying any application, then add allow policies as you deploy services
  • Danger: always allow DNS (port 53 to kube-system) before applying default deny egress, otherwise pods cannot resolve service names
3. How do pod selectors and namespace selectors work together in Network Policies?

Expected answer points:

  • podSelector selects pods within the same namespace as the policy by label match
  • namespaceSelector selects entire namespaces, often combined with a podSelector for fine-grained control
  • Example: allow ingress from frontend namespace pods labeled app=web-frontend AND from monitoring namespace pods labeled app=prometheus
  • namespaceSelector uses the `kubernetes.io/metadata.name` label to match namespace names
  • Without namespaceSelector, podSelector only matches pods in the policy's own namespace
4. What are the differences between Network Policy support across major CNI providers?

Expected answer points:

  • Calico: Full support for ingress, egress, policy priorities (order field), and DNAT; extends with explicit action: Allow/Deny rules
  • Cilium: Full support with eBPF-based enforcement and L7 HTTP-aware policies for HTTP method/path filtering
  • Weave: Basic ingress and egress support only; no policy priorities or DNAT
  • Flannel: No Network Policy support at all
  • Always verify CNI capabilities before designing policies — a policy assuming a feature not implemented by your CNI will not be enforced
5. How does policy evaluation work when multiple Network Policies target the same pod?

Expected answer points:

  • Network Policies are additive — the union of all allowed traffic is permitted when multiple policies select the same pod
  • This means you must carefully design policies to avoid unintended exposure from combined rules
  • Some CNI providers like Calico support policy priorities (order field) where lower values have higher priority
  • Without priority support, there is no guaranteed evaluation order, so policy combinations may produce unexpected results
  • Best practice: use explicit deny rules at higher priority when you need to block specific traffic in combination with allow rules
6. How do you allow DNS resolution in egress rules after applying default deny?

Expected answer points:

  • DNS runs on port 53 (TCP and UDP) in the kube-system namespace
  • Create an egress rule allowing traffic to port 53 with a namespaceSelector matching `kubernetes.io/metadata.name: kube-system`
  • Include both UDP and TCP protocols since DNS can use either
  • Without this rule, pods cannot resolve `.cluster.local` service names or external domains
  • This is mandatory — add DNS egress before applying default deny egress to any namespace
7. How do L7 network policies in Cilium differ from standard Kubernetes Network Policies?

Expected answer points:

  • Cilium supports HTTP-level filtering at L7, not just port and protocol at L3/L4
  • L7 rules can restrict by HTTP method (GET, POST, PUT, DELETE) and URL path regex patterns
  • Example: allow only frontend to reach the API on specific paths like /api/v1/.* but block /api/v1/admin
  • CiliumNetworkPolicy uses toPorts instead of ports, with nested rules.http for L7 filtering
  • Cilium also supports Kafka and DNS filtering at L7
  • Standard K8s NetworkPolicies cannot filter by HTTP method or path — only by pod selector, namespace, and port
8. How do you test Network Policies in a staging environment before production?

Expected answer points:

  • Use kubectl exec or kubectl run to create a test pod and attempt connectivity to the target service
  • If connection succeeds, the policy allows the traffic; if it times out, the policy blocks it
  • Test both allowed paths (should succeed) and blocked paths (should fail) for comprehensive coverage
  • Use a policy visualizer like Hornet to see all rules applied to a pod and identify unintended exposure
  • Calico Enterprise provides policy simulation and impact analysis tools
  • Test DNS resolution separately to ensure the DNS egress rule works correctly
9. How do Network Policies help meet PCI-DSS compliance requirements?

Expected answer points:

  • Req 1.3.1 — Restrict traffic between cardholder data environment and other networks via default-deny and explicit allow rules
  • Req 2.2.1 — Restrict traffic to only necessary protocols and ports by specifying exact ports and protocols in policy rules
  • Apply default-deny to the cardholder-data namespace with explicit allow rules only for required services
  • Enable audit logging on security group changes for compliance evidence
  • SOC 2 CC6.1 and CC6.6 requirements for restricting access and enforcing network boundaries are also met by network policies
10. What are the most common mistakes when implementing Network Policies?

Expected answer points:

  • Applying default-deny to the wrong namespace — causes sudden outage with no obvious cause in application logs
  • Forgetting DNS egress rule — pods cannot resolve service names after default deny egress is applied
  • Only configuring ingress — egress remains wide open, allowing data exfiltration or calls to malicious servers
  • Using overly broad podSelector: {} — selects system pods and breaks core functionality
  • Assuming all CNI plugins support all policy features — Flannel does not support network policies at all
  • Not testing in staging before production — policy errors only appear when traffic is blocked in production
11. How does Cilium's eBPF-based enforcement differ from traditional iptables-based CNI policies?

Expected answer points:

  • eBPF runs at the kernel level, allowing per-connection tracking and visibility without traversing iptables chains
  • eBPF can enforce policies at the socket level, reducing latency compared to iptables-based policy enforcement
  • eBPF provides richer observability — you can see per-connection statistics, latency histograms, and TCP state
  • Cilium's L7 proxy integration with eBPF allows HTTP-aware policies without sidecar proxies
  • Traditional iptables-based policies require conntrack and iptables rules for each policy, which scales poorly in large clusters
12. How do you protect Kubernetes system namespaces like kube-system with Network Policies?

Expected answer points:

  • Apply a default-deny ingress policy to kube-system namespace
  • Add an ingress rule allowing traffic from pods with the label `kubernetes.io/metadata.name: kube-system`
  • This ensures only system pods (like CoreDNS, kube-proxy) can reach other system services
  • Application pods cannot reach system services unless explicitly allowed through additional policies
  • Use namespace-level isolation policies to protect system namespaces from workload traffic
13. How do you handle cross-namespace service communication with Network Policies?

Expected answer points:

  • Use namespaceSelector to allow traffic from specific namespaces, combined with podSelector for fine-grained control
  • Example: ingress rule allows from namespace with label name=frontend and pods labeled app=web-frontend
  • For DNS-based service discovery, ensure both namespaces have DNS egress rules allowing port 53 to kube-system
  • Calico's Tiered policies can enforce namespace-level isolation with hierarchical policy evaluation
  • Be explicit — too many namespace selectors create complex policies that are hard to audit
14. What is the relationship between Network Policies and pod security? How do they complement each other?

Expected answer points:

  • Network Policies control traffic flow at L3/L4 but do not restrict what a pod can do if it receives traffic
  • Pod Security Standards (PSA) and Pod Security Policies restrict pod capabilities: running as root, host access, capabilities
  • Use both together: network policies block unauthorized traffic, pod security restricts pod capabilities
  • Network policies are ineffective if a compromised pod can escalate privileges to run with host network or privileged access
  • Defense in depth: combine Network Policies + RBAC + Secrets encryption + Pod Security Policies
15. How would you design Network Policies for a three-tier web application (frontend, API, database)?

Expected answer points:

  • Start with default-deny ingress and egress for all three tiers
  • Allow frontend to reach API on the API's ingress port (e.g., 8080)
  • Allow API to reach database on the database's ingress port (e.g., 5432 for PostgreSQL)
  • All three tiers need DNS egress to kube-system on port 53
  • For external access, use an Ingress controller with its own policy allowing HTTP/HTTPS traffic to frontend only
  • API backend may need egress to external APIs or cloud services — allow explicitly per requirement
  • Database should have no ingress from external networks and minimal egress (only to API pods)
16. How do Network Policies interact with service mesh sidecar proxies?

Expected answer points:

  • Service mesh like Istio uses sidecar proxies (Envoy) to intercept all pod traffic at L7
  • Network policies work at L3/L4 before traffic reaches the sidecar, providing foundational filtering
  • Istio's AuthorizationPolicy provides L7-aware access control that works alongside NetworkPolicy
  • If a pod has a sidecar, all traffic goes through the sidecar — network policy enforcement may appear to be bypassed but is actually applied before the sidecar intercepts
  • Best practice: use NetworkPolicy for L3/L4 baseline (default deny, DNS, known services) and AuthorizationPolicy for L7 fine-grained control
17. What happens when you apply a Network Policy to a pod that is already running?

Expected answer points:

  • The policy is enforced immediately by the CNI plugin — existing connections may be affected if they are not among the allowed traffic
  • Established connections that are now blocked will be terminated at the connection level (not immediately, but when they try to send)
  • For rolling deployments, the policy is applied when the pod is recreated or when the CNI plugin reconciles
  • To avoid disruption, apply policies during low-traffic windows and have a rollback plan
  • Test in staging first — apply to production during maintenance windows when impact can be contained
18. How do you troubleshoot when a service cannot reach another service after applying Network Policies?

Expected answer points:

  • Check if the destination service's pod has a policy that blocks ingress from the source
  • Check if the source service's pod has a policy that blocks egress to the destination
  • Verify DNS resolution works: can the source resolve the destination service name? (DNS egress rule to kube-system on port 53)
  • Verify the port numbers match in both the policy and the service definition
  • Check if the pod selectors actually match the source and destination pods (label mismatch is common)
  • Test with a debug pod using kubectl run --rm -it to manually verify connectivity and diagnose
19. Can Network Policies block traffic from nodes to pods? How does host networking work with policies?

Expected answer points:

  • Pods using host network (hostNetwork: true) bypass the CNI entirely, so Network Policies do not apply to them
  • Traffic from nodes to pods running with host ports is not filtered by pod Network Policies
  • Use Pod Security Standards or NodeRestriction admission to prevent pods from using host network
  • For host-network pods that must exist (like kube-proxy), apply policies at the node level via security groups or cloud VPC rules
  • HostNetwork pods can still be reached by other hostNetwork pods on the same node if CNI-level policies do not apply
20. How do you implement egress filtering to prevent data exfiltration from compromised pods?

Expected answer points:

  • Start with default-deny egress to block all outgoing traffic
  • Explicitly allow only required egress destinations: DNS (port 53 to kube-system), specific API endpoints, known external services
  • For databases, allow egress only to the specific application pods that need database access, not to all pods
  • Consider egress gateways or NAT policies to restrict which pods can reach external networks
  • Cilium supports L7 egress policies that can filter by HTTP Host header or DNS domain name to block exfiltration via DNS tunneling or HTTP
  • Monitor egress traffic patterns in production to understand normal behavior before tightening policies

Further Reading

Conclusion

  • Default deny policies applied to untrusted namespaces first
  • Only required traffic explicitly allowed per application
  • DNS egress allowed (port 53 to cluster DNS service)
  • Policies tested in staging before production
  • CNI plugin capabilities verified for required features
  • Policy visualization used to check for unintended exposure
  • Network Policies combined with RBAC and Secrets encryption
  • Policy rationale documented and reviewed during security audits

For more on Kubernetes networking, see the Services and Networking post.

Category

Related Posts

Cloud Security: IAM, Network Isolation, and Encryption

Implement defense-in-depth security for cloud infrastructure—identity and access management, network isolation, encryption, and security monitoring.

#cloud #security #iam

Kubernetes Services: ClusterIP, NodePort, LoadBalancer, Ingress

Master Kubernetes service types and Ingress controllers to expose your applications inside and outside the cluster with proper load balancing and routing.

#kubernetes #networking #services

Secrets Management: Vault, Kubernetes Secrets, and Env Vars

Learn how to securely manage secrets, API keys, and credentials across microservices using HashiCorp Vault, Kubernetes Secrets, and best practices.

#microservices #secrets-management #security