Documentation
¶
Overview ¶
Package egress implements the forward proxy that constrains sandbox network traffic. Sandboxes are pointed at it via HTTP(S)_PROXY, and it only permits connections allowed by a Policy. Stdlib only.
Index ¶
Constants ¶
const ( // StrictProxyUID is the uid the transparent proxy runs as; iptables // exempts it so the proxy's upstream traffic isn't redirected back to // itself. The sandbox must run as a different uid to be intercepted. StrictProxyUID = 1337 // StrictRedirectPort is the proxy's listen port and the iptables REDIRECT target. StrictRedirectPort = 15001 )
Constants shared between the Kubernetes backend and the runeward-egress binary for strict (L3) enforcement.
Variables ¶
This section is empty.
Functions ¶
func ExtractSNI ¶
ExtractSNI parses the SNI host from a TLS ClientHello, returning "" and false if data isn't a ClientHello or has no SNI extension. The transparent proxy uses it to recover the hostname when only the destination IP is known.
func RecordDecision ¶
RecordDecision appends one decision to the per-sandbox bounded in-memory log.
func SetupRedirect ¶
SetupRedirect installs iptables rules that redirect outbound TCP to the transparent proxy on redirectPort, exempting the proxy's own uid, loopback, and DNS. Runs once from a privileged init container before the sandbox starts. Enforcement happens in the kernel, so an app can't opt out by ignoring HTTP(S)_PROXY.
Beyond TCP redirect it also closes two bypass paths the proxy can't see:
- non-DNS UDP is dropped, so QUIC/HTTP3 (443/udp) can't tunnel around the TCP-only proxy — clients fall back to TCP, which is proxied.
- IPv6 egress is dropped (except loopback and DNS), since the proxy is IPv4-only; this forces traffic onto the proxied IPv4 path.
Types ¶
type Decision ¶
type Decision struct {
Timestamp time.Time `json:"timestamp"`
Host string `json:"host"`
IP string `json:"ip"`
Allow bool `json:"allow"`
Reason string `json:"reason"`
}
Decision is one recorded egress allow/deny outcome for dashboard inspection.
func ListDecisions ¶
ListDecisions returns the current per-sandbox decision log, oldest to newest.
type PinnedTransport ¶
PinnedTransport wraps base and forces dials to outReq.URL.Host (already pinned). It keeps TLS ServerName from request context when provided.
type Policy ¶
type Policy struct {
// Default is "allow" or "deny"; empty means "allow".
Default string `json:"default"`
Rules []Rule `json:"rules"`
}
Policy is an ordered list of [Rule]s; the first match wins, otherwise Default applies.
func LoadPolicy ¶
LoadPolicy reads and decodes a JSON Policy from the file at path.
func (Policy) Allow ¶
Allow reports whether host is permitted. Only Hostname rules are considered; first match decides, otherwise Default applies.
func (Policy) AllowAddr ¶
AllowAddr reports whether the destination "host:port" is permitted. The host is checked against Hostname rules, and against CIDR rules when it parses as an IP; first match decides, otherwise Default applies.
func (Policy) AllowListedHostname ¶
AllowListedHostname reports whether host matches an explicit hostname rule whose first matching verdict is allow. Unlike [Allow], it does not fall back to the policy default.
type Proxy ¶
type Proxy struct {
Policy Policy
// SandboxID associates decisions with a sandbox for dashboard egress logs.
SandboxID string
// Logger receives allow/deny decisions; nil discards them.
Logger *log.Logger
// AuthUser/AuthPass, when both set, require Proxy-Authorization (HTTP Basic)
// on every request. This keeps a proxy bound on a shared interface (e.g. the
// host proxy reachable via host.docker.internal) from being used by other
// local/LAN processes.
AuthUser string
AuthPass string
// contains filtered or unexported fields
}
Proxy is a forward proxy that enforces Policy on CONNECT tunnels (HTTPS) and plain absolute-URI HTTP requests.
func (*Proxy) Handler ¶
Handler returns an http.Handler implementing the forward proxy.
func (*Proxy) ListenAndServe ¶
ListenAndServe serves the proxy handler on addr until an error occurs.
type Rule ¶
type Rule struct {
// Verdict is "allow" or "deny"; anything but "allow" denies.
Verdict string `json:"verdict"`
// Hostname matches exactly or by a leading "*." wildcard.
Hostname string `json:"hostname"`
// CIDR matches a destination IP (e.g. "10.0.0.0/8").
CIDR string `json:"cidr"`
}
Rule is a single allow/deny entry in a Policy. Set exactly one of Hostname or CIDR.
type TransparentProxy ¶
type TransparentProxy struct {
Policy Policy
// SandboxID associates decisions with a sandbox for dashboard egress logs.
SandboxID string
// Logger receives allow/deny decisions; nil discards them.
Logger *log.Logger
}
TransparentProxy enforces a Policy on connections redirected to it by iptables. Unlike Proxy it needs no HTTP(S)_PROXY cooperation: the original destination comes from SO_ORIGINAL_DST and the hostname is sniffed from TLS SNI or the HTTP Host header. Linux-only.
func (*TransparentProxy) Serve ¶
func (t *TransparentProxy) Serve(addr string) error
Serve handles redirected connections on addr until an accept error occurs.