Files
tomswallapi/internal/database/migrations/0001_init.sql
T
2026-07-19 13:31:14 +10:00

96 lines
3.9 KiB
SQL

-- Initial tomswallapi schema: fleet-global objects + per-device layer.
-- See DESIGN.md (tomswall repo) for the model this implements.
-- Global settings: a single row of fleet-wide defaults.
CREATE TABLE settings (
id BOOLEAN PRIMARY KEY DEFAULT true CHECK (id), -- singleton
address_family TEXT NOT NULL DEFAULT 'inet',
log_level TEXT NOT NULL DEFAULT 'info',
ip_forwarding BOOLEAN NOT NULL DEFAULT true,
table_name TEXT NOT NULL DEFAULT 'tomswall',
default_resolver JSONB NOT NULL DEFAULT '[]'::jsonb -- ["10.0.0.53"] or "system"
);
INSERT INTO settings (id) VALUES (true);
-- Routing domains. enforce_on_routers toggles defense-in-depth vs transparent transit.
CREATE TABLE fabrics (
name TEXT PRIMARY KEY,
enforce_on_routers BOOLEAN NOT NULL DEFAULT false,
description TEXT NOT NULL DEFAULT ''
);
-- Fleet-global zones. subnets is a list of CIDRs. parent gives subzone nesting.
CREATE TABLE zones (
name TEXT PRIMARY KEY,
type TEXT NOT NULL DEFAULT 'ip', -- ip | ip6 | firewall
subnets JSONB NOT NULL DEFAULT '[]'::jsonb,
parent TEXT REFERENCES zones(name) ON DELETE RESTRICT
);
-- Address groups materialize nftables named sets. type drives population source.
CREATE TABLE address_groups (
name TEXT PRIMARY KEY,
type TEXT NOT NULL CHECK (type IN ('static', 'dns', 'asn')),
members JSONB NOT NULL DEFAULT '[]'::jsonb, -- static: CIDRs; dns: FQDNs; asn: ASN numbers
refresh TEXT NOT NULL DEFAULT '', -- asn: cache TTL (e.g. 24h); dns: honor_ttl
description TEXT NOT NULL DEFAULT ''
);
-- Reusable port+proto combos.
CREATE TABLE portgroups (
name TEXT PRIMARY KEY,
proto TEXT NOT NULL,
ports JSONB NOT NULL DEFAULT '[]'::jsonb
);
-- Default zone-to-zone policies. priority orders evaluation (first match wins).
CREATE TABLE policies (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
priority INT NOT NULL DEFAULT 0,
source TEXT NOT NULL,
dest TEXT NOT NULL,
action TEXT NOT NULL,
log TEXT NOT NULL DEFAULT ''
);
-- Fleet-global intents. source/dest use the shorewall-style element list
-- (bare zone, or zone:+ipset / zone:&fqdn). Stored as JSONB element arrays.
CREATE TABLE rules (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
priority INT NOT NULL DEFAULT 0,
action TEXT NOT NULL,
source JSONB NOT NULL DEFAULT '[]'::jsonb, -- ["loc", "net:+asn_cloudflare"]
dest JSONB NOT NULL DEFAULT '[]'::jsonb,
proto TEXT NOT NULL DEFAULT '',
portgroup TEXT REFERENCES portgroups(name) ON DELETE RESTRICT,
ports JSONB NOT NULL DEFAULT '[]'::jsonb,
log TEXT NOT NULL DEFAULT '',
comment TEXT NOT NULL DEFAULT ''
);
-- Devices in the fleet.
CREATE TABLE devices (
name TEXT PRIMARY KEY,
class TEXT NOT NULL CHECK (class IN ('router', 'firewall')),
fabric TEXT REFERENCES fabrics(name) ON DELETE SET NULL,
resolver JSONB NOT NULL DEFAULT '[]'::jsonb, -- per-device DNS resolver override
settings JSONB NOT NULL DEFAULT '{}'::jsonb, -- per-device settings overrides
reported_generation BIGINT NOT NULL DEFAULT 0, -- last generation the agent applied
last_seen TIMESTAMPTZ
);
-- The per-device zone->interface binding table (the only host-specific object).
CREATE TABLE bindings (
device TEXT NOT NULL REFERENCES devices(name) ON DELETE CASCADE,
zone TEXT NOT NULL REFERENCES zones(name) ON DELETE CASCADE,
interfaces JSONB NOT NULL DEFAULT '[]'::jsonb, -- ["eth1"] or ["bond0.40"]
PRIMARY KEY (device, zone)
);
-- Monotonic generation counter bumped on any config-affecting change.
CREATE TABLE generation (
id BOOLEAN PRIMARY KEY DEFAULT true CHECK (id), -- singleton
current BIGINT NOT NULL DEFAULT 1
);
INSERT INTO generation (id) VALUES (true);