Access Control
Tubo uses a layered capability model. Publishing a service requires authority approval, collaborative namespaces require namespace discovery entry state, and connecting to a service requires a signed lease or a valid membership-based grant path.
Overview
There are three layers of access control:
- Transport isolation — PSK swarm key. Nodes without the key are rejected at the TCP level.
- Publish authorisation — a service peer must hold a
PublishLeasesigned by the cluster authority to appear in discovery. - Connect authorisation — a client must hold a
ConnectAccessLeaseto open data-plane streams. The service verifies a signed proof-of-possession on every stream open.
Share invites (the simplest flow)
The most common flow is: Alice runs tubo attach, gets a share invite token,
and gives it to Bob.
# Alice: publish a service and get a share token $ tubo attach http://127.0.0.1:8080 --name myapi -d ✓ Share token: tubo connect --token eyJ... # Bob: connect with the token (no account needed) $ tubo connect --token eyJ... --local 127.0.0.1:9000
The token is self-contained: it includes the service endpoint, the grant service peer,
and all metadata needed to redeem it for a ConnectAccessLease. No discovery
is needed.
tubo share service/...
to generate additional tokens.
Sharing a service manually
# Generate a new one-time connect token for myapi $ tubo share service/myapi --expires 24h ✓ Share invite (valid for 24h): tubo connect --token eyJ...
Collaboration namespaces
For teams, create a private cluster and invite members. Members can discover and connect to services by name without an explicit token:
# Authority: invite a team member $ tubo share cluster/myteam --role member ✓ tubo join cluster/myteam --token eyJ... # Member: join and connect by name $ tubo join cluster/myteam --token eyJ... $ tubo get services $ tubo connect myapi --local 127.0.0.1:9000
Viewer invites (--role viewer) allow discovery but not connect.
Member joins install the current namespace discovery secret locally, so the member can use
tubo get services and tubo connect <name> in that namespace.
Publish Grants
On private clusters, a service host that doesn't own the authority key must request a
Publish Grant before tubo attach can succeed:
# Authority host: start the grant service $ tubo grants serve --cluster myteam --namespace default -d # Service host: request a grant $ tubo grants request service/myapi \ --peer /ip4/1.2.3.4/tcp/4001/p2p/12D3... Waiting for approval... (Ctrl-C to cancel) # Authority host: approve the grant $ tubo grants pending gr_abc123 myapi pending $ tubo grants approve gr_abc123 --ttl 168h # Service host: now attach works $ tubo attach http://127.0.0.1:8080 --name myapi -d
Namespace discovery entries and rotation
In collaborative scopes, service visibility is additionally gated by namespace discovery entry state. Operators can inspect and rotate that state locally without printing raw secret bytes:
$ tubo get secrets $ tubo describe secret/namespace-discovery/myteam/default $ tubo rotate secret/namespace-discovery/myteam/default --grace 24h
Rotation uses a managed current/previous model. Publishers emit using only the new
current entry. Subscribers accept current plus a non-expired previous entry during the grace window.
This is a compatibility window, not perfect immediate per-peer revocation.
Revocation
# Revoke a share invite (prevents future redemptions) $ tubo revoke invite eyJ... # Revoke an active session $ tubo revoke session <session-id> # Revoke service access (all existing leases for a service) $ tubo revoke service-access myapi # Revoke a publish lease (service can no longer publish) $ tubo revoke publish myapi
Connect lease lifecycle
When Bob connects with a token, Tubo exchanges the one-time invite for two leases:
- ConnectAccessLease — short-lived (default 10 min). Used to open data-plane streams. The service verifies a proof-of-possession on each stream open.
- ConnectRefreshLease — longer-lived (default 48h). Used to renew the access lease before it expires. The bridge renews automatically in the background.
Leases are bound to the client's local keypair — they cannot be forwarded to a different machine.
Namespace connect policies
Each namespace has a configurable connect policy:
| Policy | Who can connect |
|---|---|
invite_only | Only holders of a valid share invite token (public default) |
namespace_members | Cluster members with connect permission (private clusters default) |
public | Anyone on the swarm (rate-limited) |
Next steps
- Security Model — full trust chain and non-goals
- CLI Reference — all grant and share commands
- Deployment — running grants serve in production