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:

  1. Transport isolation — PSK swarm key. Nodes without the key are rejected at the TCP level.
  2. Publish authorisation — a service peer must hold a PublishLease signed by the cluster authority to appear in discovery.
  3. Connect authorisation — a client must hold a ConnectAccessLease to 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.

One-time tokens. Each share invite can be redeemed exactly once. A second connect attempt with the same token will be denied. Use 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:

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_onlyOnly holders of a valid share invite token (public default)
namespace_membersCluster members with connect permission (private clusters default)
publicAnyone on the swarm (rate-limited)

Next steps