egress

package
v0.40.0 Latest Latest
Warning

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

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

Documentation

Overview

Package egress is the transparent egress PEP (ADR-0117, FEAT-0007/F81): the enforcement point F80's nftables substrate REDIRECTs remaining external worker TCP into. Per redirected connection the Linux driver recovers the pre-DNAT destination (SO_ORIGINAL_DST), authenticates the caller by source IP via the WorkerIndex, builds the FORWARDER-ATTESTED destination (the B1 invariant — client SNI/Host is never the authorization basis), asks the auth.Authorizer PDP whether that worker's principal (its Function or Lake) may egress::connect to that NetDestination, and splices on ALLOW / refuses on DENY — auditing every connection. It is default-deny, fail-closed, opt-in (server.network.egress), and Linux/containerd only. Disabled or on a non-Linux host New returns a no-op Gateway and worker egress stays open exactly as before. The SNI/Host parsers, the forwarder-attested destination build, and the decision flow are pure + unit-tested cross-platform; the SO_ORIGINAL_DST recovery, conn peek/replay, and splice are the Linux driver (Lima e2e verifies behavior).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AuditRecord

type AuditRecord struct {
	Namespace, Function, Domain string
	IP                          netip.Addr
	Port                        uint16
	Allowed                     bool
	Reason                      string
}

AuditRecord is one egress decision (allowed or blocked).

type AuditSink

type AuditSink interface {
	Egress(ctx context.Context, rec AuditRecord)
}

AuditSink records one egress decision to the funclog audit channel.

type Deps

type Deps struct {
	GatewayPort uint16          // F80's REDIRECT target (server.network.egressGatewayPort)
	Workers     WorkerIndex     // src-IP → caller Ref (containerd runtime populates it, §5)
	DNS         DomainResolver  // forwarder-attested (worker, dst-IP) → domains (the trust anchor)
	Authz       auth.Authorizer // the PDP (egress::connect over a NetDestination)
	Audit       AuditSink       // every connection (allowed + blocked) → the funclog channel
	Logger      *slog.Logger    // nil ⇒ slog.Default()
	// NodeAddrs reads the addresses on the node's interfaces, which a domain rule never reaches (ADR-0315); nil reads them
	// from the host.
	NodeAddrs func() ([]netip.Addr, error)
}

Deps wires the gateway. On a non-Linux host or when disabled, New returns a no-op Gateway.

type DomainResolver

type DomainResolver interface {
	DomainsFor(src netip.Addr, dst netip.Addr) []string
}

DomainResolver returns the domains THIS worker resolved to dst via the funcd forwarder — the authoritative domain→IP binding (never client SNI/Host). It includes any namespace wildcard pattern token an attested FQDN matched (so wildcard rules stay exact set-membership). Empty ⇒ only a CIDR rule can permit dst.

type DomainRules added in v0.38.0

type DomainRules interface {
	For(ctx context.Context, principal auth.EntityRef) ([]string, error)
}

DomainRules supplies the domain rules (exact names and "*." wildcards) of the EgressPolicies that apply to a worker's principal: who they cover is what the PDP grants (ADR-0315). An error means they could not be read, and the lookup is refused.

type Forwarder

type Forwarder interface {
	Serve(ctx context.Context) error
	DomainResolver
}

Forwarder is the ONLY resolver a worker can reach (F80 redirects worker :53 into it). It answers known workers only and forwards to the node resolver only the names a domain rule of an EgressPolicy that applies to them allows; anything else gets REFUSED and nothing goes upstream (ADR-0315). It records (src, question's name)→resolved-IP set, exposing the reverse DomainsFor the gateway uses to authorize domain rules, with a matched wildcard token. It satisfies DomainResolver. Serve blocks until ctx is cancelled.

func NewForwarder

func NewForwarder(listen, upstream netip.AddrPort, workers WorkerIndex, rules DomainRules, logger *slog.Logger) Forwarder

NewForwarder builds the forwarder over the node resolver (github.com/miekg/dns; BSD-3-Clause), listening on the bridge address. The correlation map keys on the DNS client's source IP so a worker only inherits the domains IT resolved. workers maps that source IP → its principal and rules supplies that principal's domain rules, so a resolved FQDN also records any "*.x.com" it matched (keeping wildcard authorization an exact set-membership check over a forwarder-derived token). A nil workers or rules knows no source or no rule, so every query is refused; a nil logger means slog.Default().

type Gateway

type Gateway interface {
	Serve(ctx context.Context) error
	Close() error
}

Gateway is the transparent egress PEP: it accepts F80-redirected worker connections on GatewayPort, recovers the original destination, identifies the caller, asks the PDP, and splices or refuses — auditing every connection. Serve blocks until ctx is cancelled or Close is called.

func New

func New(enabled bool, d Deps) Gateway

New returns the Linux driver when enabled on Linux, else a no-op (build-tagged newGateway() dispatch, mirroring internal/network's nftables_linux.go / _other.go split).

type MemoryWorkerIndex

type MemoryWorkerIndex struct {
	// contains filtered or unexported fields
}

MemoryWorkerIndex is the in-memory WorkerIndex (ADR-0117, §5) the containerd runtime populates at worker provisioning: on worker-up it records the assigned funcd0 IP → the worker's principal Ref (its owner kind); on worker-down it removes it. The gateway reads it to authenticate the caller by source IP (never client-asserted). Concurrency-safe.

func NewMemoryWorkerIndex

func NewMemoryWorkerIndex() *MemoryWorkerIndex

NewMemoryWorkerIndex returns an empty index.

func (*MemoryWorkerIndex) Add

func (w *MemoryWorkerIndex) Add(ip netip.Addr, ref auth.EntityRef)

Add records a worker's funcd0 source IP → its principal Ref (worker-up).

func (*MemoryWorkerIndex) Lookup

func (w *MemoryWorkerIndex) Lookup(ip netip.Addr) (auth.EntityRef, bool)

Lookup resolves a source IP to its principal Ref; ok==false ⇒ unknown worker (the gateway denies+audits).

func (*MemoryWorkerIndex) Remove

func (w *MemoryWorkerIndex) Remove(ip netip.Addr)

Remove drops a worker's IP mapping (worker-down); safe if absent.

type WorkerIndex

type WorkerIndex interface {
	Lookup(ip netip.Addr) (ref auth.EntityRef, ok bool)
}

WorkerIndex resolves a worker's funcd0 source IP to the principal Ref of its owner kind (a Function or a Lake).

Jump to

Keyboard shortcuts

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