Authorization
Who gets to use the relay
Every relay connection is authenticated before it is admitted, and admission is decided by NervesCloud rather than by the relay itself.
The handshake
-
1
The device proves its key
Before anything else, the relay handshake makes the endpoint prove it holds the private key for the public key it claims, by signing either keying material exported from the TLS session or a challenge the relay issues. The relay does this for every connection, authorized or not, so the identity that reaches the next step cannot be spoofed.
-
2
The relay asks NervesCloud
The relay knows the endpoint is who it says it is, but not whether it is one of ours. So it calls this service with the endpoint id and waits for a verdict. No policy lives on the relay itself, which is why access can be changed without redeploying one.
-
3
NervesCloud answers with a fabric
We look the endpoint up and reply with a decision and, for a known device, the organisation it belongs to. That name is what the relay uses to keep one customer's devices from reaching another's.
-
4
The connection is admitted or refused
An admitted endpoint can now be reached through the relay by others in its fabric. A refused one is disconnected during the handshake and never registered, so it cannot send a single packet.
The access hook
Each relay is configured with the URL of this service and a bearer token that identifies it to us. It makes one request per incoming connection, before that connection is registered.
POST /relay-access HTTP/1.1
Host: iroh.nervescloud.com
X-Iroh-NodeId: c8924b6c9b7a8528b1365ebec4b2e43b6edebef684f8521f12b8caaf6e1b2302
Authorization: Bearer <the relay's token>
A 200
carrying allow: true
admits the endpoint. A denial refuses it. So does a bad status, or no answer at all.
HTTP/1.1 200 OK
Content-Type: application/json
{"allow": true, "fabric": "org-1234"}
Fabrics
Not deployed yet.
The relays currently admit endpoints without applying fabric isolation. The
fabric
field is already part of the contract above so that nothing has to change here when it is.
A fabric is a name the relay compares verbatim when deciding whether to forward a datagram: two endpoints exchange traffic only if they were admitted into the same one. We use organisation ids, so one customer's devices cannot reach another's through a relay, even if an endpoint id leaks. A packet that would cross fabrics is dropped exactly as one addressed to an endpoint that is not connected, so it cannot be used to probe whether a device is online.
An endpoint admitted without a fabric is unrestricted, reaching every fabric and reachable from all of them. That is reserved for NervesCloud's own infrastructure.
What this does not cover
It admits endpoints, not conversations
The check runs once per relay connection and answers "may this endpoint use the relay". It is not asked again per peer, so pairing rules between two specific devices are not something a relay can enforce.
Direct connections never reach us
Once hole punching succeeds, traffic flows straight between the two devices and no relay is involved. Any rule that must hold on every connection has to be enforced by the device accepting it, checking the remote endpoint id itself.
Revocation applies at the next connection
Removing an endpoint stops it being admitted from then on, and a live connection can be dropped, but a device that is already connected is not interrupted by the change alone.