diff options
| author | tv <tv@krebsco.de> | 2026-11-02 12:03:02 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-02 12:03:02 +0100 |
| commit | 25076058f102c8275c8fa2ba76efb33a46207687 (patch) | |
| tree | 6ae44b2acfa6f1fb64ce3d2b7ed9f4c2492359d4 /docs/trust.md | |
| parent | b6e44154902fd3507852932b0aed9885ceb85fbf (diff) | |
add documentation
Diffstat (limited to 'docs/trust.md')
| -rw-r--r-- | docs/trust.md | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/docs/trust.md b/docs/trust.md new file mode 100644 index 0000000..521a175 --- /dev/null +++ b/docs/trust.md @@ -0,0 +1,114 @@ +# Trust model + +Who can do what to a swarm, and what stands in the way. In short: the swarm key +decides who is a member, and members are trusted with everything. + +## The boundaries + +**The network.** Every transport authenticates the sender of every message, each by +its own key: Mycelium by the public key of the sending daemon, libp2p by the peer ID +of the connection, Tor by a challenge handshake on each connection, in which both sides +prove their node key ([`transports.md`](transports.md)). So a node always knows which address sent it something, though not +who wrote what that message carries (changes are relayed). On top, a node proves its +node ID at each address with a signature by its node key (WHO and ME, [`peers.md`](peers.md)), so a +node is known by its node ID whichever transport and address it uses. A private Mycelium +network (`--mycelium-network-key-file`, `--mycelium-network-name`) additionally keeps +other Mycelium nodes from reaching ours at all; on libp2p and Tor, anyone who knows an +address can connect, and the swarm key is what keeps them out. + +**The swarm key.** With `--swarm-key-file`, a node proves the key in the handshake +before anything else it sends is acted on; until then it is a *stranger*. Without a +swarm key, every node that can reach a member can join: a joining node doesn't need to +know the swarm ID, and the swarm ID is no secret anyway. The key file should be readable +by its owner only; a node warns at startup if others may read it. + +**Public infrastructure.** Nodes use none unless told to: Mycelium peers are those in +`--mycelium-peers`, and libp2p reaches only seeds, members and the relays of the swarm. +With `--libp2p-public`, a node joins the IPFS DHT and may use public relays: they see +whom it talks to and how much (the traffic itself is encrypted end to end), and the DHT +makes its peer ID and addresses public. + +**The node key.** `--node-key-file` holds the node's own key, from which its node ID +(`continuum:<hex>`) derives: who the node is, whatever transport reaches it. It is a +secret like the swarm key: readable by its owner only (a node warns otherwise; a key +it creates is). + +**The HTTP API.** Every endpoint but the API description needs a user from +`--htpasswd`. It listens on `127.0.0.1:3000` by default (`--bind-addr`) and speaks +plain HTTP: to expose it, put a TLS proxy in front. All users may read and write user +data and use the admin endpoints (remakes, forgetting peers, exports, log filters). +There are no read-only users: whoever may open the dashboard may also edit and delete +the document's data from it, and its writes reach the whole swarm. +Only the users in `--protocol-writers` may write protocol data through the store; epoch +metadata and the swarm ID are never writable. The `/debug` endpoints exist only with +`--debug-api`. + +**The configuration.** Whoever can write a node's configuration file or its options can +run commands as the node's user: a `cmd:` (or `command`) value runs at startup, and a +`file:` value reads any file the node can ([`configuration.md`](configuration.md), "Importing values"). +Protect the configuration like the swarm key. + +## What members are trusted with + +Everything in the document. A member syncs changes to and from its peers, and every +node acts on what the document says: + +* **User data**: any member can write or delete any path. +* **Who wrote what** (`GET /admin/changes`): each change names its node and API user + as the writing node says; nothing signs that, so a member can name another. The + names of the users who write are in the document, and so on every node. +* **The member registry**: each node writes its own entry, but nothing stops a member + from writing others'. The registry decides the topology and, through the alive + stamps, the electorate of a remake. +* **Forget records**: any member can make the swarm forget a peer (until it says HELLO + again). +* **Remakes**: any member can propose one, vote, and, as coordinator, decide. Votes + are not signed: the votes register says who voted, but any member could write any + entry. Every node switches to a committed epoch without counting the votes again. +* **Epochs it advertises**: a rejoining node follows the epoch ready members + advertise, corroborated by two of them once it was ready (one if only one is active, + and one before it was ever ready), and downloads the epoch's snapshot from them, + checked against its hash. +* **What it says about itself**: its keepalives and handshake replies say whether it is + ready, whether it would sync with the recipient, and how long it last heard from it + (which counts towards the recipient's stability tier). Nodes believe that: a member + claiming to be ready can become a joining node's catch-up source (though one with an + empty document can't make it ready: empty heads prove nothing), and one misreporting + absences can move a node between tiers. + +So a member that misbehaves, by a bug or on purpose, can rewrite or delete data, +manipulate the registry and the electorate, forge votes, commit a remake without a +majority, and make the swarm forget peers. Nothing but the swarm key protects against +that; keep it to nodes you trust as much as your data. + +## What depends on clocks + +Nodes don't agree on time; each judges by its own clock: voting periods, when a remake +expires and may be aborted by others, the replay window, alive stamps (and so the +electorate). Keep the clocks within a grace period (four keepalives) of each other, +e.g. with NTP. A node whose clock is further off can, together with an operator's +abort, make a remake contested ([`remakes.md`](remakes.md), Limits). A node compares its clock with its +peers' and warns when its own is off (`--clock-skew-warn`; [`measurements.md`](measurements.md), Clocks). + +## What a stranger can do + +Send messages. Before it proves the swarm key, a node ignores everything from it but +the handshake, and doesn't sync with it. A stranger can still cost a node the work of +reading and dropping its messages. + +## What protects against mistakes + +Not against a hostile member, but against honest ones getting in each other's way: + +* Majority voting with one vote per member and epoch: two remakes can't both commit + ([`remakes.md`](remakes.md)). +* A snapshot every node builds itself and checks against the committed epoch, and + downloads checked against their hashes. +* Protocol data writable through the API only by `--protocol-writers`, and logged. + +## Not yet + +Revoking a single member, or limiting what a member may do, needs per-node keys: a +member list in the document, with keys that sign what each node writes about itself +(its registry entry, its votes). See [`review-rejections.md`](review-rejections.md), "Author binding for remake +votes and decisions". |
