Docs
The security model
What isolates one tenant from another, how credentials are stored and why, what a staff session can be revoked from, and where backups end up.
This page is the honest version: what the system does, what it deliberately does not do, and where a property comes from something you could verify rather than from an assurance.
Tenant identity
A subscriber is identified by the pair of a tenant and a username, never by a username alone. The tenant half is taken from a verified RADIUS attribute — the device's address or identifier, or the called station — or from a verified session token. It is never read from a request body or a query parameter.
Row-level security
Every tenant table in Postgres carries a policy keyed on a session variable that is set for the duration of each transaction. A query that forgets its tenant filter does not leak; it returns a narrower result.
The application connects as a role that is not a database superuser, because a superuser bypasses those policies unconditionally. That is the single most important line of the deployment: with the wrong database user, every policy is written, present in the catalogue, and inert.
Partition leaves get their own policies rather than inheriting them, and a schema check in the build fails when one is missing.
Passwords and credentials
Staff and reseller passwords are hashed with Argon2id. They are never recoverable, including by us.
Subscriber credentials are a different case, and it is worth stating plainly rather than implying otherwise: PAP, CHAP and MS-CHAPv2 require the server to hold the credential in a form it can compute against, so a subscriber's password is stored in a form the RADIUS path can use. That is a property of those protocols, not a choice of storage. If your threat model does not allow it, the answer is to change the authentication method your network uses, not to expect a billing system to defeat the protocol.
Card codes are stored so that staff can read a code back off a printed card, which is what the counter and support workflows need.
Payment gateway credentials are encrypted before they reach the database and are never sent back to the browser.
Staff accounts and sessions
- Time-based two-factor authentication, per account.
- Session revocation: a signed-out or revoked session stops working immediately rather than at its natural expiry.
- A configurable session length per tenant.
- An append-only audit log of who did what, with the request identifier.
Tokens, webhooks and the audit log
API tokens are scoped to an intersection of their own scope and their owner's live permissions, and a restricted token is never an administrator whoever created it. They are refused outright on account credentials and on token management itself.
Outgoing webhooks are signed, so a receiver can verify that a delivery came from your instance.
Long-lived streams re-prove their credential about once a minute: revoke a token, disable it, suspend its owner or block the tenant, and an open stream ends within the minute rather than running until the service restarts.
Backups
Instance backups are encrypted before they leave the machine and are written to storage you connect yourself, so the archive is yours and the key is not shared with the destination.
Restores are exercised rather than assumed: the recovery path is run as a drill from Control, not documented and hoped for.
Last updated