Browse the docs

Serve

Security Model

Offloader runs in your environment and serves read-only data. This page explains, in plain terms, what it protects for you and what you remain responsible for. (Newer to the concepts? See What Offloader is.)

The short version

  • Your data, config, logs, and metrics stay in your environment. Offloader makes no outbound telemetry calls.
  • Consumers reach data only through named endpoints on the API port, using an API key you issue. There is no arbitrary SQL.
  • Each key is scoped to specific endpoints and bound to one tenant (customer/account). Offloader inserts the tenant filter itself — a caller cannot widen it or read another tenant's rows.
  • Operator surfaces (docs, metrics, diagnostics) are on a separate admin port that you keep private. Offloader is not a login/identity product.

Who can reach what

Port Who What they get Guarded by
API (4000) your product / consumers only the endpoints their key is granted, only their tenant's rows, only allowed columns the API key + rules Offloader enforces (below)
Admin (4001) your operators health, metrics, generated docs, diagnostics you — network / firewall / proxy / IAM. Keep it off the public internet.

An API key is a bearer token you mint with offloader keys create. Only its SHA-256 hash is stored in config — never the token itself. Revoke a key by changing its status; it's denied immediately.

What Offloader enforces (you get these for free)

  • No arbitrary SQL reaches consumers — only your declared endpoints.
  • Endpoint allowlist per key: a key can call only the endpoints granted to it.
  • Tenant isolation: the tenant filter is inserted server-side from the key and cannot be overridden by a request parameter.
  • Column allowlist: an endpoint can return only its declared columns — checked before the query runs.
  • Safe errors: a forbidden endpoint and a non-existent one return the same response, so probing can't discover what exists.
  • Secrets stay out of the open: logs, metrics, diagnostics, and support bundles never include API keys, tokens, credentialed URLs, or raw params by default; support bundles are redacted and list what's inside.
  • Read-only object-store credentials are the intended posture — Offloader only reads snapshots.

What you're responsible for

  • Exposing the admin port safely. Offloader ships the separation (two ports) and redaction; you decide how the admin port is reached — loopback, an internal network, a proxy, or your IAM.
  • TLS and ingress in front of the API port.
  • The snapshot pipeline that publishes data to object storage, and the object-store permissions themselves.

Offloader does not provide RBAC, SSO, org/team management, or a hosted control plane. If you need enterprise access controls, run the admin port behind the ones you already use.

Co-hosting config in the bucket

If you load config from a bucket (OFFLOADER_CONFIG=gs://…), the config tree includes the keys file — but keys are stored as hashes, never tokens, so bucket-read exposure leaks hashes plus the endpoint/tenant access map, not usable credentials. A public deployment (auth: none) has no keys file at all. For an authed deployment, put the config under a tighter-ACL bucket/prefix than the bulk data if you want to limit who can read the hashes.

How we prove it

An adversarial test suite (gateway/test/offloader/security_suite_test.exs) exercises the invariants above on every build: API-key bypass attempts, tenant-override attempts, column selection outside the allowlist, param/filter injection, admin surfaces not reachable on the API port, secret redaction in logs and bundles, and safe rollback of a failed snapshot.