Start Housecarl: the logo, the wordmark and the skeleton
Housecarl will be a firewall manager for nftables, built the way Jarl and Steward are: housecarld (a daemon with a REST API and web UI), hc (the CLI) and SQLite. - The logo: a carved Nordic doorway in Jarl's blue (artwork/logo.svg), with a small version without the carvings, lighter on dark backgrounds. scripts/logo.py builds the web UI's copies and scripts/banner.py the README banner. - The HOUSECARL wordmark in Jarl's and Steward's angular letters, with new H, O, U and C (assets/brand.js), and the UI's color tokens. - housecarld and hc print their version; the Makefile, version package, AGENTS.md, CHANGELOG and the design sketch (docs/design.md). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
54beb0bba3
24 files changed
+949
No files matched your search
@@ -0,0 +1,86 @@
|
||||
# Housecarl's design
|
||||
|
||||
Housecarl is a firewall manager with the same shape as
|
||||
[Jarl](https://gitea.adbraun.lol/adam/jarl) and
|
||||
[Steward](https://gitea.adbraun.lol/adam/steward): one daemon,
|
||||
`housecarld`, that serves a REST API and a web UI; one CLI, `hc`, that
|
||||
talks to that API; SQLite for everything. As Jarl does for BIND, it keeps
|
||||
a Linux machine's **nftables** ruleset: the database is the source of
|
||||
truth, and the ruleset is built from it.
|
||||
|
||||
This page is the starting sketch. Nothing here is built yet; it records
|
||||
what was decided and what is still open.
|
||||
|
||||
## How a change is made
|
||||
|
||||
As in Jarl, every change goes through one engine:
|
||||
|
||||
1. the request becomes a change to a copy of the configuration;
|
||||
2. the whole result is validated, with errors that say what is wrong and
|
||||
how to fix it;
|
||||
3. the ruleset is rendered, and checked with `nft -c -f` (a dry run by
|
||||
nftables itself);
|
||||
4. it is applied with `nft -f`, which replaces Housecarl's table in one
|
||||
transaction: the old rules stay in force until the new ones are all in;
|
||||
5. the change, its history entry and the audit record are saved together.
|
||||
|
||||
Dry runs, history with undo, users, sessions and scoped API tokens come
|
||||
from the same machinery, as in Jarl and Steward.
|
||||
|
||||
### Not locking yourself out
|
||||
|
||||
A firewall managed over the network can cut off its own manager. Housecarl
|
||||
should guard against that from the start:
|
||||
|
||||
* **Confirm or roll back.** A risky change (one touching the rules for the
|
||||
machine itself) is applied on probation: unless it is confirmed within a
|
||||
minute or two, from the web UI or `hc confirm`, the previous ruleset comes
|
||||
back by itself. Network equipment calls this "commit confirmed".
|
||||
* **A management rule that can't be dropped by accident**: the API and SSH
|
||||
stay reachable from the management network unless that rule is removed
|
||||
on purpose.
|
||||
|
||||
## Its own table only
|
||||
|
||||
Housecarl writes one nftables table of its own (`inet housecarl`) and
|
||||
leaves every other table alone, such as Docker's or libvirt's. It never
|
||||
flushes the whole ruleset.
|
||||
|
||||
## Concepts (draft)
|
||||
|
||||
* **Zones**: interfaces or VLANs grouped by trust (`lan`, `iot`, `guest`,
|
||||
`wan`), and the default policy between each pair.
|
||||
* **Address sets**: named sets of addresses or prefixes, which rules refer
|
||||
to. An entry may have a **timeout**, which nftables enforces by itself, so
|
||||
an entry expires even if housecarld is down. Other programs can be given
|
||||
a token that may only change one set.
|
||||
* **Rules** between zones: allow or drop, by set, port and protocol, with
|
||||
logging and counters.
|
||||
* **NAT**: masquerading out of the WAN zone, and port forwards.
|
||||
* **Services**: names for ports (`ssh`, `https`, `dns`).
|
||||
|
||||
## Working with Steward and Jarl
|
||||
|
||||
* **Steward's captive portal** (parked until Housecarl exists): a guest
|
||||
network's zone lets clients that haven't signed in reach only DNS and
|
||||
the portal, and sends their web traffic to it. When a guest signs in,
|
||||
Steward adds its address to a set (`guest-signed-in`) for the session's
|
||||
length, with a token that may only change that set. Addresses, not MAC
|
||||
addresses: matching by MAC only works on the guests' own network
|
||||
segment.
|
||||
* **Names instead of addresses**: Steward knows every reservation's and
|
||||
lease's address, so rules could name a device ("the printer") or a
|
||||
subnet; Jarl knows the names in DNS.
|
||||
* **Steward's deny lists** could also be enforced here, so a denied device
|
||||
with an address set by hand is still blocked.
|
||||
|
||||
## Open questions
|
||||
|
||||
* IPv6 from the start, or IPv4 first as Steward did?
|
||||
* Import an existing nftables (or iptables) ruleset, as Jarl imports a BIND
|
||||
configuration?
|
||||
* Connection tracking defaults: established and related traffic allowed
|
||||
everywhere unless a rule says otherwise?
|
||||
* Does Housecarl also run the router's interfaces and routes, or only the
|
||||
firewall? (Only the firewall, for now.)
|
||||
* Rate limits and flow offloading: later.
|
||||
Reference in new issue
Block a user