netpol: NetworkPolicy v1 enforcement via nftables
Build flock Image / build (push) Has been cancelled

New pkg/agent/netpol implementing standard networking.k8s.io/v1
NetworkPolicy. Pipeline:

  pods + policies + namespaces  →  Translate  →  Render  →  Apply

Supports ingress + egress, all three peer types (podSelector,
namespaceSelector, ipBlock with except), numeric ports + port ranges,
default-deny semantics derived from PolicyTypes (or inferred from
non-empty Spec.Egress when unset).

Apply path is `nft -f -` shell-out — single transaction, atomic, kernel
guarantees partial-failure rollback. Idempotent dedup via last-applied
script. Reconcile triggers: informer events, 30s self-heal tick, every
CNI ADD/DEL.

Verified against the three live cluster NetPols (calico-apiserver,
remote-proxies/lodge-home-assistant, storage/garage-admin-restrict).
Fuzz target stitches Translate + Render with random selector and peer
inputs; 21 unit tests cover the policy semantics.

Named ports skip with a warn — deferred until kubelet exposes them in a
form that doesn't require shadowing pod state.

Dockerfile: + nftables.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Donavan Fritz
2026-04-25 09:25:58 -05:00
parent 71e584cf96
commit 39ede9130b
16 changed files with 2698 additions and 2 deletions
+19 -1
View File
@@ -7,6 +7,8 @@ import (
"fmt"
"net"
"time"
"code.fritzlab.net/fritzlab/flock/pkg/agent/netpol"
)
// configureRuntime wires Pod informer, IPAM, netlink, and BIRD on a real
@@ -103,6 +105,17 @@ func (s *Server) configureRuntime(ctx context.Context) error {
}
}()
// NetworkPolicy enforcement.
world := netpol.NewWorld(s.Logger)
if err := world.Start(ctx, s.restCfg); err != nil {
return fmt.Errorf("netpol informers: %w", err)
}
npApplier := &netpol.Applier{}
npReconciler := netpol.NewReconciler(world, func() []netpol.Pod {
return collectLocalPods(s.Store, pods)
}, npApplier, s.Logger)
go npReconciler.Run(ctx)
handler := &PodHandler{
Node: s.Node,
Store: s.Store,
@@ -111,7 +124,12 @@ func (s *Server) configureRuntime(ctx context.Context) error {
NodeConfig: s.NodeConfig,
SetupFunc: Setup,
TeardownFunc: Teardown,
AfterCommit: anycast.Trigger,
AfterCommit: func() {
anycast.Trigger()
// Re-evaluate policy on every CNI ADD/DEL so a brand-new
// pod's chain lands before its first packet egresses.
npReconciler.Trigger()
},
}
s.RPC.SetHandlers(handler.Add, handler.Del, handler.Check)
s.Logger.Info("runtime ready",