Farrier

Fleet management for Ubuntu and Debian servers, without a remote shell. The agent is outbound-only, runs a closed set of typed operations, and obeys a policy the control plane cannot change.

By Pegasus Networks. Licensed Apache-2.0. Documentation: farrier.tools.

Important

Farrier is in phase 0. It ships no write capability at all. The intent catalogue is complete — four read-only operations, one routine and five destructive — but only the read-only four have an executor behind them; every privileged one is refused with a distinguishable error. The protocol, the policy enforcement and the packaging are real and tested, so that phase 1 adds executors rather than foundations. Do not expect to patch a fleet with this yet.


The guarantee

An attacker who fully owns the Farrier control plane, its database, and an administrator account still cannot run arbitrary code on any enrolled host, cannot exceed any host's local policy, and cannot reboot or stop services on hosts whose policy forbids it.

A host being enrolled applies, at most once, the bootstrap template its operator named on the command line — shown in full before it runs, signed by a key from that host's own trusted-signers, and recorded permanently on the host.

Both paragraphs ship together, always. The second is the price of the bootstrap feature, and a guarantee with an undisclosed exception is worse than no guarantee — so the first paragraph is never quoted on its own just because it reads better.

Landscape, Salt, Uyuni and Rudder all ship a remote execution channel. Farrier does not. That absence is the product, and everything below exists to make the absence hold up under a control plane that has been fully compromised.

How it holds

Three mechanisms, specified in docs/SECURITY.md and asserted by a required CI workflow that no maintainer can override:

  1. A closed intent catalogue. The wire protocol carries an enumerated, typed operation — never a command string. No code path leads from a network message to a shell. Every external call is execve with a fixed argv slice.
  2. Local policy sovereignty. Each host carries a root-owned /etc/farrier/policy.toml that the control plane cannot modify and no intent can touch. Effective permission is always min(central request, local policy) — never the max. The check that matters runs as root in the helper, so a fully compromised agent process is still bounded.
  3. Offline job signing. Every destructive operation requires a signature from a key in that host's own /etc/farrier/trusted-signers — a key the control plane does not hold. The file is empty by default, so a fresh agent executes nothing destructive until an administrator puts a key in it.

What it does

What it will never do

No remote shell. No configuration management — this is not Ansible. No metrics platform — Prometheus does time series properly; this takes a low-frequency state snapshot. No secret distribution — the control plane never pushes credentials to hosts. No VPN requirement. No runtime plugin loader. No database abstraction layer for portability.

shell.exec, script.run, arbitrary file.write, apt.addRepository, user.create, ssh.authorizedKeys.add and agent.updateFromURL are permanently refused, each with its reason written down in docs/SECURITY.md. In an open-source project that request arrives eventually, usually from someone with a real problem, and the answer needs to be a document rather than an argument.

Architecture

Agent Go. A static binary — no runtime on managed hosts, which is what keeps MemoryDenyWriteExecute=yes available
Control plane Go. One binary with the Angular bundle embedded via embed.FS, plus PostgreSQL
Database PostgreSQL, used deliberately: JSONB + GIN for facts, partial indexes for the job claim, LISTEN/NOTIFY instead of Redis, SELECT … FOR UPDATE SKIP LOCKED for atomic claims
Web UI Angular + Angular Material + Tailwind v4, standalone components
Queue / pubsub None
Transport HTTPS long-poll with mTLS. Agent to server, never the reverse

Open-source software is installed by strangers who close the tab on friction, and a four-service Compose stack is friction. Sharing one language between both sides also means the intent catalogue and signature verification are literally the same code on the agent and on the server, rather than two implementations that agree until they don't.

Supported platforms

Ubuntu 22.04 (jammy), 24.04 (noble), 26.04 (resolute); Debian 12 (bookworm) and 13 (trixie).

The policy is a rule rather than a list: the Ubuntu LTS releases in standard support, plus Debian stable and oldstable. Ubuntu 20.04 is excluded as ESM-only.

Documentation

docs/ Everything below, plus a note on where the design rationale lives
docs/INSTALL.md Getting a control plane and a host running, and what a fresh host will and will not do
docs/SECURITY.md The guarantee, the three mechanisms, the permanently-refused list, and an honest statement of what Farrier does not defend against
docs/PROTOCOL.md The agent protocol, specified well enough to reimplement
docs/EXTENDING.md The seams that are open, and the ones that are closed on purpose
CONTRIBUTING.md DCO sign-off, English, and the comment rule
TRADEMARK.md What you may call your fork

Building

make build          # all three binaries into ./dist
make test           # unit tests
make guarantee      # the tests that enforce docs/SECURITY.md §1
make lint           # golangci-lint + doccheck
make web            # the Angular application, embedded into farrier-server
make deb            # the farrier-agent .deb via nfpm

Go 1.26 or newer. make deb additionally needs nfpm; make web needs Node and pnpm.

Licence, and why it will not change

Apache-2.0 for everything. Contributions are made under the Developer Certificate of Origin — there is no CLA, and Pegasus Networks holds no special rights over contributed code that you do not also hold.

This is deliberately permanent. Relicensing a DCO project requires the agreement of every contributor, which means no future owner of this repository can take it proprietary, including us. For a security tool whose entire value is that you can verify its claims yourself, the ability to promise that is worth more than the option to change our minds.

Apache-2.0 §6 grants no trademark rights. The Farrier word mark is reserved; see TRADEMARK.md. You may fork the code and ship it; you may not call your fork Farrier.

Contributing

Please read CONTRIBUTING.md first. Two rules catch most first-time contributors:

Security issues go through GitHub's private advisory flow, not the public tracker — docs/SECURITY.md §9.