Known limitations
Things we know aren't covered. None of these block production use, but operators should know about them so they aren't surprised.
#Failed-login audit rows are not yet recorded
Successful auth.login rows are recorded; failed ones aren't. The
per-IP rate limiter on /auth/login/local (10 attempts / 15 min,
hard-coded) defends against brute-force, so the absence of failure
rows isn't an exposure — it's a forensic-completeness gap. Tracked in
Roadmap.
#No persistent session revocation list
When an admin disables a user, that user's existing sessions are unaffected until the next attach. The session row is still in the database; the user simply can't log in again. To force immediate logout of an active session, delete the session row directly from SQLite or restart Stowage (which invalidates every session).
#OIDC logout doesn't initiate IdP-side logout
POST /auth/logout clears the local session. It doesn't redirect the
user through the OIDC provider's logout endpoint. If your IdP keeps
its own session, the user may stay signed in there.
If you need single-logout, configure your IdP's session lifetime to match Stowage's, or front Stowage with an authenticating proxy that handles the OIDC logout dance.
#CSV streaming pagination isn't implemented
The /admin/audit.csv handler buffers in memory before responding.
Multi-million-row exports may exhaust memory. Workaround: query the
SQLite directly off a backup snapshot. Tracked in
Roadmap.
#Quota scanner only walks quota-configured buckets
The dashboard's storage card excludes buckets without a quota. Tracked in Roadmap.
#No native admin-API screens (yet)
Capabilities.AdminAPI returns "" for every driver. The
corresponding dashboard screens (per-backend users, keys, policies)
are gated on this and so remain hidden. To manage backend-native
identities, use the upstream's own tooling.
#Single replica only
SQLite has one writer, the rate limiter is in-process, the audit
recorder is in-process. Multi-replica is not supported. The Helm
chart pins replicas: 1 and uses an RWO PVC.
#No automatic key-rotation tool
Rotating STOWAGE_SECRET_KEY is a manual procedure (see
Operations → Key rotation).
An automated re-sealing migration is on the wishlist.
#Operator's Internal Secrets are not double-sealed
The internal Secret in the operator namespace holds plaintext
secret_access_key data inside the Secret payload. It's protected
by Kubernetes RBAC and (if you've configured it) etcd encryption
at rest, but Stowage doesn't apply its AES-256 sealing to that
side. The reasoning: the proxy informer reads these on every
request, and double-sealing would force the proxy to share the
master key with the operator, which makes blast radius worse.
If your threat model requires Stowage-side encryption-at-rest of operator-written Secrets, run with etcd encryption-at-rest enabled on the cluster.
#DDoS is your edge's problem
Stowage has rate limits but isn't designed to absorb flood traffic. Run it behind an edge that can drop garbage requests early (Cloudflare, AWS Shield, ngx_http_limit_req_module with sane buckets).
#Side-channel timing on argon2id
argon2id verification leaks whether a hash exists. The per-IP login rate limit caps the parallelism this gives an attacker, but the absolute timing is observable from a single request.