ownappfirewall

package
v0.57.11 Latest Latest
Warning

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

Go to latest
Published: Nov 13, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Overview

Package ownappfirewall owns the closed network authorization boundary for own-application v2. It never changes the host's general firewall or Docker tables.

Index

Constants

View Source
const EgressMaxAge = 90 * time.Second
View Source
const EgressRefresh = 30 * time.Second
View Source
const EgressSet = "household_egress_v4"

Rules exist before the bridge or container. Inet prerouting runs after conntrack but before DNAT; forward repeats destination checks after DNAT. Bridge filtering covers same-bridge peers without depending on br_netfilter. Only conntrack replies to admitted inbound requests may return to a private peer. The application cannot initiate even a connection to its ingress router.

View Source
const HostSettleTime = 5 * time.Minute

HostSettleTime is how long after the kernel boot a host-facts mismatch is still retried: interfaces and routes that come up late must not stop the application for good.

View Source
const MinimumSystemd = 244

MinimumSystemd is the oldest systemd that accepts Restart=on-failure on a Type=oneshot unit (systemd 244).

View Source
const Owner = "stackkit.own-egress/v1"
View Source
const RestorePermanentExit = 78

RestorePermanentExit is the restore unit's exit status for a refusal that a retry cannot change: the rule definition or the signed record differ from the snapshot, or the host's network facts still differ once the boot has settled. The unit names it in RestartPreventExitStatus, so systemd stops retrying; the application stays stopped until a reviewed update or start. 78 is EX_CONFIG.

View Source
const RestoreTimeout = 150 * time.Second

RestoreTimeout bounds one restore attempt. It leaves margin over the watcher's 20 second notify wait plus discovery, apply and verification.

View Source
const WatchInterval = 3 * time.Second

Variables

This section is empty.

Functions

func Bridge

func Bridge(network string) string

func DefinitionDigest

func DefinitionDigest() string

DefinitionDigest binds the rule compiler, registry data, dynamic host exclusion contract and restart policy to review and signed receipts. Changing enforcement requires changing this definition, and invalidates older reviews.

func MAC

func MAC(network string) string

func Remove

func Remove(ctx context.Context, network string) error

Remove needs no current uplink: a disconnected host must still be removable.

func RestoreExitCode

func RestoreExitCode(err error) int

RestoreExitCode maps a RestoreMain result to the unit's exit status.

func RestoreMain

func RestoreMain(path string, reviewed func(workspace, network string) (Receipt, error)) (err error)

RestoreMain is the restore unit's only action. Once a start completed in the running boot it does nothing: the reviewed lifecycle owns that boot, and a flushed or changed table is never silently reinstalled. Otherwise it loads the signed reviewed receipt, observes the host again and requires the exact reviewed static ruleset, observes a fresh egress answer, applies the same rules and requires the reviewed receipt, checks the bridge, and only then delegates the start to the watcher. Any failure leaves the application stopped. systemd retries, except after a PermanentRefusal (RestoreExitCode maps it to RestorePermanentExit). An ingress-only policy observes no host facts and needs no egress echo, so it also restores on an offline host.

func RestoreUnit

func RestoreUnit(network string) string

RestoreUnit is the persistent, enabled unit that brings the application back after a host reboot: it re-applies the exact reviewed ruleset and then hands the start to the watcher. It never starts the container itself.

func RestoreUnitFile

func RestoreUnitFile(network, executable string) (string, error)

RestoreUnitFile renders the boot-time unit. A failed attempt is retried 30 seconds after it ends, without limit, unless it exits with RestorePermanentExit; every attempt re-verifies everything, so a retry never starts the application without its rules. Restart= on a oneshot unit needs systemd 244 or newer (installRestore checks it).

func Resume

func Resume(ctx context.Context, network, id, reviewedDigest string) error

Resume never reapplies rules or adopts fresh host facts. Backup recovery must use the exact reviewed apply snapshot and a still-fresh echo.

func Run

func Run(ctx context.Context, name string, args []string, input []byte) ([]byte, error)

func StopWatcher

func StopWatcher(ctx context.Context, network string, remove bool) error

StopWatcher ends the application's lifetime custody: it first disables (and stops a running attempt of) the boot-time restore, so a stopped application stays stopped across a reboot, then stops the live watcher, whose ExecStopPost kills the container. remove also deletes the restore unit and both snapshots.

func Table

func Table(network string) string

func VerifyRunning

func VerifyRunning(ctx context.Context, network, id, reviewedDigest string) (err error)

func WatchDecision

func WatchDecision(verify error, egressAt, now time.Time) error

WatchDecision is the fail-closed lifetime decision, independent of event transport. Missing tables, rule changes, extra networks and stale echoes all terminate the unit and hence trigger systemd's exact-container kill.

func WatchMain

func WatchMain(path string) error

func WatchUnit

func WatchUnit(network string) string

Types

type Guard

type Guard struct {
	Policy Policy
	// contains filtered or unexported fields
}

func New

func New(ctx context.Context, network string, outbound bool) (*Guard, error)

New observes the host for the static policy of a firewalled application. Without outbound Internet the policy is ingress-only and needs no host facts: no uplink, gateway or route inventory, so a disconnected host can still run an application that only publishes ports.

func (*Guard) Apply

func (g *Guard) Apply(ctx context.Context) (Receipt, error)

func (*Guard) ObserveEgress

func (g *Guard) ObserveEgress(ctx context.Context, workspace string) error

ObserveEgress uses only the installation's already-configured Me origin. No registration, no echo route, or an unusable answer means no grant. The source-bound direct IPv4 transport excludes proxies and another uplink. The ingress-only policy grants no destination, so it needs no echo: only the workspace is recorded for the watcher and the boot-time restore.

func (*Guard) Remove

func (g *Guard) Remove(ctx context.Context) error

func (*Guard) StartWatcher

func (g *Guard) StartWatcher(ctx context.Context, id string) error

StartWatcher delegates the ONLY start to the kit unit. systemd waits for READY after initial verification and start; ExecStopPost kills the exact ID even when the watcher is killed, crashes or fails during startup.

func (*Guard) Verify

func (g *Guard) Verify(ctx context.Context) error

func (*Guard) VerifyBridge

func (g *Guard) VerifyBridge() error

VerifyBridge refuses rootless/remote daemon namespaces: rules in this host namespace cannot authorize a bridge that exists only inside another one. It is called after stopped container/network creation, before any start.

func (*Guard) VerifyWatcher

func (g *Guard) VerifyWatcher(ctx context.Context) error

type PermanentRefusal

type PermanentRefusal struct{ Err error }

PermanentRefusal marks a restore refusal that no retry can change.

func (PermanentRefusal) Error

func (p PermanentRefusal) Error() string

func (PermanentRefusal) Unwrap

func (p PermanentRefusal) Unwrap() error

type Policy

type Policy struct {
	Network      string   `json:"network"`
	IngressOnly  bool     `json:"ingressOnly,omitempty"`
	HomePrefixes []string `json:"homePrefixes"`
	Gateway      string   `json:"gateway"`
	Uplink       string   `json:"uplink"`
	UplinkSource string   `json:"uplinkSource"`
	NextHops     []string `json:"nextHops"`
}

Policy is the static ruleset of one firewalled own application. A firewalled application has outbound Internet, published host ports, or both. IngressOnly is the variant without outbound Internet: the container may only answer connections made to it (its published ports and its router), so it needs no uplink, gateway, egress echo or host facts at all.

func IngressPolicy

func IngressPolicy(network string) Policy

IngressPolicy is the complete static policy of a firewalled application without outbound Internet. It depends on the network name only.

func (Policy) AllowsDestination

func (p Policy) AllowsDestination(addr netip.Addr) bool

AllowsDestination is the address portion of the policy. IPv6 is deliberately denied entirely; IPv4-mapped IPv6 is not unwrapped into an IPv4 permission. The ingress-only variant allows no destination at all.

func (Policy) Digest

func (p Policy) Digest() string

func (Policy) Script

func (p Policy) Script() string

type Receipt

type Receipt struct {
	PolicyDigest  string   `json:"policyDigest"`
	RulesetDigest string   `json:"rulesetDigest"`
	Network       string   `json:"network"`
	Tables        []string `json:"tables"`
	IPv6          string   `json:"ipv6"`
	DynamicSets   []string `json:"dynamicSets,omitempty"`
}

type Runner

type Runner func(context.Context, string, []string, []byte) ([]byte, error)

type SpecialUse

type SpecialUse struct {
	Prefix   string `json:"prefix"`
	Name     string `json:"name"`
	Registry string `json:"registry"`
}

func SpecialRanges

func SpecialRanges() []SpecialUse

Jump to

Keyboard shortcuts

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