59 lines
3.2 KiB
Markdown
59 lines
3.2 KiB
Markdown
# 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:
|
|
|
|
```text
|
|
<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
|
|
|
|
Stop RustProxy first so the data directory lock is available. The output file must be outside the RustProxy data directory and must not already exist.
|
|
|
|
```bash
|
|
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.
|
|
|
|
It excludes rebuildable/runtime data such as cache, logs, temporary files, sockets, PID/lock files and SQLite WAL/SHM sidecars.
|
|
|
|
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 and requires an interactive TTY for the password:
|
|
|
|
```bash
|
|
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.
|