Security → Architecture

Security architecture

TunnelCrib has four components. Only two of them ever see Service traffic; the Central Server only ever sees control-plane and signaling messages.

ComponentRoleSees Service traffic?
TunnelCrib ClientRequests a Tunnel, opens a local listener, forwards Service traffic to the Agent.Yes (it is one endpoint of the Tunnel)
Central ServerAuthenticates Devices, enforces organization isolation, allocates sessions, relays signaling messages.No — signaling only
TunnelCrib AgentAdvertises approved Services, serves the requested Service over the established transport.Yes (it is the other endpoint)
TunnelCrib Relay (tunnelcrib-bridge)Optional data-plane hop, used only when a Direct Tunnel cannot be established.See What the Relay can see

Direct Tunnel first, Relay only on failure

Every Tunnel attempt tries a direct Client–Agent path before ever involving a Relay, using three fallback tiers:

TierMechanismFalls back when
0UDP + KCP, local/VPN candidates and STUN-assisted NAT traversalNo reachable candidate or punch timeout
1TCP simultaneous-open punch (SO_REUSEPORT)Tier 0 fails within the shared punch budget
2TunnelCrib Relay (tunnelcrib-bridge), hosted or a Private RelayTier 1 also fails within the total punch budget (10s)

Whichever tier wins, SSH is the only authentication and encryption layer. UDP and TCP punching only establish the underlying byte stream; the SSH handshake, host-key pinning, and public-key authentication are identical in every tier.

Direct-path address disclosure: for UDP setup, each endpoint advertises up to 16 IPv4 candidates, including local LAN and VPN interface addresses plus the STUN-observed public address when available. The Central Server relays these signaling candidates to the other authorized endpoint, so both the peer and the control plane can see them. Candidate exchange can happen even when the attempt later falls back to a Relay. The selected UDP peer addresses may also be included in the organization's Tunnel audit event; server debug logs can contain signaling payloads. These addresses are routing hints only: SSH public-key authentication and Agent host-key pinning still determine whether the peer is trusted.

Registration and authorization sequence

  1. TunnelCrib Client, TunnelCrib Agent, and a customer Private Relay each register with the Central Server (hostname, uuid, and, for Agents, advertised protocols).
  2. The Central Server validates each Device against the organization's registry by organization, UUID, and Device type.
  3. The Central Server issues a nonce challenge to both peers.
  4. Client, Agent, and customer Private Relay sign the nonce with their registered per-Device identity key (see Device identity).
  5. The Central Server verifies the signature against the registered public key. Connections failing this check are rejected.
  6. When a Client requests a Tunnel, the Central Server checks the requested protocol against the Agent's advertised list and organization boundary before signaling either peer.

Independently of the registration handshake, every Direct Tunnel's SSH layer separately pins a per-session Client public key and, after first use, the Agent's host key — so a Direct Tunnel cannot be impersonated even if the transport-level address exchange were spoofed. Address candidates do not grant access to a Service; the Central Server still authorizes the requested Agent and Service before signaling begins.

Signed control messages

Registration proves possession of a Device key. After registration, TunnelCrib adds message-level signatures to the WebSocket control plane so a valid connection cannot simply be used to inject or replay commands.

DirectionControlProtection
Client → Central ServerRequests, tunnel signals, and status messagesClient ECDSA P-256 key signs each JSON payload with the Device UUID, connection session ID, and increasing sequence number.
Agent → Central ServerAgent control messages and tunnel signalsAgent ECDSA P-256 key signs each JSON payload with the same identity, session, and sequence binding.
Private Relay → Central ServerRegistration and relay control connectionThe registered Private Relay signs the nonce challenge. Its ongoing control messages are currently accepted unsigned for compatibility while relay signing support is being completed.
Central Server → AgentManaged tunnel configuration and sensitive tunnel commandsThe server signs the payload with its active P-256 control-server key. The Agent verifies the pinned server key ID, organization, target Agent UUID, and increasing sequence number before processing it.

Registration and nonce-response messages remain bootstrap messages and are not wrapped in the per-message envelope. During rollout, the server can accept older unsigned Client or Agent messages in compatibility mode; deployments can switch to required signatures after all participating Devices support them. A shared infrastructure Relay has no registered Device key and is not part of this message-signature policy.

Control-server signing key

The Central Server's signing key is an unencrypted ECDSA P-256 private key loaded from a protected server secret. The private key is never sent to Devices and is not stored in the management database. The server publishes only the corresponding OpenSSH public key and key ID during registration. Devices pin that key in their local organization configuration, and every server-signed command is bound to the organization, target Agent, key ID, payload, and per-connection sequence. A key rotation therefore requires issuing and pinning a new key ID before commands signed by it are accepted.

Trust boundary summary: the Central Server brokers who may request what; it never terminates or forwards Service traffic. The Client and Agent are the only parties that see Service bytes on a Direct Tunnel. On a Relay-mediated Tunnel, see what the Relay can see.

Last reviewed 2026-10-22.