Skip to main content
Cloud DevOps Solutions
Get a quote Talk to an engineer

Kubernetes Consulting

Implementing Kubernetes Network Policies Without Breaking Production

Kubernetes network policies restrict which pods can talk to which, limiting how far an attacker or a bug can spread. We map real traffic, choose Calico or your cloud's native CNI enforcement, roll out default-deny namespace by namespace in observation first, and verify with tests before enforcing.

Key takeaways

  • By default every pod can reach every other pod, so one compromised workload can scan the whole cluster.
  • Network policies only work if your CNI enforces them, so the CNI choice comes first.
  • Start from observed traffic, apply default deny per namespace, then allow only what is needed.
  • Do not forget DNS and egress to cloud services, the two most common causes of broken rollouts.
  • Rules are code, tested in CI, and owned by the team that owns the workload.

Why flat pod networking is a risk

Out of the box, Kubernetes networking is open: every pod can reach every other pod, in any namespace, on any port. That is convenient and, for production, dangerous. If an attacker gets code execution in one internet-facing pod, they can probe the database, internal admin tools and the cloud metadata endpoint without a single firewall in the way.

Network policies are the built-in answer. This page explains how we implement a Kubernetes network policy model as part of our Kubernetes consulting work, why rollouts so often go wrong, and when the effort is not worth it.

Step zero: does your CNI enforce policy?

A NetworkPolicy is only a declaration. The container network interface (CNI) plugin does the enforcing. If it does not support policy, objects are accepted and silently ignored, which is worse than having none because it feels safe.

Typical situations:

  • EKS: the Amazon VPC CNI can enforce policy when the feature is switched on, or you can run Calico.
  • AKS: choose a policy engine at cluster creation (Azure’s own, Calico or Cilium), and check it matches your CNI mode.
  • GKE: Dataplane V2 (Cilium based) enforces policy, or Calico can be enabled.

Check, then test with a deliberate deny and a probe pod. Do not trust the YAML.

Native policy or Calico

Both implement the standard Kubernetes API. Calico also has its own resources with deny rules, ordered tiers, global policies and host endpoint protection. The decision:

NeedNativeCalico
Namespace and pod allow rulesYesYes
Explicit deny rulesNoYes
Cluster-wide baseline policyAwkwardGlobalNetworkPolicy
Fewer moving partsBetterExtra component
Policy by DNS name or FQDNLimitedAvailable in some editions

Most startups are well served by native policy. We recommend Calico when a security team wants cluster-wide guardrails or deny semantics.

The rollout pattern we use

Applying default deny to a live namespace without preparation is how outages happen. The sequence:

  1. Observe. Collect real flows, using CNI flow logs, Hubble on Cilium, or Calico flow logs. Include DNS, cluster add-ons, metrics scraping and calls to cloud APIs.
  2. Label. Policies select by labels, so consistent labels on workloads and namespaces come first.
  3. Write allows before denies. Draft the allow rules for a namespace and review them with its owners.
  4. Apply default deny last, in non-production first, then production, one namespace at a time.
  5. Watch. Monitor dropped connections and application errors for a full traffic cycle, including batch jobs.

A default deny baseline plus DNS and one real flow looks like this:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: payments
spec:
  podSelector: {}
  policyTypes: [Ingress, Egress]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-egress
  namespace: payments
spec:
  podSelector: {}
  policyTypes: [Egress]
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - { protocol: UDP, port: 53 }
        - { protocol: TCP, port: 53 }
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-from-ingress
  namespace: payments
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes: [Ingress]
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress
      ports:
        - { protocol: TCP, port: 8080 }

The label on the DNS pods (k8s-app: kube-dns) is standard for CoreDNS but verify it in your cluster.

What breaks, and how we avoid it

  • DNS. Covered above. Always ship a DNS allow with default deny egress.
  • Ingress controller reachability. Your ingress controller namespace must be allowed to reach backends.
  • Monitoring scrapes. Prometheus needs to reach metrics ports, or dashboards go blank. See cluster monitoring.
  • Egress to managed services. Databases, object storage and third party APIs live outside the cluster, so egress rules need CIDR ranges or, on engines that support it, FQDN rules. IP-based rules go stale when providers change addresses.
  • Webhooks and the API server. Admission webhooks and operators need control plane traffic allowed.
  • Cloud metadata endpoint. Blocking pod access to the instance metadata address is a high-value, low-effort egress rule.

Worked example: a three tier namespace

Take a namespace with a web frontend, an API and a database. After default deny and DNS, the allow list is short and readable: ingress controller to frontend, frontend to API, API to database, and Prometheus to each metrics port. Anything else, such as the frontend talking straight to the database, is intentionally absent.

We then prove the negative. A temporary pod labelled like the frontend tries to open a connection to the database port and must be refused, while the API pod must succeed. Keeping these two checks in CI means a future label change that quietly widens or breaks access fails a build rather than surfacing in production. Teams often discover at this stage that a service was making a call nobody remembered, which is exactly the value of mapping flows first.

Trade-offs and when not to do it

Policies add friction. Every new service needs rules, and a mislabeled pod can lose connectivity in confusing ways. They do not encrypt traffic, and they do not understand HTTP paths or identities. If you need encryption between services or layer 7 rules, you are in service mesh territory, which we cover in Kubernetes consulting discussions case by case.

For a small cluster with one team and no sensitive data, a lightweight approach may be enough: default deny only on the namespaces holding databases and admin tools. For regulated workloads, a full model is usually worth it. Combine it with least privilege RBAC, since network and API access are separate attack surfaces.

Delivery and how to tell it works

We deliver the policy set as code in your repository, a labelling convention, automated connectivity tests that run in CI (for example a short-lived pod that must succeed on allowed paths and fail on denied ones), and a one page guide for requesting new flows. Success looks like: a probe pod in the wrong namespace cannot reach your database, deny counters are low and explainable, and no one needs a change ticket for ordinary traffic. If you want help designing your model, reach out.

References

How we deliver it

  1. 01

    Check CNI and enforcement

    We confirm your CNI supports network policy and decide whether native enforcement or Calico fits.

  2. 02

    Map actual traffic

    Flow logs or observability tooling show who really talks to whom, including DNS and external calls.

  3. 03

    Design the policy model

    We agree a namespace baseline, labelling scheme and which teams own which rules.

  4. 04

    Roll out in stages

    Policies go in non-production first, then production namespace by namespace, starting with low risk services.

  5. 05

    Test and monitor denies

    Connectivity tests and deny logs confirm that only unexpected traffic is blocked.

  6. 06

    Automate and document

    Policies live in Git, tests run in CI, and a short guide explains how to request a new allowed flow.

Tools and technologies

CalicoCiliumAmazon VPC CNIAzure CNIGKE Dataplane V2NetworkPolicykubectlnetshootHubbleArgo CDKyverno

Frequently asked questions

Do Kubernetes network policies work on EKS, AKS and GKE?
Yes, but enforcement depends on configuration. The Amazon VPC CNI supports network policy when the feature is enabled, AKS offers Azure Network Policy Manager, Calico or Cilium options, and GKE uses Dataplane V2 or Calico. Without an enforcing CNI, policy objects are accepted but do nothing.
Should we use Calico or the native CNI?
Native enforcement is simpler and fully supported by the cloud, and it is enough for standard allow rules. Calico adds richer features such as global policies, deny rules, ordering and host protection. Choose Calico when you need those, and accept the extra component to operate.
What is a default deny policy?
It is a policy that selects all pods in a namespace and allows no traffic, so anything not explicitly permitted is blocked. You then add allow rules for each needed flow. Default deny turns the cluster from open by default into closed by default, which is the point.
Why did my pods lose DNS after adding a policy?
A default deny egress policy also blocks traffic to CoreDNS, so name resolution fails. You must allow egress to the cluster DNS service on port 53, both UDP and TCP, usually by selecting the kube-system namespace and DNS pods. This is the most frequent mistake we see.
Can network policies replace a service mesh?
They overlap but differ. Network policies work at layers 3 and 4 by IP, port and label. A service mesh adds mutual TLS, identity-based rules and layer 7 controls, with more operational cost. Many clusters need only policies; mesh is justified by encryption or fine-grained routing needs.

Talk to an engineer about kubernetes network policy implementation

Book a free 30-minute call. We review your current setup and tell you honestly whether and how we can help.

Written by Saddique Khan, DevOps / SRE / Cloud Consultant Engineer. Last updated 2026-10-08.