netpolicy

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package netpolicy is the engine module for Phase 6 (CAPABILITY_SPEC domain 6): network egress analysis and least-privilege policy generation. It is a thin adapter — the flow model and detection heuristics live in internal/netmon; this package loads a recorded capture from a Target, runs netmon over it, and projects the resulting anomalies and posture observations onto engine.Finding.

It also *generates* least-privilege artifacts from an observed baseline: a Kubernetes NetworkPolicy, a companion DNS/FQDN egress allowlist, and a default-deny egress policy. Generation is advisory by design — the module and the `dsecrat net` command emit policy for review or agent-application, never enforce it. That keeps us an observation-and-recommendation layer, not a dataplane, exactly as the phase handoff requires.

Two AI-age features ride on top, both OFF by default (opt in via Target metadata or CLI flags): egress intent modelling (intended-vs-anomalous destinations with a rationale an agent can approve) and agent egress governance (watching AI-agent workloads for egress to unknown model hosts).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Command

func Command(args []string) int

Command runs `dsecrat net <capture.json> [flags]`. Exit codes: 0 ok, 1 error or --fail-on threshold met, 2 usage error.

func Register

func Register(r *engine.Registry)

Register adds the netpolicy module to the registry. The master agent calls this from modules.Default() during integration, so this package never edits the shared registry file (parallel-safe wiring — see SHARED_CONTRACT §2).

func RenderFQDNAllowlist

func RenderFQDNAllowlist(gp GeneratedPolicy) string

RenderFQDNAllowlist renders the DNS/FQDN egress allowlist as an advisory YAML document. Standard NetworkPolicy cannot express FQDN egress, so this is a portable artifact for an FQDN-aware CNI (Cilium toFQDNs, Calico DNS policy). Each entry carries its intent class and rationale as comments so a reviewer or agent can see why the domain is permitted.

func RenderNetworkPolicy

func RenderNetworkPolicy(p NetworkPolicy) string

RenderNetworkPolicy renders a NetworkPolicy as a valid Kubernetes manifest. The default-deny form emits an empty egress list (which Kubernetes interprets as "deny all egress" for the selected pods).

Types

type Allowlist

type Allowlist struct {
	// FQDNs are permitted destination names; a leading "." or bare domain matches
	// subdomains too (".example.com" and "example.com" both match "a.example.com").
	FQDNs []string `json:"fqdns,omitempty"`
	// CIDRs are permitted destination IP ranges.
	CIDRs []string `json:"cidrs,omitempty"`
	// Ports restricts allowed destination ports; empty means any port.
	Ports []int `json:"ports,omitempty"`
	// AllowInternal permits all private-range (east-west) egress.
	AllowInternal bool `json:"allow_internal,omitempty"`
	// AllowDNS permits UDP/TCP 53 to any resolver (a pod must resolve names).
	AllowDNS bool `json:"allow_dns,omitempty"`
}

Allowlist is a candidate egress policy expressed as matchable rules. It is the JSON shape the `--dry-run` flag consumes and the shape AllowlistFromPolicy produces from a generated policy.

func AllowlistFromPolicy

func AllowlistFromPolicy(gp GeneratedPolicy) Allowlist

AllowlistFromPolicy derives the matchable allowlist implied by a generated policy: its FQDN entries, its ipBlock CIDRs, and DNS egress. Used to prove a generated policy against its own baseline.

func DecodeAllowlist

func DecodeAllowlist(r io.Reader) (Allowlist, error)

DecodeAllowlist parses a candidate Allowlist from JSON.

type DeniedFlow

type DeniedFlow struct {
	Workload string `json:"workload"`
	Dest     string `json:"dest"`
	IP       string `json:"ip,omitempty"`
	Port     uint16 `json:"port"`
	Count    int    `json:"count"`
	Reason   string `json:"reason"`
}

DeniedFlow is one destination a candidate policy would drop, aggregated over the connections to it.

type DryRunResult

type DryRunResult struct {
	AllowedDests int          `json:"allowed_dests"`
	DeniedDests  int          `json:"denied_dests"`
	Denied       []DeniedFlow `json:"denied"`
}

DryRunResult is the outcome of auditing a capture against a candidate policy.

func DryRun

func DryRun(c *netmon.Capture, a Allowlist) DryRunResult

DryRun replays a capture against a candidate allowlist and returns the would-be-denied destinations in deterministic order.

type EgressPeer

type EgressPeer struct {
	CIDR            string            `json:"cidr,omitempty"`
	NamespaceLabels map[string]string `json:"namespace_labels,omitempty"`
	PodLabels       map[string]string `json:"pod_labels,omitempty"`
	Ports           []Port            `json:"ports,omitempty"`
}

EgressPeer is one allowed destination in a generated NetworkPolicy: either an ipBlock CIDR (external IP) or a namespace/pod label selector (internal peer).

type FQDNEntry

type FQDNEntry struct {
	FQDN      string   `json:"fqdn"`
	Ports     []Port   `json:"ports,omitempty"`
	Class     string   `json:"class,omitempty"`     // intended | anomalous | observed
	Rationale []string `json:"rationale,omitempty"` // human+machine reasons
}

FQDNEntry is one domain on the DNS/FQDN egress allowlist, with the class and rationale from intent modelling so a reviewer/agent sees *why* it is allowed.

type GenOptions

type GenOptions struct {
	Namespace string
	// UseIntent, when set, restricts the allowlist to intended destinations and
	// records anomalous ones under Excluded. Off by default (mirrors netmon).
	UseIntent bool
	// Opts carries the netmon thresholds used for intent classification.
	Opts netmon.Options
}

GenOptions tunes generation.

type GeneratedPolicy

type GeneratedPolicy struct {
	Workload      string        `json:"workload"`
	Namespace     string        `json:"namespace"`
	Policy        NetworkPolicy `json:"policy"`
	DefaultDeny   NetworkPolicy `json:"default_deny"`
	FQDNAllowlist []FQDNEntry   `json:"fqdn_allowlist"`
	// Excluded lists destinations left OFF the allowlist because intent modelling
	// classed them anomalous — surfaced so the omission is explicit, not silent.
	Excluded []FQDNEntry `json:"excluded,omitempty"`
}

GeneratedPolicy bundles the artifacts produced for one workload.

func GenerateForCapture

func GenerateForCapture(c *netmon.Capture, g GenOptions) []GeneratedPolicy

GenerateForCapture generates artifacts for every workload with egress in the capture, in stable workload order.

func GeneratePolicy

func GeneratePolicy(fl *netmon.FlowLog, g GenOptions) GeneratedPolicy

GeneratePolicy synthesises the least-privilege artifacts for one workload's observed flow log.

type Module

type Module struct{}

Module is the network egress-analysis capability.

func New

func New() *Module

New returns a netpolicy module.

func (*Module) Analyze

func (m *Module) Analyze(_ context.Context, t *engine.Target) ([]engine.Finding, error)

Analyze loads the capture from the target, runs netmon detection, and projects anomalies plus network-posture observations onto findings. When the target is not a network capture it returns nothing so generic scans stay silent.

func (*Module) Description

func (m *Module) Description() string

func (*Module) Domains

func (m *Module) Domains() []string

func (*Module) Name

func (m *Module) Name() string

func (*Module) Supports

func (m *Module) Supports(t engine.TargetType) bool

Supports handles filesystem targets: the carrier for a recorded network capture (JSON). There is no dedicated "flow capture" target type yet — see NOTES.md for the proposed engine change. Until then a filesystem target whose content is a capture is analysed; anything that is not a capture yields no findings, so ordinary filesystem scans are unaffected.

type NetworkPolicy

type NetworkPolicy struct {
	Name        string            `json:"name"`
	Namespace   string            `json:"namespace"`
	PodSelector map[string]string `json:"pod_selector"`
	Egress      []EgressPeer      `json:"egress,omitempty"`
	DefaultDeny bool              `json:"default_deny"`
}

NetworkPolicy is a minimal, renderable Kubernetes NetworkPolicy. DefaultDeny marks the empty-egress "deny all" form.

type PolicyDiff

type PolicyDiff struct {
	Workload     string   `json:"workload,omitempty"`
	AddedFQDNs   []string `json:"added_fqdns,omitempty"`
	RemovedFQDNs []string `json:"removed_fqdns,omitempty"`
	AddedCIDRs   []string `json:"added_cidrs,omitempty"`
	RemovedCIDRs []string `json:"removed_cidrs,omitempty"`
}

PolicyDiff is the delta between a current and a generated allowlist. It is deliberately set-based (not a text diff) so it is stable and machine-appliable.

func DiffAllowlists

func DiffAllowlists(current, generated Allowlist) PolicyDiff

DiffAllowlists computes generated-minus-current: entries the generated policy adds (present in generated, absent in current) and removes (the reverse).

func (PolicyDiff) Empty

func (d PolicyDiff) Empty() bool

Empty reports whether the generated policy matches the current one exactly — the "nothing to do" signal an agent uses to skip opening a change.

func (PolicyDiff) Render

func (d PolicyDiff) Render() string

Render produces a human-readable, review-ready diff (+ widens, - tightens).

type Port

type Port struct {
	Protocol string `json:"protocol"` // TCP or UDP
	Port     int    `json:"port"`
}

Port is an L4 port/protocol pair in a generated rule.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL