zerobyte icon indicating copy to clipboard operation
zerobyte copied to clipboard

feat: Add secret reference support (Environmental variables, Docker secrets)

Open tvarohohlavy opened this issue 2 weeks ago • 29 comments

Summary

Adds secret references so users can avoid storing credentials directly in Zerobyte. Sensitive fields can now be provided as env://... or file://... references which are not encrypted, but visible in UI as they are not the actual secrets.

Supported secret formats

  • env://VAR_NAME — reads process.env.VAR_NAME inside the Zerobyte container
  • file://secret_name — reads /run/secrets/secret_name (Docker secrets)
  • encv1:... — encrypted value stored in the database (existing native encryption)

What changed

  • Centralized secret handling (server)
    • cryptoUtils.sealSecret() encrypts plaintext before storing, but stores env:// / references as-is
    • cryptoUtils.resolveSecret() resolves env:// / file:// and decrypts encv1:... when needed
  • Wired through the app
    • Repositories, volumes (SMB/WebDAV), notifications store via sealSecret() and resolve via resolveSecret()
    • Restic env building resolves credentials at runtime
    • Backend compatibility checks compare resolved values (not raw encrypted strings)
  • UI: consistent secret input UX
    • While editing: masked input with an eye toggle
    • After save (stored value is env://, file://, or encv1: and field is not dirty): shown as plaintext with no eye icon
    • Scoped CSS fix to prevent “double eye” in Edge/Windows by hiding native reveal/clear controls only within SecretInput
  • Docs & examples
    • Added README section explaining env:// and file://
    • Added docker-compose commented examples for env var + Docker secrets wiring

Security notes

  • File secret references are restricted to a single path segment and resolved under /run/secrets using POSIX semantics (prevents traversal).

Breaking changes

None.

How to test

  1. Set a sensitive field to env://SOME_SECRET and confirm it resolves at runtime.
  2. Mount a Docker secret at /run/secrets/<name> and set the field to file://<name>.
  3. Enter a plaintext secret and confirm it is stored as encv1:... and still works end-to-end.

tvarohohlavy avatar Dec 06 '25 01:12 tvarohohlavy