Security and access
Security
Authentication, roles, TLS, limits and the safeguards built into the process.
Clients and TLS#
- Client authentication is SCRAM-SHA-256 by default;
md5is available andtrustis for development only. - Enable client TLS with
listen.tls.certandlisten.tls.key, and require it withlisten.require_tls = true. StreamQL acceptsSSLRequestand direct TLS with ALPNpostgresql. - Server connections use
upstream.sslmode. Useverify-fullwithupstream.sslrootcertfor a private CA; an unreadable CA fails closed. - Clients that ask for protocol 3.2 are negotiated down to 3.0.
Console sign-in#
- The console supports local passwords (argon2id, minimum
access.password.min_length12 characters, common passwords and the user's email rejected), OIDC single sign-on with PKCE, TOTP and WebAuthn multi-factor, and break-glass accounts whose every use is audited. access.mfaisoff,optional(default),required_adminsorrequired.- Sessions end after
access.session_idle_s(1800) of inactivity oraccess.session_absolute_s(43200). An account locks foraccess.lockout_s(900) afteraccess.lockout_attempts(5) failures, and sign-in attempts are rate limited (access.attempts_per_minute, 20). - The first start prints a one-time setup code. The first person to claim the node becomes its admin;
access.loopback_claimlets a loopback client claim a loopback-bound node. - Set
access.trusted_proxiesto the CIDRs of your reverse proxies before relying onX-Forwarded-For, andaccess.public_urlwhen the console is served under a public host name.
For OIDC, access.oidc takes issuer, client_id, client_secret, scopes, role_claim, a roles map from claim values to console roles, default_role and auto_provision. ID tokens signed with RS256 and ES256 are accepted, and issuer, audience, expiry and nonce are checked.
Roles#
| Permission | Admin | Operator | Viewer | Auditor |
|---|---|---|---|---|
| View dashboards | yes | yes | yes | yes |
| View statement text and client addresses | yes | no | no | yes |
| Add and remove databases | yes | no | no | no |
| Edit policy and config | yes | scoped | no | no |
| Switch optimizations on or off | yes | scoped | no | no |
| Drain gateways and manage workers | yes | yes | no | no |
| Manage alert rules and channels | yes | scoped | no | no |
| Manage users, roles and API tokens | yes | no | no | no |
| Read the audit log | yes | no | no | yes |
Scoped is a full grant for a user assigned every database. A user assigned only some databases gets it on routes that check the target database, and every changed key must sit under an assigned database. Without the sensitive-read permission, client addresses show as <redacted>.
API credentials#
| Credential | Principal |
|---|---|
sq_session cookie | A console user, with the user's role and database scope |
Authorization: Bearer sqa_... | An API token with its own role and scope |
Authorization: Bearer <admin.token> | Automation, as admin |
A wrong bearer token is always 401 and never falls back to anonymous. Cookie-authenticated writes need a CSRF token. access.anonymous is auto (default), none or viewer.
Limits and hardening#
limits.max_message_bytes(256 MiB) bounds a message held whole in memory; larger row and COPY data is streamed whenlimits.stream_large_messagesis on.limits.max_unauthenticated(1024),limits.auth_timeout_s(30) andlimits.failed_login(20 failures per 60 s block an address for 60 s) harden the pre-authentication phase.- Framing and authentication faults close the connection; missing evidence means a statement is forwarded unmodified.
- The process sets
RLIMIT_COREto 0, disables dumping, refuses to run as root unlesssecrets.allow_rootis set, and keeps secrets in an encrypted in-memory vault with zeroed memory. - Every optimization has an independent kill switch; the
dataplane.*options anddataplane.engine = "tokio"restore the defaults.
Secrets#
Use secret references (file:, env:, vault: and the others in Configuration) for upstream passwords, the admin token, OIDC client secrets and MCP passwords. They are never written to logs or shown again by the console.