Architecture
Available

Security model

The trust boundaries of a Loams deployment today, how requests are authenticated, and what is designed next.

Loams 0.1.0 has one deployment shape, and its security model follows from it: you run the whole stack, it has no public address, and you reach it over your own Tailscale tailnet. Ostrium hosts only the console's static files and, for one optional sign-in mode, an OIDC issuer. Neither ever connects to your stack or sees your data.

Why we built it this way

A first release is the wrong time to put a new database on the public internet. Authorization is still coarse, several protocol listeners exist, and none of it has had an external review. The question we asked was: what is the smallest set of things that must be right for this to be safe to try?

Our answer: make the network do the first job, and make authentication mandatory on the one door. A tailnet gives every device a WireGuard identity and lets your own policy decide who reaches what. The stack exposes exactly one service to it, and the engine authenticates every request that comes through. Everything else stays inside the compose network.

That choice also keeps data where it belongs. The console is static files that run in your browser and call your engine directly; it holds no data and no secrets. Your bucket, your metadata and your keys never leave your machines.

The trust boundaries of the Loams 0.1.0 stack. Only the sidecar is reachable, and only over your tailnet.

How it works

One door. The compose stack's tailscale sidecar joins your tailnet (as loams by default) and serves the engine at https://loams.<tailnet>.ts.net with a tailnet HTTPS certificate. It is the only service reachable from outside the compose network, and only for tailnet members your policy admits. Nothing binds 0.0.0.0 on the host by default. With the House profile, the House gets its own sidecar and its own network that no other service shares.

Authentication on every request, chosen by LOAMS_AUTH_MODE:

ModeAcceptsNotes
tailscale (default)The Tailscale identity that tailscale serve addsTrusted only on the dedicated listener the sidecar targets (127.0.0.1:7781); every other listener ignores those headers, so a forged one on the main port gets a 401. LOAMS_TAILSCALE_ALLOWED_USERS narrows who is admitted
oidcBearer JWTs (RS256 or EdDSA) from an issuer, checked against its JWKSThe engine refuses to start without an allow-list of emails, subjects or groups. The console uses Authorization Code with PKCE and keeps tokens in memory, never in localStorage
apikeyAPI keys for the CLI and SDKsThe key file holds only hashes. loams auth new-key creates one
offLoopback clients onlyFor a laptop with nothing on any network; every non-loopback request is refused

Browsers are limited by CORS to the console's origin (or LOAMS_CORS_ORIGINS). Loams Live apps list their own allowed origins, and a Live call from any other origin is refused.

TLS when you leave loopback. The compose stack keeps the engine's main listener on loopback and relies on the tailnet's encryption. To bind it elsewhere, give it a certificate (LOAMS_TLS_CERT_FILE, LOAMS_TLS_KEY_FILE), optionally require client certificates (LOAMS_TLS_CLIENT_CA_FILE), or declare a TLS-terminating proxy and the addresses it connects from. Loams Live refuses to start on a non-loopback listener without TLS.

Isolation of the House. Loams House runs ClickHouse code (chDB) in workers that are sealed three ways: chDB's own access control (the worker users have no grants to reach files, URLs or other databases), statement checks as a second line, and an OS sandbox (Landlock and seccomp by default, or a per-worker network namespace). A worker whose sandbox cannot be applied refuses to boot.

Upgrades snapshot first. loams upgrade snapshots every store before it changes anything and loams upgrade rollback restores it. The snapshots stay on the host with mode 0700, because they contain your data and secrets.

What is not hardened yet

The release documentation lists these plainly, and so do we:

  • Authorization is coarse. A valid credential can do anything the engine can do. Per-namespace roles and tenant quotas are planned.
  • Keep the other listeners inside the stack. The Qdrant, Elasticsearch, Flight SQL, Postgres-wire, MySQL-wire and Resonate listeners are not published by default. Do not publish them in Loams 0.1.0: the auth modes are specified for the main port.
  • Traffic inside the compose network is plain text between the engine, TiKV, PD, TiDB and the Postgres stack. The tailnet encrypts the hop from your device to the stack.
  • The Postgres development stack uses default credentials and runs its computes with fsync = off.
  • No external security review has been done yet.

Report anything you find privately, through the repository's SECURITY.md, not in a public issue.

What is designed next

  • Roles and authorization behind an Authorizer interface: built-in role-based access on namespaces and collections first, then fine-grained grants through OpenFGA, with every grant fenced to its tenant (D66, D67).
  • Organizations, API keys and quotas held in a control store separate from the metastore (D65), with a planned key format loams_<id>_<secret>. The keys 0.1.0 issues are lk_<ULID>_<secret>.
  • Customer-managed keys per namespace, with WAL chunks envelope-encrypted per chunk, so destroying a key makes that namespace unreadable (D96).
  • An audit stream of administrative and security events (D100), and a GDPR erasure path that removes bytes from every place they live, caches included (D68).
  • Headscale as an alternative to Tailscale, once it can serve HTTPS certificates the hosted console can call.

How other systems do it

  • Self-hosted databases usually listen on a port and leave the firewall and access policy to you.
  • Managed services put the database behind the provider's network and identity (private endpoints, IAM). Loams' BYOC design reaches a similar shape with an outbound agent or a tailnet.
  • Tailscale-fronted services (tailscale serve with identity headers) are a common way to run internal tools without a public address; the important detail is to trust those headers on one listener only, which is what the engine does.

Status

Available Tailnet-only access through the sidecar, the four auth modes, CORS limits, TLS options, House sandboxing and snapshot-first upgrades ship in Loams 0.1.0 (the release table's "Engine auth" and "Self-hosting with Docker Compose" rows). Roles, per-namespace authorization, tenant quotas and customer-managed keys are Planned.

Go deeper

On this page