Kubernetes NetworkPolicy default-deny is the right security posture. If a pod can only communicate with what it’s explicitly allowed to communicate with, an entire class of lateral movement and unexpected dependency problems goes away.
It’s also one of the most reliable ways to break production if you enforce it without knowing what’s actually communicating.
The cold enforcement problem
The failure mode is predictable. You apply a default-deny NetworkPolicy. Traffic starts failing. Something unexpected was communicating with something else — a health check endpoint, a metrics scraper, a service dependency that wasn’t documented — and now it’s blocked.
The ensuing incident is fixable. You remove or relax the policy, traffic recovers, and you update the policy to permit what should be permitted. But you’ve created an outage, and the trust in the network policy work takes a hit that takes time to recover.
The problem wasn’t the goal. Default-deny is the right goal. The problem was the sequence: enforce first, discover traffic second.
Observe mode as the correct starting position
The better sequence: implement in observe mode first. Log what would be blocked by a default-deny policy, without actually blocking it. Use that data to map the real traffic patterns across your cluster. Then enforce progressively against a traffic map you’ve validated.
Kubernetes itself doesn’t have a native “observe mode” for NetworkPolicy — policies either match and enforce or they don’t. But you have options:
Cilium’s policy enforcement modes let you enable policy in audit mode: traffic that would be blocked is logged but not dropped. You can review the flow logs, map the communications that a default-deny policy would affect, and build out your allow rules against real data.
With standard Kubernetes NetworkPolicy, a similar effect is achievable by starting with a broadly permissive policy and tightening it incrementally — not ideal, but it lets you observe before enforcing. The goal in either case is the same: understand what’s actually talking to what before you make any of it impossible.
On a securities brokerage platform in Indonesia, we implemented Kubernetes RBAC and network segmentation as part of a security audit remediation. The approach was staged deliberately: we documented the expected traffic patterns from the application inventory, then validated those patterns against actual cluster traffic before writing policy. Where the documented pattern and the actual traffic diverged — and they did, on a handful of services — we investigated the discrepancy rather than assuming the documentation was correct.
Some of the discrepancies were misconfigured services that should have been cleaned up. Some were legitimate patterns that hadn’t been documented. Both categories needed a decision before enforcement.
The migration metaphor applied to security controls
The same instinct that drives staged traffic shifting in a migration applies to security control enforcement. You don’t shift 100% of traffic to the new platform on day one because you want to validate behaviour in production incrementally. The rollback window stays open until you’re confident.
Default-deny enforcement follows the same logic. You don’t enforce against 100% of traffic on day one because you haven’t validated what the actual traffic patterns are. The observation window stays open until you have a traffic map you trust.
The acceptance criterion for moving from observe to enforce is the same question you ask at every migration cutover: have we validated the new state against real production behaviour? Can we explain what’s changing and why?
For network policy, that means: do our allow rules cover everything in the traffic logs? Have we reviewed the things the logs flagged and made a deliberate decision about each one — either permitting it, or identifying it as something that should stop communicating?
Progressive enforcement
Once the traffic map is validated, enforcement can be progressive. Start with the namespace or service boundary where the communication patterns are clearest and the blast radius is lowest. Enforce there, observe for a period, then extend to the next boundary.
This gives you real enforcement in production — not a paper policy — while maintaining the ability to diagnose and fix gaps without a full outage.
The goal is a cluster where default-deny is active and every permitted communication is explicit. That state is achievable. The path to it goes through observation, not past it.
Enforce when you know what you’re enforcing. Observe until you do.