Closed ShadowJonathan closed 4 months ago
Tailscale seems to have an option to enable verification of peers, --verify-clients
, but this does not seem to be used in central regions, as it requires the embedded tailscale client to populate a list of all known peers over the whole network into each derp server all at once.
Instead, it seems to be used more for private relays, and such.
It does highlight the issue of preloading keys into relay servers. It seems that tailscale relies on clients mutually authenticating, and doesn't really add authentication to relay servers, confident in their ability to absorb the load, or simply ratelimit bad actors (I havent really checked for ratelimits, but I saw some strewn around).
Tailscale uses box
to seal disco messages over relay and such, golang.org/x/crypto/nacl/box
, for this it does some extra clamping to restrict the key.
If we're gonna be using this library (which does look useful, and enables simply authenticated disco messages and such), we'd have to do keygen ourselves.
Tailscale uses a key architecture mechanism where it generates a stable "machine key", with which it then authenticates itself with control, then it generates and publishes a "node key" that has expiry attached to it.
All other clients will understand and only see the "node key", and a "node ID", the machine public key is never shared. The key can have an expiry date added to it, and tailscale nodes will auto-expire the node based on this, and then no longer allow connections from that node.
The node then needs to be re-authenticated, this is done by generating a new key and publishing it to control. The old key is never re-authenticated, and keys are effectively rotated on a regular basis.
Note: The node key is also the wireguard key.
There are three keys:
Machine Key is never updated, and effectively authenticates and maps the Node itself. Never shared with other nodes.
Node Key is updated once it expires and/or the client re-authenticates, using the Machine Key to say "hello, I'm the same client" to do so.
Disco Key is generated on every program start, and effectively lives for as long as the program itself does. Is used for disco messages, and peer-to-peer exchange with other nodes.
All of this exists to provide stronger security guarantees, at the cost of extra complexity.
The current idea I have for eduP2P is this:
Have one key, this is simply the Node Key.
This key is not replaced, the public key is used as a node identifier.
Relays, when a client first connects, requests knowledge of the key, and also then subscribes to updates to that key's expiry. Or, when the network is small enough, preloads all keys at once, with subscription to their expiries. (1000 keys is 100 KB of memory, I think we could possibly key away with all keys + their expiries per server)
When keys expire, the node can reauth an existing key at control. (The control server)
Control will have its own key, this will authenticate control to clients and relays.
Control will send out updates - to concerned[1] clients and relays - with increased key expiry times, or (effectively) key re-authentication. Clients and relays will know these are authentic messages, as they're signed by Control's key.
Trust of key expiry is then put entirely in the hands of control, and clients will be notified when re-authentication happens.
[1] "Concerned" here means that the client is eligible to know and get updated about another client/peer.
Some related diagrams I made on request
I think for authentication, i'll go with the below:
The question of "will relays be authenticated" will be waylaid by this, because ephemeral sessions will be verified end-to-end anyways, where every client expects a session key for a particular node's session
With the decision to adopt the last key management system (with node keys, session keys, and shared keys), i'll close this as done
Here, i'm looking at the possibility of securing the Relay from being used/overloaded by unauthenticated users, and/or also addressing the possibility of what would happen if users could "bypass control" by simply connecting to relays even though they're not "supposed to", and the relay is unauthenticated.