4.3 KiB
Secret Store and encrypted full backup/restore
RustProxy keeps application credentials in a central encrypted Secret Store. Provider and ACME secrets are not stored as plaintext configuration values in SQLite.
Secret Store
Secret records live in the secret_store SQLite table and contain an identifier, provider/type, encryption version, nonce, ciphertext, metadata and timestamps. Values are encrypted with AES-256-GCM using a random local data key stored at:
<data-dir>/secrets/master.key
The key file is created with mode 0600; its directory is private. The application loads it during normal startup, so normal operation does not require an interactive password.
Existing ACME DNS credential files are migrated on startup for Cloudflare, OVH and RFC2136. After successful import, the legacy plaintext credential file is removed. Certbot-compatible credential files are recreated only as short-lived private files around the external operation and removed afterwards.
Do not copy only config.sqlite3 as a Secret Store backup: the local key material is also required. Use the encrypted full-backup command below.
Create a full backup
backup create may run while RustProxy is serving traffic. If the service is stopped, the CLI takes the data-directory lock; if the service is running, it creates a consistent SQLite snapshot and stages durable filesystem state without taking ownership of that lock. The output file must be outside the RustProxy data directory and must not already exist.
rust-proxy --data-dir /var/lib/rustproxy backup create \
--output /private/rustproxy-backup.rpb
When run from a TTY, RustProxy asks for the backup password without putting it in process arguments or shell history. Press Enter at the password prompt to generate a strong random password. A generated password is printed exactly once and is required for restore.
For non-interactive backup create, RustProxy generates the password automatically and prints it once to standard output. Protect that output as a secret.
The encrypted backup contains the durable application state needed for recovery, including:
- a consistent SQLite snapshot,
- configuration and Secret Store records,
- backup-wrapped Secret Store key material,
- certificates and private keys,
- ACME state and durable provider data,
- other durable RustProxy data accepted by the backup manifest,
- validated internal relative symlinks, including Certbot
live/links into the same profile'sarchive/tree.
It excludes rebuildable/runtime data such as cache, logs, temporary files, sockets, PID/lock files, SQLite WAL/SHM sidecars and the managed Certbot Python environment (acme-python; the acme_python spelling is excluded as well). Certificate/ACME durable state inside the RustProxy data directory remains included; the virtual environment is rebuilt when needed. Manual certificates configured with absolute external paths (for example /etc/letsencrypt/live/...) are intentionally not copied into the backup: only the configured path remains in SQLite, so the external files or mounts must be restored separately. Symlinks inside the backed-up RustProxy data tree are accepted only when their target is relative and resolves inside that staged tree; absolute, escaping or dangling links fail backup/restore. Restore recreates accepted in-tree links as links rather than dereferencing them.
The outer container derives a backup key with Argon2id and encrypts authenticated chunks with AES-256-GCM. The backup password is independent from the local Secret Store key.
Restore
Restore is CLI-only, requires RustProxy to be stopped, and requires an interactive TTY for the password:
rust-proxy --data-dir /var/lib/rustproxy backup restore \
/private/rustproxy-backup.rpb
Before replacing the destination, RustProxy verifies the encrypted container, password/authentication tags, manifest, checksums, backup format, RustProxy/schema compatibility, restored SQLite database and decryptability of all Secret Store records.
Files are first restored into a private staging directory. Only after validation succeeds is the staged data directory atomically activated; activation failure attempts to roll back to the previous directory. Sensitive restored files use restrictive permissions.
A lost backup password cannot be recovered by RustProxy.