config

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 29, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package config reads the edge's config. It comes in four parts, and each has one owner:

fortress.yml    baked into the ISO by fortressctl bake: what the edge
                trusts and how it runs. A new ISO changes it.
user-data       the NoCloud drive: fqdn, the edge's DNS name. Nothing
                else in it is read.
network-config  the NoCloud drive: the static address.
policy.yml      the /var disk, from fortressctl apply: who may reach the
                edge and how much. It changes while the edge runs.

None of them holds a secret.

Index

Constants

View Source
const (
	FrpsBindAddr     = "127.0.0.1"
	FrpsTCPPort      = 7000 // dark-node control (wss)
	FrpsQUICPort     = 443  // dark-node QUIC on the public UDP port; TCP control stays on loopback
	FrpWebsocketPath = "/~!frp"

	// Operator API, served on the tunnel SNI (mTLS already enforced there).
	OpsPathPrefix = "/~!ops/"
	OpsLogsPath   = OpsPathPrefix + "logs"
	OpsAccessPath = OpsPathPrefix + "access"
	OpsStatusPath = OpsPathPrefix + "status"
	// OpsPolicyPath reads the policy (GET) and replaces it (PUT).
	OpsPolicyPath = OpsPathPrefix + "policy"
)

frps listens on loopback for dark-node control, which the edge reaches in-process. QUIC, when enabled, binds FrpsQUICPort on the public address instead.

View Source
const (
	DefaultNTP = "pool.ntp.org"
	// DefaultRenewInterval is how often ACME certificates are checked for
	// renewal when fortress.yml sets no renew_interval.
	DefaultRenewInterval = 4 * time.Hour
	// The access log's defaults keep it at 24 MiB, well inside a 64 MiB
	// data disk.
	DefaultAccessLogMaxSize  = 8 << 20
	DefaultAccessLogMaxFiles = 3

	// EdgeFile is the baked config, at BakedFile in the initramfs.
	EdgeFile  = "fortress.yml"
	BakedFile = "/etc/fortressedge/" + EdgeFile
	// PolicyName is the runtime config, stored at PolicyFile.
	PolicyName = "policy.yml"

	// The persistent disk mounts at /var; state and logs live there.
	DataDir    = "/var/fortressedge"
	PolicyFile = DataDir + "/" + PolicyName
	CertsDir   = DataDir + "/certs"
	// RunClientCA holds the fortress.yml client_ca for this boot, for frps,
	// which reads its trust anchor from a file. The edge holds no CA key.
	RunClientCA = "/run/fortressedge/client_ca.crt"
	LogDir      = "/var/log/fortressedge"
	LogFile     = LogDir + "/current.log"
	// AccessLogDir holds the access log (access_log: true), one JSON line
	// per site request, apart from the edge's own log.
	AccessLogDir = LogDir + "/access"
)

Variables

This section is empty.

Functions

func CheckEdge

func CheckEdge(edge []byte) error

CheckEdge validates fortress.yml on its own, as fortressctl bake does before it puts the file into an ISO.

func ControlAddr

func ControlAddr() string

func EdgeKeys added in v0.2.0

func EdgeKeys() []string

EdgeKeys lists the keys fortress.yml takes.

func PolicyETag

func PolicyETag(policy []byte) string

PolicyETag names a policy.yml body: its SHA-256, quoted as an HTTP entity tag. The ops API sends it with the policy; fortressctl diff compares it with the file in git.

Types

type Config

type Config struct {
	Iface   string
	Addr    netip.Prefix // static address of Iface, with prefix length
	Gateway netip.Addr
	DNS     []netip.Addr
	Tunnel  string // the fqdn: SNI dark nodes and operators connect to
	// Disk is the device boot mounted at /var; not part of the config.
	Disk string
	NTP  string
	ACME string // ACME directory URL; empty is Let's Encrypt
	// ACMECA is the PEM trust anchor for the directory's TLS certificate.
	// Empty uses the system roots. Set, it is the only pool the ACME client trusts.
	ACMECA []byte
	// RenewInterval is how often every ACME certificate is checked, and
	// renewed once it is due (the last third of its life, or when the CA
	// says so through ARI).
	RenewInterval time.Duration
	QUIC          bool // dark-node QUIC on UDP 443
	// AccessLog writes one line per site request to AccessLogDir, in
	// files of up to AccessLogMaxSize bytes, keeping AccessLogMaxFiles.
	AccessLog         bool
	AccessLogMaxSize  int64
	AccessLogMaxFiles int
	// ClientCA is the PEM trust anchor from fortress.yml (client_ca) for
	// dark-node, operator, and log-reader certificates.
	ClientCA []byte
	// ClientCAPath is the file listeners load this boot. Set after boot
	// resolves client_ca; not part of fortress.yml.
	ClientCAPath string
	Policy
}

func Parse

func Parse(userData, networkConfig, edge, policy []byte) (Config, error)

Parse reads the four parts. policy may be nil: an edge nobody has applied a policy to yet runs the defaults (no block list, DefaultLimits).

type InvalidError

type InvalidError struct{ Err error }

InvalidError is a config that parsed but is not acceptable. Callers map it to HTTP 400; other errors are failures to store or apply.

func (*InvalidError) Error

func (e *InvalidError) Error() string

func (*InvalidError) Unwrap

func (e *InvalidError) Unwrap() error

type Limits

type Limits struct {
	ConnsPerSource    int           // open connections
	RequestsPerSecond int           // sustained
	RequestBurst      int           // at once
	NewConnsPerSecond int           // TCP SYNs, dropped in XDP
	NewConnBurst      int           // SYNs at once
	Ban               time.Duration // XDP ban for a source that keeps being refused; 0 never bans
	BanAfter          int           // refusals within BanWindow that earn a ban
	BanWindow         time.Duration
	MaxConns          int   // all sources, per port; 0 sizes it from memory
	MaxHeaderBytes    int   // request line and headers
	MaxURIBytes       int   // request target
	MaxBodyBytes      int64 // request body; 0: no limit
	MaxHTTP2Streams   int   // concurrent streams per HTTP/2 connection
	// ResponseHeaderTimeout is how long a request waits for the origin's
	// response headers; a stream that sends them with its first event
	// (server-sent events, long polling) is cut after it. Whole seconds.
	ResponseHeaderTimeout time.Duration
}

Limits protect the edge from one source (an IPv4 address or an IPv6 /64). A rate or count of 0 turns that limit off.

func DefaultLimits

func DefaultLimits() Limits

DefaultLimits are generous: many people can share one IPv4 address.

func (Limits) BootLimits

func (l Limits) BootLimits() Limits

BootLimits are the limits the HTTP servers, listeners, and frps fix when they start; a change to any of them reboots. The rest apply at once.

type Policy

type Policy struct {
	Block []netip.Prefix // XDP drop list; host or CIDR
	// Exempt are sources the per-address limits and bans skip: a load
	// generator, a monitoring probe, an office behind one address.
	Exempt []netip.Prefix
	Limits Limits
}

Policy is policy.yml: what the edge lets through. It is the part an operator changes while the edge runs.

func ParsePolicy

func ParsePolicy(b []byte) (Policy, error)

ParsePolicy reads policy.yml. Empty is the defaults.

func (Policy) RebootFrom

func (p Policy) RebootFrom(cur Policy) bool

RebootFrom reports whether moving from cur to p needs a reboot: only the limits the servers fix when they start do.

Jump to

Keyboard shortcuts

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