Network policy changes are among the most frequent operations in a Kubernetes cluster. They are also among the most delicate, as even a small mistake can lead to widespread traffic disruption. This tutorial walks through several methods to make policy management safer, especially in day-2 operations or brownfield deployments where clusters already run critical workloads. It shows how to test and validate changes before enforcing them, helping teams adopt a more reliable approach to policy rollout. By following these steps, you can build confidence in your network policy lifecycle and reduce the likelihood of accidental outages. How do Cilium network policy operations and enforcement modes work? Cilium network policies build upon Kubernetes NetworkPolicy, extending it with deeper visibility and more flexible rule types. Policies are used to allow or deny traffic based on defined rules, which can apply to ingress, egress, or both. These rules are evaluated at the datapath level, meaning enforcement can take place directly in the kernel through eBPF. Every Cilium-managed endpoint operates under a policy enforcement mode, which defines the default network behavior before and after a policy is applied: Default: All traffic is allowed until an endpoint is selected by a policy. Once selected, traffic is denied unless explicitly permitted. Always: All traffic is denied by default. Only explicitly allowed connections are permitted. Never: Policies are disabled entirely for selected endpoints. Use this mode if you want a default-allow network policy. This distinction matters when introducing or changing policies. A newly applied policy that selects an endpoint will immediately transition that endpoint from “allow-all” to “deny-all.” Any traffic not explicitly covered by a rule will be dropped. There are two situations where this transition can cause disruption: Applying the first policy — This changes the endpoint’s default mode from open to restrictive, potentially cutting off traffic you didn’t plan to block. Updating an existing policy — Specific flows may be unintentionally denied or allowed depending on the rule changes. The following sections explore practical ways to handle both cases safely; observing real traffic before enforcement, auditing changes, and simulating outcomes to ensure consistent behavior. Test environment setup As a test application, we’ll be using a single Pod with isovalent=cilium-tutorial label, which can be deployed with this command: To trigger network traffic we will be connecting to this pod and executing commands from its shell, e.g. Before you proceed, take note of the values of identity, endpoint and the name of the cilium pod managing the test application. These values will be used in subsequent commands to narrow down the output. As an example, here’s the command you can use to view the Hubble flow log for the test application. Hubble is Cilium’s observability component that provides detailed visibility into network traffic and policy decisions across your cluster. We have detailed write-ups and showcase labs available if you’d like to read more or get hands-on experience. Some of the techniques described in this post work best when they can access historical network flow data. For long-term visibility and richer simulations, Isovalent Networking for Kubernetes provides Hubble Timescape, which provides centralized storage and querying of Hubble flow logs. Scenario 1: Applying the first default deny policy Applying the first network policy triggers the default-deny behavior, which may unintentionally block traffic not yet accounted for in your definitions. Cilium provides two mechanisms that let you preview the impact of these changes before enforcement. Let’s start with a simple egress-only policy that allows connections to a single destination (1.1.1.1/32): You can observe allowed traffic using Hubble. If the test pod connects to https://1.1.1.1, the output may look like this: The above output displays only a subset of information contained in the actual flow log. To see the entire payload, including the reference to a policy that allowed this type of traffic, you can add the --output json flag to the above command, e.g.: Now let’s focus on detecting dropped flows safely, without actually enforcing deny behavior. Solution 1.a: Endpoint audit mode Audit mode lets you apply policies to an endpoint while disabling enforcement. Verdicts appear in Hubble as AUDIT rather than DROP or FORWARDED. Enable audit mode for a specific endpoint: Remember that this setting is not persisted, so it will be disabled if Cilium agent restarts. To filter the audit logs for flows that would have been denied: The above flow log would result from our test application trying to access a destination not explicitly permitted by the policy, e.g. https://8.8.8.8. Once you’re happy with the observed results, you can disable the audit mode for an endpoint with the following command. The downsides of this approach is that it works per-endpoint, meaning that policies need to be carefully constructed not to select non-audit mode endpoints, or, requires enabling audit mode on all selected endpoints. Solution 1.b: Policy default deny mode You can also control the default enforcement behavior directly within a CiliumNetworkPolicy using the enableDefaultDeny field. This approach has the following advantages compared to the previous solution: It’s policy-centric rather than endpoint centric, which makes it easier to implement. It works per-direction, allowing extra flexibility to control the enforcement mode It’s part of the CNP/CCNP specification and doesn’t require agent-level changes This is how you would audit your first policy using the current solution. Take the example policy defined above and disable the default deny behaviour by setting spec.enableDefaultDeny.egress to false. In order to see and distinguish the implicitly allowed traffic, you need to filter based on the policy_match_type field of the Hubble flow log. This can be done by adding a CEL expression to the hubble observe query to filter the “allow-all” matches, which correspond to policy_match_type value of 4 (see the tip below for more information): The above command would allow you to see all traffic that would’ve been blocked if the default deny mode was set to enabled. You can use these flows to assess the potential impact of the applied policy and, when you’re happy with the results, flip the default deny mode back to the default value of true. With this solution, you have to remember that each policy will have its own EnableDefaultDeny flag, with default value being true which would always take priority over false. So whenever you apply a combination of policies, make sure they all have this flag set to the right value. In general, our recommendation is to start with a small set of well-understood policies and transition to the full “default deny” mode early in the lifecycle of a cluster, to limit the blast radius of a potential change. Tip: The policy_match_type field records which part of the policy logic allowed or denied a flow. You can use it to understand why Cilium made a particular decision. Common values include: You can confirm this mapping in raw Hubble output, the below example is after running kubectl exec example -- curl https://1.1.1.1: Scenario 2: Making changes to the existing policies Continuing from scenario 1, where we introduced our first policy, the focus now moves to maintaining and evolving your configurations safely. Once an endpoint has transitioned into the “default deny” mode, making incremental changes should be a lot safer. Here is the breakdown of the potential changes along with an estimated worst case impact: Similar to the previous scenario, our goal is to ensure that we can make these changes, while minimizing the risk of an unintended drop. Let’s examine available options starting with the last change type. Solution 2.a: L7 allow-all This solution is designed to address the “adding the first L7 policy” change type. It works by constructing a L7 policy that matches and, thus, allows all traffic. There are two special cases, depending on the type of L7 traffic, which are covered in the following examples. Use Case 1: Allow all DNS traffic The following policy will allow all DNS traffic to kube-dns. If applied as a CiliumClusterwideNetworkPolicy, you can also use enableDefaultDeny to avoid accidentally enabling default deny for pods with no policies applied. Once you apply this policy to the test application, you should be able to see DNS queries in the Hubble flow log: Use case 2: Allow all HTTP traffic You can use a similar approach of allowing all HTTP traffic to gain L7 HTTP visibility. The Hubble flow log will provide Layer 7 relevant information, in the below example, this includes HTTP Request, Method, Latency and response code. Solution 2.b: Introducing IsoPolicy for Network Policy simulations Introducing Isopolicy Isopolicy is a command-line tool designed to simplify the management and validation of Cilium network policies. It performs static analysis, suggests optimizations based on live or historical Hubble Timescape data, and simulates the outcome of proposed policy changes. By combining information from CiliumNetworkPolicy objects, CiliumEndpoints, and Hubble flows, it helps identify stale or redundant rules, fine-tune policy scope, and reduce common configuration errors before they affect workloads. One of the most powerful features is the simulate command, which creates a safe “what-if” environment for testing policy updates. Users can preview how new, modified, or deleted policies would impact network access across identities or namespaces without changing the live cluster. When connected to Hubble Timescape, Isopolicy can even replay historical flows to show how verdicts would have differed under the new configuration, providing a reliable way to validate intended outcomes and strengthen overall policy hygiene. You can see Isopolicy in action in the below technical walkthrough video, or follow along with the remainder of this blog post! Using Isopolicy The isopolicy CLI tool is available for both Linux and MacOs, and can be downloaded by customers from the Isovalent Enterprise Documentation pages or via request from our support desk and customer success team. Preparing for a Simulation Let’s revisit the test application and its simple CiliumNetworkPolicy that allows egress access to isovalent.com only. To ensure the below policy works correctly, there is an existing CiliumClusterwideNetworkPolicy implemented that allows DNS from workloads to the kube-dns service. If this existing policy did not exist, then the rules of default deny would apply, as discussed in the previous scenarios: The test application tries to access the allowed domain but also a couple of destinations that are implicitly denied at this stage: Only the first command should succeed as the rest of the FQDNs are falling under the implicit deny rule. Now let’s imagine you want to change this policy and allow access to cisco.com instead of isovalent.com. We will save the below policy into a directory called proposed: Running a Simulation You can now simulate how this change would affect your workloads without applying it to the live cluster: This command compares the proposed policy set in the proposed/ directory with the current cluster state. The simulation engine evaluates both configurations and shows how the effective policy would change if the new manifest were applied. The first table, “Simulated Network Policies,” lists all the egress rules that would exist after applying the change, including both existing and new entries. Each row shows the source pod, destination, identity IDs, protocol and port, verdict, and the policy that permits the traffic. The second table, “Simulation Results” highlights the differences between the current and proposed states. Rows prefixed with + represent newly allowed connections, while rows prefixed with - indicate flows that would be removed or denied as a result of the update. This makes it clear at a glance which endpoints or domains gain or lose access under the revised policy. For brevity, the lines concerned with the existing network policy that allows traffic to the kube-dns service, have been removed from the below output. The above simulation is performed in the so-called “offline” mode, as it doesn’t rely on historical flow data and only uses the control plane data to estimate the results. If Hubble Relay or Timescape are available, you can replay actual flow history for more accurate results. The --range flag specifies how far back to look, with isopolicy automatically discovering Hubble Timescape, to consume it's historical data. The below output shows the new proposed updated Cilium Network Policy would allow the previously denied flows to cisco.com, with the previously allowed traffic to isovalent.com would be denied: With flow data as a reference, we were able to correctly predict the impact of a change for all of the three traffic destinations and corroborate it with example flows that would be affected. This simulation workflow can be extended to several other scenarios. You can run it against a sysdump to analyze policies offline, evaluate how proposed DNS or other Layer 7 rules would affect existing traffic, or even use it when introducing the very first network policy to preview enforcement results before switching to default deny mode. Summary & Next Steps In this post you learned how to manage Cilium network policies more safely. We explored two main change scenarios; applying a first default-deny policy and editing existing policies, and introduced practical techniques such as audit mode, default-deny toggles, L7 allow-all scaffolding, and policy simulations using Isopolicy. When used properly, these approaches help you validate policy changes before they hit production and reduce the risk of traffic disruptions. If you want to explore Cilium policy design and best practices further, download our free resources: 📘 Cilium Network Policy Deep Dive: a practical guide to building, testing, and securing advanced Cilium policies. 📗 Kubernetes Network Policies Done the Right Way by Isovalent: a step-by-step ebook on network policy strategy, validation, and real-world adoption. 🎥 Join our live webinar: Network Policies Done the Right Way: see these concepts in action and learn how to apply effective segmentation across workloads using Cilium and Isovalent Enterprise. Coming next: In the next article, we’ll look at Isopolicy’s Tune capabilities. You’ll see how to use live and historical Hubble flows to automatically suggest refinements to existing policies, trim redundant rules, and continuously strengthen your cluster’s security posture.