Learn Flannel - Network Policy Ecosystem
Episode 14 of 23

Learn Flannel - Network Policy Ecosystem

This episode explains why Flannel does not enforce NetworkPolicy and how to complete it: adding a policy engine such as Calico policy-only or Cilium on top of Flannel without replacing the CNI, then applying the first NetworkPolicy and verifying it.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Kubernetes provides NetworkPolicy as the standard for restricting traffic between Pods. But that standard only works if the CNI enforces it. This is where Flannel honestly admits its limits.

Episode 14 explains why Flannel does not enforce NetworkPolicy, then guides you through adding a policy engine on top of Flannel without replacing the CNI. You will install Calico policy-only, apply your first NetworkPolicy, and verify it.

Why Flannel Does Not Enforce NetworkPolicy

CNI Data Plane Limitations

NetworkPolicy needs an engine that filters packets based on Pod labels and keeps connection state. Flannel is designed as a simple data plane that only builds routes and overlays. Adding policy enforcement would break the simplicity that is the main reason people choose Flannel.

The Common Pattern

Instead of replacing the CNI, the common pattern is to add a separate policy engine. This engine reads NetworkPolicy from the API server, converts it into rules on the nodes, and filters traffic without interfering with Pod network creation. Flannel stays the data plane; the engine becomes the policy plane.

Adding a Policy Engine on Top of Flannel

Calico Policy-Only

Calico provides a dedicated manifest that only deploys the policy components, without replacing the Flannel CNI:

Install Calico policy-only
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico-policy-only.yaml

The kubectl apply -f calico-policy-only.yaml command deploys the Calico daemons and components that enforce policy, while Pod network creation stays with Flannel.

Cilium Without Replacing the CNI

Cilium can also act as a policy engine on top of Flannel in certain modes. The choice comes down to team preference and the features you need. What is certain is that both approaches avoid the far larger risk of a full CNI migration.

Applying Your First NetworkPolicy

Policy: Block Cross-Namespace Traffic

The most common example: a namespace may only receive traffic from a specific namespace:

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

The policy above makes all Pods in that namespace only able to receive traffic from the kube-system namespace. All other traffic will be blocked by the policy engine.

Apply the policy
kubectl apply -f allow-kube-system-only.yaml

The kubectl apply -f allow-kube-system-only.yaml command registers the policy with the API server. The policy engine then enforces it on every node.

Verification and Considerations

Testing the Effect of the Policy

Deploy two Pods in different namespaces and test connectivity. Pods in the namespace covered by the policy must not be reachable from other namespaces:

Test after the policy is active
kubectl run nettest-a --image=busybox --restart=Never -- sleep 3600
kubectl exec -it nettest-a -- ping -c 2 <ip-pod-namespace-lain>

If ping fails after the policy is applied, enforcement is working. Without a policy engine, ping would succeed because Flannel does not filter.

Things to Keep in Mind

Adding a policy engine adds new components you must maintain: its daemon, RBAC, and metrics. Start with a loose policy and test carefully before tightening. A policy mistake is easier to prove than it is to fix in the middle of an incident.

Tip

Before enabling a default deny policy in production, make sure cluster monitoring, ingress, and DNS are on the allowlist. Otherwise, the whole cluster could lose connectivity in an instant.

Verifying the Policy Engine

Make Sure the Engine Is Truly Active

After installing a policy engine, make sure it is actually enforcing rules. There are many cases where a policy is applied but has no effect because the engine is not running or the namespace labels do not match. Check the policy engine's Pods in your cluster:

Check the policy engine components
kubectl get pods -n calico-system 2>/dev/null || kubectl get pods -n kube-system | grep -i calico

The output of kubectl get pods -n calico-system shows the Calico components that enforce policy. Make sure they are all in the Running state.

Test with a Real Scenario

Do not settle for a single test. Create additional scenarios: allow traffic from one specific namespace, then block another namespace. Every policy change should be tested in staging before being used in production, just like the GitOps practices in episode 18.

Conclusion

Episode 14 completes Flannel's security with a policy plane: understanding Flannel's limits with NetworkPolicy, adding Calico policy-only or Cilium on top of it, and applying a first policy that actually works.

Key takeaways:

  • Flannel does not enforce NetworkPolicy because it focuses on connectivity.
  • A policy engine enforces policy without replacing the Flannel CNI.
  • Calico policy-only can be installed on top of Flannel with a single manifest.
  • Cilium can also serve as a companion policy engine.
  • A default deny policy in production needs a well-prepared allowlist.
  • Verify policy with cross-namespace connectivity tests.

In the next episode, episode 15, we will secure the host layer: firewall and host networking — the ports that must be opened for VXLAN, WireGuard, and IPsec in both the host firewall and the cloud, as well as how to pick the right host interface with --iface and avoid IP conflicts.

Learn Flannel - Network Policy Ecosystem | Learn Flannel