Skip to content

How policy works

NetworkPolicy objects are not enforced directly. The engine compiles the whole set of policies into Segments, the data plane enforces reachability between segment IDs, and a generation-based rollout keeps every node consistent while the set changes.

A Segment is a policy identity: the equivalence class of endpoints that match the exact same set of policy rules. Where a NetworkPolicy selects endpoints by label, a Segment is what those selections collapse to — two endpoints selected by precisely the same rules share one segment and therefore one numeric ID.

A Segment is matched the way a NetworkPolicy peer is:

  • in / notIn — the label requirements an endpoint must and must not satisfy.
  • prefixes / excludes — IP prefixes the segment covers, for peers that have no endpoint object (external addresses, ipBlock).

Its resolved reachability is held as peer allow-lists, each tristate to mirror NetworkPolicy semantics:

  • ingressPeers — segments allowed to reach this one as a destination.
  • egressPeers — segments this one may reach as a source.
  • nil means no policy of that direction selects the segment (unrestricted); empty means a policy selects it but allows nothing (deny-all); populated is the allow-list, each peer carrying the allowed ports.

Policies overlap constantly: one endpoint can be selected by many rules at once. When the rule set changes, endpoints that now match a different combination of rules are moved into a new Segment. Segments are never mutated in place — they are only created (stamped with createGeneration) or marked deleted (deleteGeneration).

Every change to the policy set advances a generation counter. Because old segments stay valid until explicitly deleted, generations are strictly ordered and always compatible: an older generation remains fully enforceable while a newer one is still rolling out.

Two cluster-scoped resources coordinate the rollout:

  • PolicyStatus — a singleton (global). Its spec carries desiredPolicyGeneration (the segments every node must install) and desiredEndpointGeneration (the generation nodes may assign endpoints to). Its status aggregates the cluster: oldestPolicyGeneration / oldestEndpointGeneration and the last reconciled batch.
  • NodePolicyStatus — one per node. Its status reports latestPolicyGeneration (segments the node has installed in its BPF maps) and latestEndpointGeneration (the generation all of the node’s endpoints have been assigned to).

The rollout is a two-phase barrier:

  1. The engine writes the new segments and bumps desiredPolicyGeneration.
  2. Each node installs those segments and reports its latestPolicyGeneration.
  3. The controller sets desiredEndpointGeneration to the minimum latestPolicyGeneration across all nodes — endpoints may reference a generation only once every node already has its segments, so an endpoint is never pointed at a segment some node lacks.
  4. Nodes assign their endpoints to that generation and report latestEndpointGeneration.
  5. oldestPolicyGeneration / oldestEndpointGeneration track the minimum across nodes; segments deleted at or before that point have no remaining references and can be garbage-collected.

When desired and observed generations agree across every node, PolicyStatus shows the policy set has fully converged.

Each NetworkEndpoint records the segment it belongs to: the segment ID, the generation that assignment is valid for, and a named-port variation. At enforcement time the peer of a flow resolves to an endpoint and from there to its segment — by IP address for L3, by MAC for L2 (see Network policy).

A NetworkPolicy may allow a port by name, and different endpoints in the same segment can resolve that name to different protocol/number pairs. The Segment lists the relevant portNames and a set of variations: each distinct resolution of those names is one variation with its own per-segment ID, monotonic and never reused.

An endpoint’s segment assignment carries its variation ID alongside the segment ID. The variation exists only so the data plane can resolve a named port to a concrete one; it never affects matching. Peers are matched by segment ID alone — the variation is not generation-gated and two endpoints in the same segment are interchangeable as a peer regardless of their variation.