firewall

package
v0.21.0 Latest Latest
Warning

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

Go to latest
Published: Jul 2, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package firewall implements the node-agnostic `solo-provisioner network firewall` scope: the `inet host` nftables table that protects the bare-metal host (SSH/mgmt allowlist, ICMP policy, in-cluster host-service ports).

It is a generic primitive — it knows nothing about block/consensus/mirror/ relay nodes. Orchestration (wiring create into `kube cluster install`, teardown into `kube cluster uninstall`) is owned by the host/cluster layer (#777 → #778/#791); this package only implements the verbs.

The `inet host` table is kept deliberately separate from `inet weaver` (the BN workload plane). The two tables have opposite lifecycles: `inet host` is set once and rarely changes, while `inet weaver` churns continuously as the daemon rewrites set elements.

Index

Constants

View Source
const (
	// TableName is the nftables table this package owns.
	TableName = "inet host"

	// HostNftPath is the on-disk artifact replayed at boot by the shared
	// solo-provisioner-network-nft.service oneshot (authored by #780). It lives
	// under /etc (host OS config on the root filesystem) — not /opt/solo/weaver,
	// which may be a late mount and would leave the firewall unloaded early at
	// boot.
	HostNftPath = "/etc/solo-provisioner/network-host.nft"

	// WeaverNftPath is the inet weaver artifact, owned by `block node install`
	// (TS_2 #743). This package never writes it; it only checks for its presence
	// to decide whether the shared oneshot may be disabled (teardown is #791).
	WeaverNftPath = "/etc/solo-provisioner/network-weaver.nft"

	// NetworkNftService is the oneshot unit that loads network-host.nft at boot
	// and is restarted on every live mutation so the kernel and the on-disk file
	// are always in sync. This package authors, installs, and enables the unit;
	// it never disables it — that is orchestrated by `kube cluster uninstall`
	// (#791). The unit is extended by #780 to also load network-weaver.nft.
	NetworkNftService = "solo-provisioner-network-nft.service"

	// NetworkNftServiceUnitPath is the absolute path where the unit file is
	// installed so systemd can discover it.
	NetworkNftServiceUnitPath = "/usr/lib/systemd/system/" + NetworkNftService

	// NftablesDropInDir is where the nftables.service drop-in is installed.
	// Drop-ins in /etc/systemd/system/ take precedence and survive package
	// upgrades of the nftables package itself.
	NftablesDropInDir = "/etc/systemd/system/nftables.service.d"

	// NftablesDropInPath is the drop-in file that makes nftables.service pull
	// in solo-provisioner-network-nft.service whenever it activates — so a
	// mid-run nftables flush (e.g. triggered by kube cluster install's preflight)
	// is always followed by a re-apply of our inet host rules.
	NftablesDropInPath = NftablesDropInDir + "/solo-provisioner.conf"

	// LockDir holds the cross-command apply lock. It lives on tmpfs (/run) so it
	// is auto-cleared on reboot and leaves nothing behind on uninstall.
	LockDir = "/run/solo-provisioner/network"

	// LockPath is the flock acquired (LOCK_EX) for the duration of any mutating
	// verb, so a hand-run operator command and the daemon poll loop (#754) can
	// never interleave nft transactions.
	LockPath = "/run/solo-provisioner/network/.applying"
)
View Source
const (
	DefaultSSHPort = 22
)

Default flag values per design §8.4.1.

Variables

View Source
var DefaultInClusterPorts = []int{6443, 4244, 7472, 10250}

DefaultInClusterPorts is the "stack set" of host-service ports opened to the in-cluster (pod) CIDR by default: the kube-apiserver (6443), the Cilium cluster-mesh / health port (4244), the kubelet read-only/metrics port (10250), and the MetalLB metrics/memberlist port (7472). Operators override with --in-cluster-ports.

Functions

This section is empty.

Types

type Config

type Config struct {
	Runner          Runner
	NftPath         string
	LockPath        string
	ApplyViaService func(ctx context.Context) error
}

Config customises a Manager. The zero value is not useful; prefer NewManager. Tests inject a fake Runner, temp paths, and a no-op service func so the package builds and runs on any platform.

type Manager

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

Manager implements the `network firewall` verbs against the `inet host` table. Every mutating verb takes the shared apply lock, atomically rewrites the on-disk artifact, and then restarts the systemd service via DBus so the kernel is updated in one consistent operation — no separate nft apply exec.

func NewManager

func NewManager() *Manager

NewManager returns a Manager wired to the live kernel and the production paths.

func NewManagerWithConfig

func NewManagerWithConfig(cfg Config) *Manager

NewManagerWithConfig returns a Manager, filling any unset Config field with its production default.

func (*Manager) AddMgmtCIDR

func (m *Manager) AddMgmtCIDR(ctx context.Context, cidr string) error

AddMgmtCIDR adds one CIDR to the management allowlist and re-renders.

func (*Manager) AddPort

func (m *Manager) AddPort(ctx context.Context, port int) error

AddPort adds one in-cluster host-service port and re-renders.

func (*Manager) Create

func (m *Manager) Create(ctx context.Context, t *Table, force bool) (bool, error)

Create is create-if-missing: when the table already exists and force is false, it makes no changes and returns (false, nil). force re-renders the table from the supplied flags and returns (true, nil).

func (*Manager) Delete

func (m *Manager) Delete(ctx context.Context) error

Delete removes the inet host table and its on-disk artifact. It is idempotent. It deliberately does NOT disable the shared solo-provisioner-network-nft.service (shared with inet weaver) — that is orchestrated by `kube cluster uninstall` (#791).

func (*Manager) RemoveMgmtCIDR

func (m *Manager) RemoveMgmtCIDR(ctx context.Context, cidr string) error

RemoveMgmtCIDR removes one CIDR from the management allowlist and re-renders.

func (*Manager) RemovePort

func (m *Manager) RemovePort(ctx context.Context, port int) error

RemovePort removes one in-cluster host-service port and re-renders.

func (*Manager) Set

func (m *Manager) Set(ctx context.Context, mgmtCIDRs []string, ports []int) error

Set atomically replaces the management CIDR list and/or the in-cluster port list. A nil slice leaves that dimension unchanged; an empty (non-nil) slice clears it.

func (*Manager) Show

func (m *Manager) Show(ctx context.Context) (string, error)

Show returns the live inet host table. If the table is not active it returns a human-readable message (not an error) so the caller can print it cleanly.

type Runner

type Runner interface {
	// List returns the rendered ruleset for the inet host table
	// (`nft list table inet host`).
	List(ctx context.Context) (string, error)
	// Delete removes the inet host table (`nft delete table inet host`).
	Delete(ctx context.Context) error
	// Exists reports whether the inet host table is present in the kernel.
	Exists(ctx context.Context) (bool, error)
}

Runner is the seam over the system `nft` binary for read and delete operations. Live rule application is done by writing the on-disk artifact and restarting the systemd service via DBus — so Apply is not part of this interface. Tests substitute a fake so the package builds and unit-tests on any platform (including macOS) without touching the kernel.

func NewExecRunner

func NewExecRunner() Runner

NewExecRunner resolves the nft binary path and returns a Runner that applies changes to the live kernel.

type Table

type Table struct {
	// MgmtCIDRs is the management/SSH allowlist (set @mgmt_addrs).
	MgmtCIDRs []string
	// InClusterPorts are host-service ports reachable from PodCIDR (set
	// @in_cluster_ports). Per design there is deliberately no --service-ports:
	// BN ports live only in `network policy --ports`.
	InClusterPorts []int
	// SSHPort is the TCP port accepted from @mgmt_addrs for management access.
	SSHPort int
	// PodCIDR is the source range allowed to reach @in_cluster_ports. Empty
	// means no in-cluster port rule is rendered.
	PodCIDR string
}

Table is the in-memory model of the `inet host` nftables table. It is the single source of truth that both the kernel apply (via `nft -f`) and the on-disk artifact are rendered from, so the two can never diverge.

func NewTable

func NewTable() *Table

NewTable returns a Table populated with the design defaults. Callers override fields from CLI flags before rendering.

func Parse

func Parse(content string) (*Table, error)

Parse reconstructs a Table from the on-disk network-host.nft artifact. It understands only the exact format this package renders (see the embedded template) — it is not a general nft parser. A render→parse→render round-trip is the identity, which is pinned by TestRoundTrip. Element verbs (add/remove/ set) use this to load prior state so they don't need the full flag set re-spec.

func (*Table) AddMgmtCIDR

func (t *Table) AddMgmtCIDR(cidr string) error

AddMgmtCIDR adds a single CIDR to the management allowlist (idempotent).

func (*Table) AddPort

func (t *Table) AddPort(port int) error

AddPort adds a single in-cluster host-service port (idempotent).

func (*Table) RemoveMgmtCIDR

func (t *Table) RemoveMgmtCIDR(cidr string)

RemoveMgmtCIDR removes a single CIDR from the management allowlist (idempotent; removing an absent CIDR is a no-op).

func (*Table) RemovePort

func (t *Table) RemovePort(port int)

RemovePort removes a single in-cluster host-service port (idempotent).

func (*Table) Render

func (t *Table) Render() (string, error)

Render produces the full `inet host` nft document for this table. The same output feeds both the kernel apply (`nft -f`) and the on-disk artifact, so the live table and the persisted file can never diverge.

func (*Table) SetMgmtCIDRs

func (t *Table) SetMgmtCIDRs(cidrs []string) error

SetMgmtCIDRs atomically replaces the full management allowlist.

func (*Table) SetPorts

func (t *Table) SetPorts(ports []int) error

SetPorts atomically replaces the full in-cluster host-service port list.

func (*Table) Validate

func (t *Table) Validate() error

Validate rejects any field that would be unsafe to render into the nft ruleset. It is the last gate before the renderer; every untrusted value (CIDRs, ports) is checked through pkg/sanity so a malformed token can never break the atomic transaction or smuggle in nft syntax.

Jump to

Keyboard shortcuts

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